waitpid#
Wait for a specific child process to terminate and reap it.
waitpid is the targeted counterpart of wait. Where
wait reaps any child and blocks until one exits, waitpid
lets you name which child (or which group of children) to wait for,
and lets you poll instead of block by passing WNOHANG in FLAGS.
The exit status of the reaped child lands in $?,
identically to wait.
Synopsis#
use POSIX ":sys_wait_h";
waitpid $pid, 0; # block until $pid exits
waitpid $pid, WNOHANG; # poll: is $pid done yet?
waitpid -1, WNOHANG; # reap any ready zombie, don't block
What you get back#
The PID of the reaped child on success.
0whenWNOHANGis set and at least one matching child exists but none have terminated yet — i.e. “still running, try again later”.-1when no child process matchesPID(never existed, already reaped, or — on systems that auto-reap — was harvested by the kernel without Perl’s help).
The child’s exit status is written to $? and the raw
platform status to ${^CHILD_ERROR_NATIVE} on every
successful reap. Decode $? the same way you would
after wait or a backtick call:
my $reaped = waitpid $pid, 0;
if ($reaped > 0) {
my $exit = $? >> 8;
my $signal = $? & 127;
my $core = $? & 128;
}
What PID means#
PID selects which children waitpid is willing to reap:
Positive PID — wait for that specific child.
-1on return means no such child (you already reaped it, or it was never yours).0— wait for any child in the current process group. Useful when your program has joined a process group with other cooperating processes and you only want to harvest your own.-1— wait for any child, same scope aswait.Less than
-1— wait for any child whose process group ID equals the absolute value ofPID.waitpid -$pgid, 0waits for any member of process group$pgid.
FLAGS is a bitmask. The portable flag is WNOHANG, which makes
the call non-blocking: if no matching child has exited, waitpid
returns 0 immediately instead of sleeping. FLAGS of 0 means
“block until something is reapable”, and is implemented on every
platform Perl runs on — even those without a native waitpid(2)
syscall, where Perl emulates it by remembering exit statuses of
children it has already seen.
Global state it touches#
$?— set to the exit status of the reaped child (shifted: high byte =exitcode, low 7 bits = signal, bit0x80= core-dumped flag).${^CHILD_ERROR_NATIVE}— set to the raw platform status word, before Perl normalises it into$?.
Neither variable is touched when waitpid returns 0
(WNOHANG and nothing ready) or -1 (no matching child).
Examples#
Block until a known child finishes, then inspect its exit code:
my $pid = fork // die "fork: $!";
if ($pid == 0) {
exec "/usr/bin/gzip", "big.log" or die "exec: $!";
}
waitpid $pid, 0;
die "gzip failed with status ", $? >> 8 if $?;
Poll without blocking — useful inside an event loop or a
SIGCHLD handler:
use POSIX ":sys_wait_h";
sub harvest_children {
while ((my $kid = waitpid -1, WNOHANG) > 0) {
warn "child $kid exited with ", $? >> 8, "\n";
}
}
The classic “reap every pending zombie, don’t block” idiom:
use POSIX ":sys_wait_h";
1 while waitpid(-1, WNOHANG) > 0;
Wait only for children in a specific process group. setpgid first,
then target the group by negating its ID:
my $leader = fork // die "fork: $!";
if ($leader == 0) {
setpgid 0, 0; # become process-group leader
exec @worker_cmd or die "exec: $!";
}
setpgid $leader, $leader; # parent matches, races with child
# ... later, reap any member of that group:
while ((my $kid = waitpid -$leader, WNOHANG) > 0) {
log_exit($kid, $?);
}
Distinguish the three return values in one place:
my $r = waitpid $pid, WNOHANG;
if ($r == $pid) { finalize_child($pid, $?) }
elsif ($r == 0) { still_running($pid) }
elsif ($r == -1) { warn "no such child $pid (already reaped?)" }
Edge cases#
WNOHANGrequiresuse POSIX. The constant is not a Perl built-in; it comes from thePOSIXmodule, typically viause POSIX ":sys_wait_h";. Writing a bare integer (waitpid $pid, 1) works on Linux but is not portable and hides intent.$SIG{CHLD} = 'IGNORE'races withwaitpid. When you tell the kernel to auto-reap children, there is nothing left forwaitpidto find — it returns-1with$!set toECHILD. Choose one reaping strategy per program, not both.Already-reaped PIDs return
-1. A single child’s PID can only be reaped once; after that, it is forgotten. If you hand the same PID towaitpidtwice, the second call returns-1.Negative
PIDis a process group, not “any but this one”.waitpid -1234, 0waits for members of process group1234, not “every child except PID 1234”. Readers unfamiliar with the POSIX convention often misread this.WNOHANGwithPID = -1is the standard “drain the zombie queue” form. Combined with awhileloop it reaps every child that has already exited and stops as soon as the kernel has nothing more to hand back.Return value of
-1can also mean auto-reap. On systems configured to reap children automatically (e.g. a$SIG{CHLD} = 'IGNORE'handler installed at startup),waitpidsees no child and returns-1even for a PID you just forked. Seeperlipcfor the platform notes.Blocking wait is always available. Even on platforms without a native
waitpid(2)orwait4(2)syscall,waitpid PID, 0works — Perl emulates it by retaining the statuses of children it has already collected.
Differences from upstream#
Fully compatible with upstream Perl 5.42.
See also#
wait— block for any child; equivalent towaitpid -1, 0on systems that support itfork— create the children you will later reap withwaitpidkill— send a signal to the same PIDs and process groupswaitpidaccepts$?— exit status of the reaped child; decode as$? >> 8for the exit code,$? & 127for the signal${^CHILD_ERROR_NATIVE}— raw platform status word for the same childPOSIX— source ofWNOHANGand the rest of:sys_wait_h