16.19.3. Discussion
When a process exits, the system keeps it in the process table so the
parent can check its status—whether it terminated normally or
abnormally. Fetching a child's status (thereby freeing it to drop
from the system altogether) is rather grimly called
reaping dead children. (This entire recipe is
full of ways to harvest your dead children. If this makes you queasy,
we understand.) It involves a call to wait or
waitpid. Some Perl functions (piped
open s, system, and backticks)
will automatically reap the children they make, but you must
explicitly wait when you use fork to manually
start another process.
To avoid accumulating dead children, simply tell the system that
you're not interested in them by setting
$SIG{CHLD} to "IGNORE". If you
want to know which children die and when, you'll need to use
waitpid.
use POSIX qw(:signal_h :errno_h :sys_wait_h);
$SIG{CHLD} = \&REAPER;
sub REAPER {
my $pid;
$pid = waitpid(-1, &WNOHANG);
if ($pid = = -1) {
# no child waiting. Ignore it.
} elsif (WIFEXITED($?)) {
print "Process $pid exited.\n";
} else {
print "False alarm on $pid.\n";
}
$SIG{CHLD} = \&REAPER; # in case of unreliable signals
}
The second trap with SIGCHLD is related to Perl,
not the operating system. Because system,
open, and backticks all fork subprocesses and the
operating system sends your process a SIGCHLD
whenever any of its subprocesses exit, you could get called for
something you weren't expecting. The built-in operations all wait for
the child themselves, so sometimes the SIGCHLD
will arrive before the close on the filehandle
blocks to reap it. If the signal handler gets to it first, the zombie
won't be there for the normal close. This makes
close return false and set $!
to "No child
processes". Then, if the close
gets to the dead child first, waitpid will return
0.
Most systems support a non-blocking waitpid. Use
Perl's standard Config.pm module to find out:
use Config;
$has_nonblocking = $Config{d_waitpid} eq "define" ||
$Config{d_wait4} eq "define";
System V defines SIGCLD, which has the same signal
number as SIGCHLD but subtly different semantics.
Use SIGCHLD to avoid confusion.