Is there any difference between "code listing 1" and "code listing 2"? Because in Code Listing 1, the child process is able to catch the SIGTERM signal and exit nicely. But code listng 2 is terminating abruptly on SIGTERM signal.
I am using Linux and C.
Code Listing 1
if (signal(SIGTERM, stopChild) == SIG_ERR) {
printf("Could not attach signal handler\n");
return EXIT_FAILURE;
}
pid = fork();
Code Listing 2
pid = fork();
if (signal(SIGTERM, stopChild) == SIG_ERR) {
printf("Could not attach signal handler\n");
return EXIT_FAILURE;
}
The strange part is that in Code Listing 2, both child and parent process sets the signal handler for SIGTERM. So, this is supposed to work. Isn't it?
POSIX specifies that fork can be called safely from signal handlers; it is required to be an async-signal-safe function.
When a child process stops or terminates, SIGCHLD is sent to the parent process. The default response to the signal is to ignore it. The signal can be caught and the exit status from the child process can be obtained by immediately calling wait(2) and wait3(3C).
If you are sending the SIGTERM from the parent, the end result depends on the order on which processes get scheduled.
If the child gets scheduled first, everything works:
+---------------+
| pid = fork(); |
+-------+-------+
parent | child
+-----------------------------+-----------------------------+
| |
| +-------------------------+--------------------------+
| | if (signal(SIGTERM, stopChild) == SIG_ERR) { |
| | printf("Could not attach signal handler\n"); |
| | return EXIT_FAILURE; |
| | } |
| +-------------------------+--------------------------+
| |
. .
. .
. .
| |
+-------------------------+--------------------------+ |
| if (signal(SIGTERM, stopChild) == SIG_ERR) { | |
| printf("Could not attach signal handler\n"); | |
| return EXIT_FAILURE; | |
| } | |
+-------------------------+--------------------------+ |
| |
| |
| |
+-------------+-------------+ |
| if (pid > 0) { | |
| kill(pid, SIGTERM); | |
| } | |
+-------------+-------------+ |
| |
| |
| |
But if the paren gets scheduled first, the child may have not had time to setup the signal handler:
+---------------+
| pid = fork(); |
+-------+-------+
parent | child
+-----------------------------+-----------------------------+
| |
+-------------------------+--------------------------+ |
| if (signal(SIGTERM, stopChild) == SIG_ERR) { | |
| printf("Could not attach signal handler\n"); | |
| return EXIT_FAILURE; | |
| } | |
+-------------------------+--------------------------+ |
| |
| |
| |
+-------------+-------------+ |
| if (pid > 0) { | |
| kill(pid, SIGTERM); | |
| } | |
+-------------+-------------+ |
| |
. .
. .
. .
| |
| +-------------------------+--------------------------+
| | if (signal(SIGTERM, stopChild) == SIG_ERR) { |
| | printf("Could not attach signal handler\n"); |
| | return EXIT_FAILURE; |
| | } |
| +-------------------------+--------------------------+
| |
| |
| |
This is called a race condition, because the end result depends on who gets to run first.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With