为什么 POSIX 要求 system(3) 忽略 SIGINT 和 SIGQUIT?
Why does POSIX demand that system(3) ignores SIGINT and SIGQUIT?
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 的程序将长时间阻塞SIGINT
和SIGQUIT
。这是在我的 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
问题
- 忽略
SIGINT
和 SIGQUIT
的目的是什么,因为进程仍然可以通过进程组终止(这就是当您在终端中执行 ^C
时发生的情况).
- 额外问题:为什么 POSIX 要求
SIGCHLD
应该被阻止?
- Update 如果
SIGINT
和 SIGQUIT
被忽略以确保我们不会留下 children,那么为什么没有处理对于 SIGTERM
- 这是 kill! 发送的默认信号
SIGINT
和 SIGQUIT
是终端生成的信号。默认情况下,当您分别按 Ctrl+C
或 Ctrl+\
时,它们会被发送到前台进程组。
我认为在通过 system
运行 a child 时忽略它们的想法是,终端应该就好像它暂时由 child 拥有并且Ctrl+C
或 Ctrl+\
应该暂时只影响 child 及其后代,而不影响 parent。
SIGCHLD
被阻止,因此 system
由 child 终止引起的 SIGCHLD
不会触发 SIGCHLD
处理程序,如果你有一,因为这样的 SIGCHLD
处理程序可能会在 system
收获它之前收获由 system
启动的 child。
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 的程序将长时间阻塞SIGINT
和SIGQUIT
。这是在我的 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
问题
- 忽略
SIGINT
和SIGQUIT
的目的是什么,因为进程仍然可以通过进程组终止(这就是当您在终端中执行^C
时发生的情况). - 额外问题:为什么 POSIX 要求
SIGCHLD
应该被阻止? - Update 如果
SIGINT
和SIGQUIT
被忽略以确保我们不会留下 children,那么为什么没有处理对于SIGTERM
- 这是 kill! 发送的默认信号
SIGINT
和 SIGQUIT
是终端生成的信号。默认情况下,当您分别按 Ctrl+C
或 Ctrl+\
时,它们会被发送到前台进程组。
我认为在通过 system
运行 a child 时忽略它们的想法是,终端应该就好像它暂时由 child 拥有并且Ctrl+C
或 Ctrl+\
应该暂时只影响 child 及其后代,而不影响 parent。
SIGCHLD
被阻止,因此 system
由 child 终止引起的 SIGCHLD
不会触发 SIGCHLD
处理程序,如果你有一,因为这样的 SIGCHLD
处理程序可能会在 system
收获它之前收获由 system
启动的 child。