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

OH gurus of perl, I seek thy wisdom........

I have a script that I am working with that starts a few child processes and keeps track of them for reaping. Most of the code for this was taken from the perl cookbook, and then I tweaked it a bit. So this is what I have:

Main program:
:::::::::::::: mxMSsmtp ::::::::::::::
#!/usr/bin/perl use mxMSsmtp::Config; use mxMSsmtp::Run; use Getopt::Std; use strict; my %opts; my $cfg = undef; my $pid; getopts('c:D', \%opts); $cfg = $opts{c} if $opts{c}; my $vars = mxMSsmtp::Config::get($cfg) or die "Problem getting config +file\n"; if ($opts{D}) { run mxMSsmtp::Run($vars) unless $pid = fork; } else { run mxMSsmtp::Run($vars); } exit;
and the processing mod:
:::::::::::::: Run.pm ::::::::::::::
package mxMSsmtp::Run; use Symbol; use POSIX; use strict; my %children = (); my $children = 0; sub _REAPER { $SIG{CHLD} = \&_REAPER; my $pid = wait; $children--; delete $children{$pid}; } sub _KILLER { local($SIG{CHLD}) = 'IGNORE'; kill 'INT' => keys %children; exit; } sub run { my ($me, $vars) = @_; my $preFork = $vars->{preFork}; for (1 .. $preFork) { _startCHLD($vars); } $SIG{CHLD} = \&_REAPER; $SIG{INT} = \&_KILLER; while (1) { sleep; for (my $i = $children; $i < $preFork; $i++) { _startCHLD($vars); } } } sub _startCHLD { my ($vars) = @_; my $pid; my $sigset; $sigset = POSIX::SigSet->new(SIGINT); sigprocmask(SIG_BLOCK, $sigset) or die $!; die $! unless defined ($pid = fork); if ($pid) { # Parent process sigprocmask(SIG_UNBLOCK, $sigset) or die $!; $children{$pid} = 1; $children++; return; } else { # Child Process $SIG{INT} = 'DEFAULT'; sigprocmask(SIG_UNBLOCK, $sigset) or die $!; for (my $i = 0; $i < $vars->{maxClients}; $i++) { print "$i\n"; sleep(10); } exit; } } 1;

So, on a whole this works exactly the way it is supposed to, though it causes some of the child procs to go <defunct> after the first run through of max clients. I think the problem is with the reaping sub, and when child procs die at the same time. If two child procs die at the same time and the main program tries to reap them, could there be a problem with the variables ($children and %children) being stepped on. Granted that the program is going to be a SMTP listener (which I already have the frame work writen), so the actual possibility of child procs dieing at the same time would be rare. So to my questions, are my thoughts on the whole thing correct, and if so is there a way to lock/block during child reaping????

Thanx

Replies are listed 'Best First'.
Re: Reaping Child procs causing <defunct>????
by Abigail-II (Bishop) on May 14, 2003 at 23:20 UTC
    It's a bit hard to give real answers to your question, as different flavours of Unix act differently. I'd suggest to carefully study your system manuals about signals, signal handlers (and their need to be reinstalled), fork and the various wait calls.

    One code suggestion I'd like to make. Consider using waitpid instead of wait. perldoc -f waitpid contains a code fragment you may want to use: a non-blocking loop that reaps all zombied children.

    Abigail