测试进程是否留下任何孤儿进程

测试进程是否留下任何孤儿进程

我不需要等待他们,我只需要一个是或否。

我正在执行一个我知道会分叉的程序(孩子们也可能会分叉)。如果运行正确,它应该照顾所有的子级,并在完成时退出它们。我需要编写一个测试来检查这是否属实。孤立进程被分配给 init 进程,因此我无法再在 pstree 中看到它们。

如果我可以获得他们的 PID 列表,这样我就可以向他们发送 SIGKILL,那就加分了。理想情况下,如果它是 POSIX-y 的东西,那么它可以在 *BSD 上工作。

答案1

找到这些的一种方法是使用ps -ef,查找parent-id 为“1”的行,例如,

#!/bin/sh
orphans="$(ps -ef | awk '$3 == 1{ print $2; }')"
echo "Processes which might be orphans: $orphans"

然而,许多进程以“1”作为其父进程。确定您感兴趣的最好方法是记住您的程序创建的子进程。

如果你碰巧知道登录名(和/或用户身份)在创建这些进程的情况下,您可以消除一些可能性。第一列ps可以显示(取决于系统类型)登录名或相应的用户身份POSIX此处提供了一些帮助,但很容易找到不同的系统 - 并且文档反映了这一点:

  • 例如,FreeBSD 10 不显示登录名-f选项。使用 just ps -ef,它会在第一列中显示进程 ID,而不显示父进程的进程 ID。它需要-l选项来显示(而不是)用户身份
  • OSX 在任一情况下都会给出用户 ID(ps -efps -efl)。
  • 如果有该-l选项,Solaris 10 将在第一列和第二列中显示进程标志。 POSIX 中提到了这一点,尽管内容标志的数量是未指定的(因为内容不同Unix平台)。
  • Linux 按照 POSIX 提供登录名和进程标志。

正如您所看到的,对于可用系统的某些子集,ps -efl前三列将给出“相同”的结果。对于更一般的内容,您必须查看标题(第一行)并确定哪一列包含与流程所有者相对应的信息(登录名或者用户身份) 和进程 ID 和它是父进程的进程 ID。

对于给定的系统(知道 的可用选项ps,并知道是否匹配登录名或者用户身份),你可以用来awk匹配字段也是如此,例如

#!/bin/sh
orphans="$(ps -ef | awk -v user=$LOGNAME '($1 == user && $3 == 1){ print $2; }')"
echo "Processes which might be orphans: $orphans"

这里我使用$LOGNAME, 来解释 POSIX 对这个术语的使用登录名,这可能会产生误导(因为原则上流程可以通过sudo,而 POSIX 使用该术语意味着它们是通过“登录”来的)。

进一步阅读:

答案2

当进程终止时,其子进程的 PPID 被设置为 1(由 init 采用),但 PGID(进程组标识符)和 SID(会话标识符)不会更改。

该进程的子进程可能不会更改其进程组,除非它们打算成为守护进程。假设没有,则在其自己的进程组中启动要测试的进程。在分叉之后和调用执行正在测试的程序setpgid(getpid(), getpid())之前,从测试框架调用。execve调用kill(-test_program_pid, 0)kill使用负参数pid和信号值 0)来测试是否有具有 PGID 的正在运行的进程test_program_pid。作为信号参数传递SIGKILL来杀死它们。

test_program_pid = fork();
if (test_program_pid) {
    waitpid(test_program_pid, &status, 0);
    if (kill(-test_program_pid, 0)) {
        record_failue("some child processes were not terminated properly");
    }
    kill(-test_program_pid, SIGKILL);
} else {
    setpgid(getpid(), getpid());
    execve("/program/to/test", …);
}

另一种方法是创建一个临时文件并在您正在测试的程序中打开它,而不是在其他地方打开它。如果程序调用execve,请确保打开的文件描述符没有标志O_CLOEXEC(或调用fcntl(fd, FD_CLOEXEC, 0))。此方法假设程序不会关闭未显式使用的文件描述符。然后,您可以运行fuser /temp/file以列出打开该文件的进程,并fuser -k /temp/file杀死它们。这种方法的一个变体甚至可以用于关闭不使用的文件描述符的程序,但假设程序不更改其当前目录,即创建一个临时目录并更改为该目录来运行程序。

相关内容