问题
The 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.
This means that a program that starts a long-running sub-process will have SIGINT
and SIGQUIT
blocked for a long time. Here is a test program compiled on my Ubuntu 18.10 laptop:
$ 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
If I start this test program running in the background...
$ ./test_system &
[1] 7489
..Then I can see that SIGINT
(2) and SIGQUIT
(3) are marked as ignored in the bitmask.
$ 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
Trying to kill test_system with SIGINT
has no effect..
$ kill -SIGINT 7489
.. But sending SIGINT
to the process group does kill it (this is expected, it means that every process in the process group receives the signal - sleep will exit and system will return).
$ kill -SIGINT -7489
[1]+ Done ./test_system
Questions
- What is the purpose of having
SIGINT
andSIGQUIT
ignored since the process can still be killed via the process group (that's what happens when you do a^C
in the terminal). - Bonus question: Why does POSIX demand that
SIGCHLD
should be blocked? - Update If
SIGINT
andSIGQUIT
are ignored to ensure we don't leave children behind, then why is there no handling forSIGTERM
- it's the default signal sent by kill!
回答1:
SIGINT
and SIGQUIT
are terminal generated signals. By default, they're sent to the foreground process group when you press Ctrl+C
or Ctrl+\
respectively.
I believe the idea for ignoring them while running a child via system
is that the terminal should be as if it was temporarily owned by the child and Ctrl+C
or Ctrl+\
should temporarily only affect the child and its descendants, not the parent.
SIGCHLD
is blocked so that system
's the SIGCHLD
caused by the child terminating won't trigger a SIGCHLD
handler if you have one, because such a SIGCHLD
handler might reap the child started by system
before system
reaps it.
来源:https://stackoverflow.com/questions/56053355/why-does-posix-demand-that-system3-ignores-sigint-and-sigquit