Professional Web Applications Themes

SIGINT, SIGCHLD, and free() - UNIX Programming

I am writing a http server, which upon starting preforks a certain number of child processes (each calling accept()). I wanted to make sure that everything gets cleaned up properly if the parent process recieves the SIGINT or SIGTERM signal. As of now I have the following: /* for SIGCHLD */ static void cleanup_children(int sig) { int s; pid_t p; while((p = waitpid(-1, &s, WNOHANG)) > 0) { if(verbose) printf("child %d terminated with an exit status of (%d)\n", p, s); } return; } /* for SIGINT */ static void sigint_handler(int sig) { int i; for(i = 0; i < nchildren; ...

  1. #1

    Default SIGINT, SIGCHLD, and free()

    I am writing a http server, which upon starting preforks a certain
    number of child processes (each calling accept()). I wanted to make
    sure that everything gets cleaned up properly if the parent process
    recieves the SIGINT or SIGTERM signal.

    As of now I have the following:

    /* for SIGCHLD */
    static void cleanup_children(int sig)
    {
    int s;
    pid_t p;

    while((p = waitpid(-1, &s, WNOHANG)) > 0) {
    if(verbose)
    printf("child %d terminated with an exit status of (%d)\n", p, s);
    }

    return;
    }

    /* for SIGINT */
    static void sigint_handler(int sig)
    {
    int i;
    for(i = 0; i < nchildren; i++) {
    printf("Sending child %d [%ld] the SIGTERM signal\n", i+1, child_pids[i]);
    kill(child_pids[i], SIGTERM);
    }
    free(child_pids); /* previously calloc()'d array of pid_t's */
    exit(0);
    }

    Did I go about doing this right? I would like to have a handler for
    SIGTERM that did the same thing as the one for SIGINT, but I don't think
    that will work with that exact code.

    Any ideas?

    Thanks,
    Aaron

    Aaron Guest

  2. #2

    Default Re: SIGINT, SIGCHLD, and free()

    Hello Aaron,

    Having 3 weeks break, I'm a bit rusty right now... But, here a few
    thoughts:
     

    Looks good.
     

    Ok.
     

    First comment: printf() is not async-signal-safe. In a signal handler,
    you are only allowed to call async-signal-safe functions, that is,
    functions that are safe to use in signal handler (Ok, that's
    technically not 100% correct, but using only async-singal-safe
    functions put you on the "safe side").

    Using printf() might work on for your particular program / OS. But it
    is not portable and risky: you might generate a SIGSEGV or your
    program might deadlock... Of course, usually this unfortunate behavior
    happens when the program is shipped to the customer :o)

     

    Like printf(), free() is not async-signal-safe! So, do not use this
    function in signal handler!
     

    Ok. First you must answer the following question: what does happen if
    SIGINT (or SIGTERM) is sent to one of the child? Should the whole
    program terminate, or is it OK to terminate children separately? Or
    should the whole program terminate only if the "init" parent receive
    SIGINT/SIGTERM?

    Assuming the later, the way I used to solve such problem is similar to
    this pseudo code:

    // main process (fork all children)
    //
    int shutdown = FALSE;

    // called upon SIGINT / SIGTERM
    void
    terminate_handler(int sig)
    {
    // send the signal sig to my children
    // ...

    shutdown = TRUE;
    }

    main()
    {
    // install signal handler
    // ...

    // initialization: fork children
    // ...

    while (!shutdown) {
    //
    // ... do whatever relevant here...
    //
    }

    // clean-up: close all fds, free allocated arrays etc.
    //
    }

    In the child, you might install a similar handler that just set the
    shutdown flag to TRUE. Usually, you take advantage of the fact that
    blocking functions, like accept(), return -1 with errno=EINTR when
    interrupted by a signal to properly terminate the process.


    Just my 2 Cents!

    Cheers,
    Loic.
    Loic Guest

  3. #3

    Default Re: SIGINT, SIGCHLD, and free()

    On Sat, 22 Nov 2003 21:55:46 GMT, Aaron Walker
    <rr.com> wrote:
     

    Take a look at:

    http://www.opengroup.org/onlinepubs/007904975/functions/xsh_chap02_04.html#tag_02_04

    Calling printf() and free() from signal handlers can cause problems
    because these functions are not reeentran nor async-signal safe. (Nor
    in fact is exit(), though _exit() is okay.)

    Taking the example of free(), the essential problem is that malloc()
    and free() update a global linked list of free blocks on the heap. If
    your signal handler interrupts a call to malloc() and then calls
    free(), chaos can result. For simialr reasons, printf() is unsafe.

    To avoid these sorts of problems, a typical approach is to just set a
    flag in the handler, and then have the main program do the work of
    calling such functions after it sees that flag is set.

    On your specific example above. It isn't really necessary to call
    free() when the process terminates anyway. When a process terminates
    all of it's memory is freed automatically. So if you removed the
    printf() calls, and replaced exit() with _exit(), things would be
    safe. (But note that calling _exit() means that anything that was
    sitting in stdio buffers WON'T be flushed on process termination.)

    Cheers,

    Michael
    Michael Guest

  4. #4

    Default Re: SIGINT, SIGCHLD, and free()

    net wrote :
     

    And why not going further and just set the shutdown flag in
    the signal handler and do all the things in main(), so that we do the
    minimal things in the signal handler (with is a very special context) ?

    int shutdown = FALSE;

    void terminate_handler()
    {
    shutdown = TRUE;
    }

    int main(void)
    {
    /* install the handler */

    while (!shutdown) {
    /* do your things */
    }

    /* send signals to the childs */

    /* clean up */
    }

    --
    DINH V. Hoa,

    etPan! - newsreader, mail user agent -- http://libetpan.sf.net/etpan

    DINH Guest

  5. #5

    Default Re: SIGINT, SIGCHLD, and free()

    On Mon, 24 Nov 2003 11:46:35 +0100, DINH Viet Hoa wrote:
     

    Make that

    sig_atomic_t shutdown = FALSE;

    --
    mail1dotstofanetdotdk

    Bjorn Guest

  6. #6

    Default Re: SIGINT, SIGCHLD, and free()

    DINH Viet Hoa wrote: 
    >
    >
    > And why not going further and just set the shutdown flag in
    > the signal handler and do all the things in main(), so that we do the
    > minimal things in the signal handler (with is a very special context) ?
    >
    > int shutdown = FALSE;
    >
    > void terminate_handler()
    > {
    > shutdown = TRUE;
    > }
    >
    > int main(void)
    > {
    > /* install the handler */
    >
    > while (!shutdown) {
    > /* do your things */
    > }
    >
    > /* send signals to the childs */
    >
    > /* clean up */
    > }
    >[/ref]

    Ok, in my case, I have main() which only handles command-line args and
    then calls server_init(), which sets up all the socket stuff, then calls
    children_init() which preforks all the children, each of which run
    child_main(). Do I need to use the while(!shutdown) loop in all of
    those, or will it suffice just doing:

    while (!shutdown) {
    server_init(...);
    }

    in main()?

    Thanks again for all the help and suggestions,
    Aaron

    Aaron Guest

Similar Threads

  1. Pthreads and SIGCHLD
    By Chris in forum UNIX Programming
    Replies: 5
    Last Post: September 11th, 08:57 PM

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139