wait#
Block until any child process exits and reap it.
wait is the simplest front end to the underlying wait(2)
system call. It suspends the current process until one of its children
terminates, collects that child’s exit status into $? and
${^CHILD_ERROR_NATIVE}, and returns the reaped child’s PID.
If there are no children to wait on, it returns -1 immediately. It is
exactly equivalent to waitpid(-1, 0).
Synopsis#
my $pid = wait;
What you get back#
The PID of the child that was reaped (a positive integer), or -1 if
there are no unreaped children left to wait on. The child’s status goes
into $?; the raw, OS-specific status word goes into
${^CHILD_ERROR_NATIVE}.
To decode $? after a successful wait:
my $exit = $? >> 8; # normal exit code (0..255)
my $signal = $? & 0x7f; # termination signal, if any
my $core = $? & 0x80; # core-dump flag
A -1 return does not always mean “never had any children” — it
can also mean “something already reaped them for me” (see below).
Global state it touches#
$?— set to the reaped child’s 16-bit wait status (high byte: exit code, low byte: termination signal and core flag). Also readable as$CHILD_ERRORunderuse English.${^CHILD_ERROR_NATIVE}— the platform’s raw status word, for callers that want to use POSIX macros (WIFEXITED,WEXITSTATUS,WIFSIGNALED,WTERMSIG) fromPOSIX.%SIG— if$SIG{CHLD}is set to'IGNORE', or a handler in it callswaititself, this call’s result changes. See Edge cases.
Examples#
Fork a worker, do something, then reap it:
my $pid = fork // die "fork: $!";
if ($pid == 0) {
# child
exec "/usr/bin/true" or die "exec: $!";
}
my $reaped = wait; # blocks until the child exits
die "unexpected pid" if $reaped != $pid;
printf "child %d exited %d\n", $reaped, $? >> 8;
Reap every outstanding child in a loop. wait returns -1 once the
process has none left:
while ((my $kid = wait) > 0) {
warn "reaped $kid, status " . ($? >> 8) . "\n";
}
Distinguish normal exit from signal termination:
my $pid = wait;
if ($pid > 0) {
if ($? == 0) { say "clean exit" }
elsif ($? & 0x7f) { say "killed by signal " . ($? & 0x7f) }
else { say "exit " . ($? >> 8) }
}
Decode the native status word with POSIX macros, which is
more portable than manual bit-shifting:
use POSIX ":sys_wait_h";
my $pid = wait;
if ($pid > 0 && WIFEXITED(${^CHILD_ERROR_NATIVE})) {
say "exit code: ", WEXITSTATUS(${^CHILD_ERROR_NATIVE});
}
Non-blocking reap of every pending zombie — use waitpid
with WNOHANG, not wait:
use POSIX ":sys_wait_h";
1 while waitpid(-1, WNOHANG) > 0;
Edge cases#
No children to wait on: returns
-1immediately.waitdoes not block in this case — it only blocks when at least one child is still alive and unreaped.$SIG{CHLD} = 'IGNORE': on POSIX systems this asks the kernel to auto-reap children. Under this setting,waitalmost always returns-1because the children are gone before user code can call it.$?is not set. If you want both fire-and-forget children and status reporting, use a real handler, not'IGNORE'.Custom
$SIG{CHLD}handler: if the handler callswait(orwaitpid) itself, a subsequentwaitin the main flow will find nothing left and return-1. Decide up-front which code path does the reaping.Interaction with
qx//andsystem: both of these internally fork, exec, and wait on their own child. A$SIG{CHLD}handler that blindly callswaitcan accidentally reap that internal child out from underqx//orsystem, leaving them unable to collect the status and typically returning-1with$!set toECHILD. Handlers should loop withwaitpid(-1, WNOHANG)and only act on PIDs they recognise.$?is only written on a successful reap. After a-1return,$?retains whatever it had before the call. Don’t inspect it unlesswaitreturned a positive PID.Interrupted by a signal: if a signal is delivered while
waitis blocked and the handler returns normally, Perl restarts the wait — you do not seeEINTRat the Perl level. If the handlerdies orexits, control leaveswaitthe usual way for that mechanism.Threaded builds:
waitwaits for children of the current process, not children of a specific thread. In a multi-threaded program the reaping thread is whichever one calledwaitfirst.Return value is a PID, not a boolean:
if (wait) { ... }is true for both successful reaps and-1. Always compare to0or check> 0explicitly, as in the loop form above.
Differences from upstream#
Fully compatible with upstream Perl 5.42.
See also#
waitpid— wait for a specific child, or poll non-blockingly withWNOHANG;waitis thewaitpid(-1, 0)formfork— create the children thatwaitreapsexec— what a forked child typically calls to become a different programsystem— fork + exec + wait in one call; uses its own internalwaitand sets$?for youkill— send a signal to a child you no longer want to wait for$?— where the reaped child’s status lands, encoded as exit-code high byte plus signal/core low byte