in reply to Net::Daemon and zombies

It looks like the code is setting the $SIG{CHLD} handler to IGNORE, which works on some OS's (traditionally System V ones) but not on others (traditionally BSD ones). What that means is that you have to reap the child yourself. That's not as hard (or as disturbing) as it sounds.

Basicaly, a zombie process is a process that has finished running, but its parent hasn't inquired about its exit status yet. The UNIX interface guarantees that a parent can get this information, so the kernel has to keep the process around in case the parent later asks for it. You can reap the zombie processes by simply asking for the exit status when the child exits, using wait, which just means creating a $SIG{CHLD} handler that calls wait.

For example:

#!/usr/bin/perl $SIG{CHLD} = sub { my $pid = wait; print "Child $pid exited with status $?\n"; }; foreach my $i (1..10) { if (!fork()) { # Child sleep(1); exit($i); } sleep(2); }

Replies are listed 'Best First'.
Re: Re: Net::Daemon and zombies
by shushu (Scribe) on Sep 23, 2003 at 07:00 UTC
    Hi,
    The code from Net::Daemon is:
    sub SigChildHandler { my $self = shift; my $ref = shift; return undef if $self->{'mode'} ne 'fork'; # Don't care for childs +. return 'IGNORE' if $^O eq 'linux'; # We get zombies on Linux other +wise my $reaper; sub { $$ref = wait; $SIG{'CHLD'} = $reaper; }; } sub Bind ($) { my $self = shift; my $fh; my $child_pid; my $reaper = $self->SigChildHandler(\$child_pid); $SIG{'CHLD'} = $reaper if $reaper; ...

    As far as I understand the solution you suggested it actually the one used, but still - it does not work.

    Any ideas? maybe there is a problem in the code I can't find?
    TIA, shushu
      That code is buggy. Here it is in a package with a dummy new function, a warn statement to tell us when the reaper is running, and the line that checks if we're running under Linux commented out (since I'm testing it on Linux): That creates 10 children fairly slowly. Let's see how many are reaped:
      [sgifford@sghome pa1]$ perl /tmp/t107 My PID is 18286 Running reaper. Use of uninitialized value in scalar assignment at /tmp/t107 line 37.
      That doesn't look promising. So what happened to the other 9 processes?
      $ ps -ef |grep 18286 sgifford 18286 16547 0 14:02 pts/0 00:00:00 perl /tmp/t107 sgifford 18288 18286 0 14:02 pts/0 00:00:00 [perl <defunct>] sgifford 18289 18286 0 14:02 pts/0 00:00:00 [perl <defunct>] sgifford 18292 18286 0 14:02 pts/0 00:00:00 [perl <defunct>] sgifford 18295 18286 0 14:02 pts/0 00:00:00 [perl <defunct>] sgifford 18298 18286 0 14:02 pts/0 00:00:00 [perl <defunct>] sgifford 18301 18286 0 14:02 pts/0 00:00:00 [perl <defunct>] sgifford 18303 18212 0 14:03 pts/20 00:00:00 grep 18286
      Yup. Zombies. Just like you're seeing.

      I think that the only problem with this code is a typo. If we add a line below my $reaper;, saying $reaper =, assigning the sub ref to $reaper (which is what I believe the author intended) the problem goes away.

      $ perl /tmp/t107 My PID is 18322 Running reaper. Running reaper. Running reaper. Running reaper. Running reaper. Running reaper. Running reaper. Running reaper. Running reaper. Running reaper.
      What version of Net::Daemon is that? On 0.37, the version on CPAN, SigChildHandler is just
      sub SigChildHandler { my $self = shift; my $ref = shift; return 'IGNORE' if $self->{'mode'} eq 'fork' || $self->{'childs'}; return undef; # Don't care for childs. }