http://qs1969.pair.com?node_id=530459

dsb has asked for the wisdom of the Perl Monks concerning the following question:

Hey all, I'm writing a script that needs to fork() and i want to be sure that I'm cleaning up all my zombies.

Between perlipc and Programming Perl, I've gotten a bit of zombie reaping code that I mostly understand, but need some clarification on.

The code I'm using is:

our $zombies = 0; $SIG{CHLD} = sub { $zombies++ }; sub reaper { my $zombie; our %Kid_Status; # store each exit status $zombies = 0; while (($zombie = waitpid(-1, WNOHANG)) != -1) { $Kid_Status{$zombie} = $?; } } while (1) { reaper() if $zombies; ... }
Because I'm not all that familiar with waitpid() - or wait(), for that matter - I'm not clear on whether or not this code has the parent process hanging around until child processes are reaped. Also, I'm not sure if this is preventing the script from fork()'ing another process before previous children are reaped.

Finally, would I be better off just running the reaper() function w/o checking for zombies first, so that the script constantly is checking on child procs. The docs for waitpid() said that it could return 0 if child procs are still running, which seems like it might be helpful insofar as making sure child processes are reaped before the parent exits. This seems like it would account for any scenarios where the parent process finished it's logic and exits before receiving a CHLD signal.

UPDATE: The cookbook has a pretty good bit on reaping zombies. Three things cleared up in recipe 16.19 of The Cookbook First Edition.


dsb
This @ISA my( $cool ) %SIG

Replies are listed 'Best First'.
Re: Reaping Zombies
by jeffa (Bishop) on Feb 15, 2006 at 18:40 UTC

    It has been several years since i looked at this stuff. First, i recommend you have a look at Advanced Programming in the Unix Environment. It's in C, but the concepts apply to Perl as well. Having said that, back in 2002 i had to write a forking server. This is the reaper code that i came up with:

    use POSIX qw(WNOHANG); our (%PID); sub reaper { while ((my $kid = waitpid(-1,WNOHANG)) > 0 ) { warn "Reaped child with PID $kid"; my $status = $? >> 8; $PID{$kid} = $status; } }
    Very simple, simply keep reaping children and store their status in a hash so that the server which did the forking can return the status to the client.

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
      The reaper code I'm using is identical to what I posted...It seems to be expensive it terms of CPU usage. Did you have a similar issue?


      dsb
      This @ISA my( $cool ) %SIG
        It seems to be expensive it terms of CPU usage

        What do you mean exactly? have you found the waitpid system call to be expensive, or are you talking about the full process?

        What else are you doing inside the while loop besides calling the reaper? You should be calling sleep or select or any other thing that causes your program to do nothing for a while!

Re: Reaping Zombies
by HuckinFappy (Pilgrim) on Feb 15, 2006 at 22:34 UTC
    I've dealt a lot with forking processes, and got tired of dealing with all this. I have a bad memory apparently, and I could never do it without re-reading the man pages for wait() and waitpid() to understad the difference.

    IAC, I just now default to using Parallel::ForkManager. It lets me write much easier to underastand forking code, and I've had no issues with it so far.

    YMMV, and I can appreciate trying to understand this stuff in detail so you know what's going on under the hood, but these days I opt for keeping the hood shut.

    ~Jeff

Re: Reaping Zombies
by zentara (Archbishop) on Feb 16, 2006 at 12:12 UTC