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

Hallo monks!
I have a client/server envirnment working with Perl 5.005_03 and RPC::PlClient/RPC::PlServer. The environment works on many different platforms, including Nokia IPSO (which is their own FreeBSD version).
Unfortunately, whenever a connection is closed, a new zombie process is created on the IPSO machine (the server side), until the proc table is full.
Looking into it I found the following line in Net::Daemon:
return 'IGNORE' if $^O eq 'linux'; # We get zombies on Linux other +wise
Reading further about this in perldoc I was glad and I just added "freebsd" to the regexp, but unfortunately nothing changed.
Since I don't really need the server to me able to listen to more then one connection at a time I moved to use 'single' mode instead of 'fork' mode, like I do on windows, but it is an ugly solution.

Any idea ?

The Perl -V data on the IPSO is:
Summary of my perl5 (5.0 patchlevel 5 subversion 3) configuration: Platform: osname=freebsd, osvers=2.2.8-release, archname=i386-freebsd uname='freebsd athens.checkpoint.com 2.2.8-release freebsd 2.2.8-r +elease #0: mon nov 30 06:34:08 gmt 1998 jkh@time.cdrom.com:usrsrcsysc +ompilegeneric i386 ' hint=recommended, useposix=true, d_sigaction=define usethreads=undef useperlio=undef d_sfio=undef Compiler: cc='gcc', optimize=' ', gccversion=2.8.1 cppflags='' ccflags ='' stdchar='char', d_stdstdio=undef, usevfork=false intsize=4, longsize=4, ptrsize=4, doublesize=8 d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=1 +2 alignbytes=4, usemymalloc=n, prototype=define Linker and Libraries: ld='ld', ldflags ='' libpth=/usr/lib libs=-lm -lc -lcrypt libc=, so=so, useshrplib=false, libperl=libperl.a Dynamic Linking: dlsrc=dl_none.xs, dlext=none, d_dlsymun=undef, ccdlflags='' cccdlflags='-DPIC -fpic', lddlflags='' Characteristics of this binary (from libperl): Built under freebsd Compiled at Jul 11 2001 20:45:05 @INC: /opt/perl5/lib/5.00503/i386-freebsd /opt/perl5/lib/5.00503 /opt/perl5/lib/site_perl/5.005/i386-freebsd /opt/perl5/lib/site_perl/5.005 .
TIA,
shushu

Replies are listed 'Best First'.
Re: Net::Daemon and zombies
by sgifford (Prior) on Sep 22, 2003 at 16:07 UTC

    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); }
      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
        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. }
        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.