Thread: Reaping zombies with sigaction()

  1. #1
    Registered User
    Join Date
    Mar 2008
    Posts
    44

    Reaping zombies with sigaction()

    Hi,
    In an example from Beej's guide to network programming there's the following piece of server code:
    Code:
    void sigchld_handler(int s)
    {
        while(waitpid(-1, NULL, WNOHANG) > 0);
    }
    
        ...
    
        sa.sa_handler = sigchld_handler; // reap all dead processes
        sigemptyset(&sa.sa_mask);
        sa.sa_flags = SA_RESTART;
        if (sigaction(SIGCHLD, &sa, NULL) == -1) {
            perror("sigaction");
            exit(1);
        }
    
        while(1) {  // main accept() loop
            sin_size = sizeof their_addr;
            if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, \
                    &sin_size)) == -1) {
                perror("accept");
                continue;
            }
            printf("server: got connection from %s\n", \
                inet_ntoa(their_addr.sin_addr));
            if (!fork()) { // this is the child process
                close(sockfd); // child doesn't need the listener
                if (send(new_fd, "Hello, world!\n", 14, 0) == -1)
                    perror("send");
                close(new_fd);
                exit(0);
            }
            close(new_fd);  // parent doesn't need this
        }
    I think I kind of understand how the //reap dead processes block itself works, but how is it ever triggered from within the while(1) loop where the works is being done? I can understand how any present zombie processes may get reaped prior to entering the while(1) loop but not after.

    Also if (sigaction(SIGCHLD, &sa, NULL) fails, tell us about it and exit the server all together. Isn't that a bit extreme or is such a thing only supposed to happen to mall-configured services?
    Thanks,
    heras

    edit: I think this may be linux specific so I put it here.
    Last edited by heras; 03-12-2008 at 06:48 AM.

  2. #2
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by heras View Post
    I think I kind of understand how the //reap dead processes block itself works, but how is it ever triggered from within the while(1) loop where the works is being done? I can understand how any present zombie processes may get reaped prior to entering the while(1) loop but not after.
    I'm not sure I entirely understand your question. When a child process dies, its parent receives a SIGCHLD signal, which invokes the signal handler asynchronously. Then it reaps as many processes as possible (probably only the single one that died, although more could die at the same instant, thus the loop). Then it returns to the main program. When another child dies, you get another SIGCHLD and it all happens again.

    Also if (sigaction(SIGCHLD, &sa, NULL) fails, tell us about it and exit the server all together. Isn't that a bit extreme or is such a thing only supposed to happen to mall-configured services?
    It is not extreme at all. What would be extreme would be continuing to run without the reaper handler, because the parent would slowly populate the system with zombie processes. Also, if a call to sigaction() fails, things are so seriously wrong that continuing would be pointless. sigaction() should not fail.

  3. #3
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by brewbuck View Post
    It is not extreme at all. What would be extreme would be continuing to run without the reaper handler, because the parent would slowly populate the system with zombie processes. Also, if a call to sigaction() fails, things are so seriously wrong that continuing would be pointless. sigaction() should not fail.
    sigaction should not fail under normal circumstances, but there is a chance that it does - otherwise it would not return an error code... It is always a good idea to check for error codes and do something "sensible" rather than just blindly hope that it worked. [This is called the "Ostrich method" for error detection, "Stick your head in the sand and hope the problem goes away".

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  4. #4
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by matsp View Post
    sigaction should not fail under normal circumstances, but there is a chance that it does - otherwise it would not return an error code... It is always a good idea to check for error codes and do something "sensible" rather than just blindly hope that it worked. [This is called the "Ostrich method" for error detection, "Stick your head in the sand and hope the problem goes away".
    I absolutely agree. What I was trying to say is that calling exit() after a failed sigaction() is the only sensible thing. sigaction() can theoretically fail, but it shouldn't. If it does, it is catastrophic and you should terminate.

    EDIT: I'm reading the man page for sigaction() and it says it can come back with EINTR. I would not have imagined that, but if true, the call to sigaction() should be wrapped in a loop to retry until it no longer gets EINTR. All system calls which return EINTR should be wrapped in such loops.

  5. #5
    Registered User
    Join Date
    Mar 2008
    Posts
    44
    Quote Originally Posted by brewbuck View Post
    When a child process dies, its parent receives a SIGCHLD signal, which invokes the signal handler asynchronously.
    Aha, I didn't realize this 'trigger' I was looking for is inherent to a dying child process and not explicitly in the code as such!

    It is not extreme at all. What would be extreme would be continuing to run without the reaper handler, because the parent would slowly populate the system with zombie processes. Also, if a call to sigaction() fails, things are so seriously wrong that continuing would be pointless. sigaction() should not fail.
    sigaction should not fail under normal circumstances, but there is a chance that it does - otherwise it would not return an error code... It is always a good idea to check for error codes and do something "sensible" rather than just blindly hope that it worked. [This is called the "Ostrich method" for error detection, "Stick your head in the sand and hope the problem goes away".
    Well, that actually makes a lot of sense. I guess what users might sometimes call a "crash" a programmer might call a feature

    Thank you both for your answers.

    Ps.: I will study the sigaction() and related man pages more closely over the next few days.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 3
    Last Post: 07-07-2009, 10:05 AM
  2. Wrapping sigaction() in loop until != EINTR;
    By heras in forum C Programming
    Replies: 5
    Last Post: 04-05-2008, 05:39 AM
  3. Zombies and Multiprocessor???
    By 3dkiwi in forum Linux Programming
    Replies: 5
    Last Post: 01-06-2007, 12:32 AM
  4. sigaction() and ANSI C
    By awoodland in forum Linux Programming
    Replies: 4
    Last Post: 04-25-2004, 01:48 AM