Scott Penrose

SIG CHLD

Scott is an expert software developer with over 30 years experience, specialising in education, automation and remote data.

There is a lot of confusion on $SIG{CHLD} in perl. There are three ways to go and they all have side effects. This document is not the answer, but the question - answers still to be discovered.

$SIG{CHLD} undefined

If you now do a fork directly, on unix systems at least, you will end up with Zombie Processes. Processes that sit in the memory space waiting to return their signal to the parent, until the parent is terminated.

This is BAD if you want to use fork.

$SIG{CHLD} = 'ignore'

A handy method for ignoring the return signals but still being there to listen (that is what is all about). No more zombie process.

But now.. you can't get your error from a SYSTEM call.

#!Perl
system("sleep 20");
print "LOCAL = $?\n";

Fails !

local $SIG{CHLD} = undef

It is tempting to think of $SIG{CHLD} like you would $SIG{_DIE_} - which is you can set a local one for a block.

#!Perl
{
    local $SIG{CHLD} = undef;
    system("sleep 20");
    print "LOCAL = $?\n";
}

This seems on the surface ok, but it is very bad - because now you miss signals that happen during your system call. Unlike internals like DIE, CHLD is a one slot unix signal handler.

perlipc example

#!Perl
use POSIX ":sys_wait_h";
sub REAPER {
    my $child;
    while (($waitedpid = waitpid(-1,WNOHANG)) > 0) {
        logmsg "reaped $waitedpid" . ($? ? " with exit $?" : '');
    }
    $SIG{CHLD} = \&REAPER;  # loathe sysV
 }

$SIG{CHLD} = \&REAPER;

This example happily catches the output of all the dead children, but what about our system call and return value inside $?

Well that is still a problem. The only real solution I know of is to keep the return values in the reaper and then check those after the system call...

CPAN

The answer is probably in CPAN - somewhere there is a module that does system without depending on the $SIG{CHLD}, but I can't find it?

  • HowTo
  • Perl