Search code examples
clinuxforksignalssignal-handling

calling signal after fork


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?


Solution

  • 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.