在 child 收到 sigstop 后,wait() 不会 return

wait() does not return after child received sigstop

正如标题所说,一个进程 fork 等待它的 child 收到一个 SIGSTOP(child 自己发送的信号)但是它并没有醒来,就好像它没有收到任何 SIGCHLD(但它确实收到了,用 strace 测试)。

有人有什么想法吗?

int main() {
  if (fork()) {
    wait(NULL);
    write(1, "Bye\n", 4);
  } else {
    kill(getpid(), SIGSTOP);
    write(1, "Hello\n", 6);
  }
return 0;
}

它们都挂起,而只有 child 应该挂起。

哎呀,我会自己回答,我忘了添加 WUNTRACED 作为 wait() 选项。 正确的函数调用是 waitpid(-1, NULL, WUNTRACED);

The specification for wait 说它只报告 children 有 exited,而不是 children 有 stopped。你应该使用

waitpid(-1, 0, WUNTRACED);

相反。

标志名称 WUNTRACED 有点神秘 - 为什么不是 WSTOPPED?这是标准化 wait* API 与 not-standardized ptrace API 擦肩而过的一点。比较 POSIX 对 WUNTRACED 的定义…

WUNTRACED
The status of any child processes specified by pid that are stopped, and whose status has not yet been reported since they stopped, shall also be reported to the requesting process.

… 及其文档在 Linux manpage

WUNTRACED
also return if a child has stopped (but not traced via ptrace(2)). Status for traced children which have stopped is provided even if this option is not specified.

所以基本上 wait* 的默认行为有一个特殊情况嵌入其中,以方便编写调试器的人(编写调试器的人会利用他们可以获得的一切便利)并且这种特殊情况已经存在了如此之久,以至于它影响了为 waitpid 的旗帜选择的名称。 (我不知道是哪一种方式,但如果得知 ptrace 停止比作业控制停止 更早 ,我不会感到惊讶。)