Linux、waitpid、WNOHANG、子进程、僵尸

Cub*_*ube 5 linux kill process zombie-process waitpid

我作为守护进程运行我的程序。

父进程只等待子进程,当子进程意外死亡时,再次fork并等待。

for (; 1;) {
  if (fork() == 0) break;
  int sig = 0;
  for (; 1; usleep(10000)) {
    pid_t wpid = waitpid(g->pid[1], &sig, WNOHANG);
    if (wpid > 0) break;
    if (wpid < 0) print("wait error: %s\n", strerror(errno));
  }
}
Run Code Online (Sandbox Code Playgroud)

但是当子进程被-9信号杀死时,子进程就会进入僵尸进程。

waitpid应该立即返回子进程的pid!
waitpid大约90秒后得到了pid号,

cube     28139  0.0  0.0  70576   900 ?        Ss   04:24   0:07 ./daemon -d
cube     28140  9.3  0.0      0     0 ?        Zl   04:24 106:19 [daemon] <defunct>
Run Code Online (Sandbox Code Playgroud)

这是父亲的踪迹

父亲没有被卡住,wait4 总是被调用。

strace -p 28139
Process 28139 attached - interrupt to quit
restart_syscall(<... resuming interrupted call ...>) = 0
wait4(28140, 0x7fff08a2681c, WNOHANG, NULL) = 0
nanosleep({0, 10000000}, NULL)          = 0
wait4(28140, 0x7fff08a2681c, WNOHANG, NULL) = 0
Run Code Online (Sandbox Code Playgroud)

大约 90 秒后,父亲收到了 SIGCHILD,并且 wait4 返回了死亡孩子的 pid。

--- SIGCHLD (Child exited) @ 0 (0) ---
restart_syscall(<... resuming interrupted call ...>) = 0
wait4(28140, [{WIFSIGNALED(s) && WTERMSIG(s) == SIGKILL}], WNOHANG, NULL) = 28140
Run Code Online (Sandbox Code Playgroud)

为什么子进程不立即退出?相反,它却意外地变成了僵尸。

Cub*_*ube 3

我终于发现 lsof 深度跟踪期间存在一些 fd 泄漏。

修复 fd 泄漏后,问题就消失了。