Skip Menu |

This queue is for tickets about the Proc-Simple CPAN distribution.

Report information
The Basics
Id: 43276
Status: open
Priority: 0/
Queue: Proc-Simple

People
Owner: Nobody in particular
Requestors: aveckey [...] hotmail.com
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in: 1.23
Fixed in: (no value)



Subject: <defunct> processes can run rampant and system calls within child processes may not return valid status
Because the $SIG{CHLD} is not being reset in the child process within the start() function, sometimes <defunct> processes can pile up. Another item is if the child process is performing system commands itself, the exit statuses of those system commands are not always reflected correctly. The observation is that the $SIG{CHLD} is still set to \&THE_REAPER and Proc::Simple has no record of those grandchild processes, so they are left <defunct>, waiting to be reaped. The fix is to add as the first line in the start() functions child process a 'local $SIG{CHLD};' in order to reset the CHLD signal handle for the child.
On Fri Feb 13 19:27:58 2009, aveckey wrote: Show quoted text
> Because the $SIG{CHLD} is not being reset in the child process within > the start() function, sometimes <defunct> processes can pile up. > > Another item is if the child process is performing system commands > itself, the exit statuses of those system commands are not always > reflected correctly. > > > The observation is that the $SIG{CHLD} is still set to \&THE_REAPER and > Proc::Simple has no record of those grandchild processes, so they are > left <defunct>, waiting to be reaped. > > > The fix is to add as the first line in the start() functions child > process a 'local $SIG{CHLD};' in order to reset the CHLD signal handle > for the child.
The below will reproduce the results I am seeing, note that within the child process 'test()' function, the $SIG{CHLD} is still set. The <defunct> processes will accumulate under the child processes, so keep monitoring the whole process tree, once the original child is reaped, the <defunct> processes will be purged too (but I have seen cases where they remain). I am running this on Perl 5.8.8 SunOS il93hsrv41 5.9 Generic_118558-39 sun4u sparc SUNW,Sun-Fire-V440 Solaris use Proc::Simple; use Cwd; my %procs = (); foreach my $cnt (1..4) { $procs{$cnt} = new Proc::Simple(); $procs{$cnt}->start(\&test, $cnt, @ARGV); } print "Current directory is ", cwd(), "\n"; print "Current directory is ", cwd(), "\n"; print "Current directory is ", cwd(), "\n"; print "Press <enter> to continue ($$)\n"; <STDIN>; sub test { my $iteration = shift; print "Passed was $iteration\n"; foreach my $cnt (0..20) { printf "%d Waiting %d more seconds ...\n",$$, 20 - $cnt; print "Current directory is ", cwd(), "\n"; my $sys = system(qq(perl -e 'exit($cnt);')); printf "%d should be %d (%d)\n", $cnt, $sys, $sys / 256; print "SIG = $SIG{CHLD}\n"; sleep(1); } print "-------------------------$$ done.\n"; }
The fix that I am suggesting is adding a 'local' before redefining the 'CHLD' signal handler and also blanking 'CHLD' within the child process: <PRE> sub start { my $self = shift; my ($func, @params) = @_; # Reap Zombies automatically local $SIG{'CHLD'} = \&THE_REAPER; # Fork a child process $self->{'pid'} = fork(); return 0 unless defined $self->{'pid'}; # return Error if fork failed if($self->{pid} == 0) { # Child local $SIG{'CHLD'}; # Turn off 'CHLD' signal handler if (defined $self->{'redirect_stderr'}) { $self->dprt("STDERR -> $self->{'redirect_stderr'}"); open(STDERR, ">$self->{'redirect_stderr'}") ; autoflush STDERR 1 ; } if (defined $self->{'redirect_stdout'}) { $self->dprt("STDOUT -> $self->{'redirect_stdout'}"); open(STDOUT, ">$self->{'redirect_stdout'}") ; autoflush STDOUT 1 ; } if(ref($func) eq "CODE") { $func->(@params); exit 0; # Start perl subroutine } else { exec $func, @params; # Start shell process exit 0; # In case something goes wrong } } elsif($self->{'pid'} > 0) { # Parent: $INTERVAL{$self->{'pid'}}{'t0'} = time(); $self->dprt("START($self->{'pid'})"); # Register PID $EXIT_STATUS{$self->{'pid'}} = undef; $INTERVAL{$self->{'pid'}}{'t1'} = undef; return 1; # return OK } else { return 0; # this shouldn't occur } } </PRE>