【问题标题】:How to test if calling process is a fork如何测试调用进程是否是分叉
【发布时间】:2017-06-29 20:00:19
【问题描述】:

Linux/POSIX 中是否有方法或 C api 来确定当前进程是否为 fork? IE。如果它是通过调用fork() 而没有随后调用execve() 系列创建的?

我不控制导致这一点的代码(它在高级语言绑定中运行)。我只需要知道当前进程是在运行顶级程序还是在其分支中。

我想出的最好的方法是测试进程是否具有与其父进程相同的 gid:

int is_fork = getpgid(0) == getpgid(getppid());

但是,这仅在父级调用 setpgid() 时才有效,而 execve() 默认情况下显然不会这样做。所以这会导致很多误报。

【问题讨论】:

  • 你控制程序吗?如果是的话,我能想到的找出类似情况的唯一方法是在fork() 之后的分叉子进程中设置一个状态变量。
  • 你的措辞有点奇怪。 每个进程(除了init)都是由fork()创建的所以你的问题应该是:我的进程是进程组长吗?
  • @wildplasser 我确实不熟悉术语。但是我认为进程组组长是调用setpgid()的祖先proc,而不是调用exec()的那个?
  • exec() 在这里不相关。该过程被不同的图像替换,但基本保持不变。只有几件事发生了变化(主要是内存映射和信号设置)
  • 顺便说一句:你的 `int is_fork = getpgid(0) == getpgid(getppid())` 中缺少分号...

标签: c linux fork exec posix


【解决方案1】:

在 Linux 上,一项不太精确的检查是查看进程的可执行文件 (/proc/$pid/exe) 是否与其父进程的可执行文件相同。但是,如果进程 execs 拥有自己的可执行文件,这将不起作用,这在某些环境(例如 shell)中可能很常见。

【讨论】:

  • 对不起,我没有看到你的答案!我删除了我的。请原谅我。
  • @jean-baptiste:不用担心。没什么大不了的。
【解决方案2】:

如果您可以控制顶级可执行文件的环境,您可以使用LD_PRELOAD 预加载一个共享库,该共享库安装一个pthread_atfork 处理程序,该处理程序通过设置全局可见变量将子项标记为分叉。然后,您的测试代码可以检查变量的值,以确定进程是否已在没有干预 exec 的情况下分叉。

【讨论】:

    【解决方案3】:

    也许您可以使用tms_utimetms_stimetms_cutimetms_cstime(请参阅http://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html)。这些变量在子进程中设置为0

    未经测试

    【讨论】:

    • 它们在 fork 时设置为 0,但在进程继续运行时它们不会保持为零。此外,这不区分fork()fork() 后跟exec()
    【解决方案4】:
    /* ppid.c
    cc -Wall ppid.c -o ppid
     */
    
    #include <stdio.h>
    #include <unistd.h>
    
    int main(int argc, char **argv)
    {
    int pid, ppid, pgid;
    
    pid = getpid();
    ppid = getppid();
    pgid = getpgid(0);
    
    printf("[%s] Pid=%d Ppid=%d Pgid=%d\n"
            , argv[0], pid, ppid, pgid);
    
    return 0;
    }
    

    /* testppid.c
    cc -Wall testppid.c -c testppid
    */
    
    #include <stdio.h>
    #include <unistd.h>
    
    int main(void)
    {
    int pid, pid2; 
    
    pid = fork();
    if (pid == -1) return 1;
    
    if (pid) { /* parent */
            char *args[] = { "Parent", NULL};
            sleep(3);
            execve("./ppid", args, NULL);
    } else { /* child */
    
            pid = getpid();
            setpgid(pid,pid);
            pid2 = fork();
            if (pid2 == -1) return 1;
    
            if (pid2) { /* child1 */
                    char *args[] = { "Child1", NULL};
                    sleep(2);
                    execve("./ppid", args, NULL);
    
            } else { /* grandchild */
                    char *args[] = { "Child2", NULL};
                    sleep(1);
                    execve("./ppid", args, NULL);
                    }
            }
    
    return 0;
    }
    

    输出:


    $ ./testppid
    [Child2] Pid=6220 Ppid=6219 Pgid=6219
    [Child1] Pid=6219 Ppid=6218 Pgid=6219
    [Parent] Pid=6218 Ppid=27410 Pgid=6218
    $
    

    这表明 shell (pid=27410) 在调用 Child2 之前对父进程的作用与 Child1 基本相同:{fork,setpgid,exec}。 Child1 是它自己和 Child2(孙子)的进程组组长

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-26
      • 2014-03-10
      • 2021-07-28
      • 2023-04-05
      • 2021-08-03
      • 1970-01-01
      • 2012-03-06
      相关资源
      最近更新 更多