为什么 POSIX 要求 system(3) 忽略 SIGINT 和 SIGQUIT?

Why does POSIX demand that system(3) ignores SIGINT and SIGQUIT?

POSIX spec says

The system() function shall ignore the SIGINT and SIGQUIT signals, and shall block the SIGCHLD signal, while waiting for the command to terminate. If this might cause the application to miss a signal that would have killed it, then the application should examine the return value from system() and take whatever action is appropriate to the application if the command terminated due to receipt of a signal.

这意味着启动long-running sub-process 的程序将长时间阻塞SIGINTSIGQUIT。这是在我的 Ubuntu 18.10 笔记本电脑上编译的测试程序:

$ cat > test_system.c <<< EOF
#include <stdlib.h>

int main() {
    system("sleep 86400");  // Sleep for 24 hours
}
EOF
$ gcc test_system.c -o test_system

如果我在后台启动这个测试程序运行...

$ ./test_system &
[1] 7489

..然后我可以看到 SIGINT(2) 和 SIGQUIT(3) 在位掩码中被标记为忽​​略。

$ ps -H -o pid,pgrp,cmd,ignored
  PID  PGRP CMD                                  IGNORED
 6956  6956 -bash                       0000000000380004
 7489  7489   ./test_system             0000000000000006
 7491  7489     sh -c sleep 86400       0000000000000000
 7492  7489       sleep 86400           0000000000000000

试图用 SIGINT 杀死 test_system 无效..

$ kill -SIGINT 7489

.. 但是向进程组发送 SIGINT 确实会杀死它(这是预期的,这意味着进程组中的每个进程都收到信号 - 睡眠将退出并且系统将 return ).

   $ kill -SIGINT -7489
   [1]+  Done                    ./test_system

问题

  1. 忽略 SIGINTSIGQUIT 的目的是什么,因为进程仍然可以通过进程组终止(这就是当您在终端中执行 ^C 时发生的情况).
  2. 额外问题:为什么 POSIX 要求 SIGCHLD 应该被阻止?
  3. Update 如果 SIGINTSIGQUIT 被忽略以确保我们不会留下 children,那么为什么没有处理对于 SIGTERM - 这是 kill!
  4. 发送的默认信号

SIGINTSIGQUIT 是终端生成的信号。默认情况下,当您分别按 Ctrl+CCtrl+\ 时,它们会被发送到前台进程组。

我认为在通过 system 运行 a child 时忽略它们的想法是,终端应该就好像它暂时由 child 拥有并且Ctrl+CCtrl+\ 应该暂时只影响 child 及其后代,而不影响 parent。

SIGCHLD 被阻止,因此 system 由 child 终止引起的 SIGCHLD 不会触发 SIGCHLD 处理程序,如果你有一,因为这样的 SIGCHLD 处理程序可能会在 system 收获它之前收获由 system 启动的 child。