--- name: waitpid signature: 'waitpid PID, FLAGS' since: 5.0 status: documented categories: ["Processes"] --- ```{index} single: waitpid; Perl built-in ``` *[Processes](../perlfunc-by-category)* # waitpid Wait for a specific child process to terminate and reap it. `waitpid` is the targeted counterpart of [`wait`](wait). Where [`wait`](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 [`$?`](../perlvar), identically to [`wait`](wait). ## Synopsis ```perl 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. - `0` when `WNOHANG` is set and at least one matching child exists but none have terminated yet — i.e. "still running, try again later". - `-1` when no child process matches `PID` (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 [`$?`](../perlvar) and the raw platform status to [`${^CHILD_ERROR_NATIVE}`](../perlvar) on every successful reap. Decode [`$?`](../perlvar) the same way you would after [`wait`](wait) or a backtick call: ```perl 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. `-1` on 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 as [`wait`](wait). - **Less than `-1`** — wait for any child whose process group ID equals the absolute value of `PID`. `waitpid -$pgid, 0` waits 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 - [`$?`](../perlvar) — set to the exit status of the reaped child (shifted: high byte = `exit` code, low 7 bits = signal, bit `0x80` = core-dumped flag). - [`${^CHILD_ERROR_NATIVE}`](../perlvar) — set to the raw platform status word, before Perl normalises it into [`$?`](../perlvar). 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: ```perl 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: ```perl 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: ```perl 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: ```perl 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: ```perl 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 - **`WNOHANG` requires `use POSIX`**. The constant is not a Perl built-in; it comes from the [`POSIX`](../../POSIX) module, typically via `use 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 with `waitpid`**. When you tell the kernel to auto-reap children, there is nothing left for `waitpid` to find — it returns `-1` with [`$!`](../perlvar) set to `ECHILD`. 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 to `waitpid` twice, the second call returns `-1`. - **Negative `PID` is a process group, not "any but this one"**. `waitpid -1234, 0` waits for members of process group `1234`, not "every child except PID 1234". Readers unfamiliar with the POSIX convention often misread this. - **`WNOHANG` with `PID = -1`** is the standard "drain the zombie queue" form. Combined with a `while` loop it reaps every child that has already exited and stops as soon as the kernel has nothing more to hand back. - **Return value of `-1` can also mean auto-reap**. On systems configured to reap children automatically (e.g. a `$SIG{CHLD} = 'IGNORE'` handler installed at startup), `waitpid` sees no child and returns `-1` even for a PID you just forked. See `perlipc` for the platform notes. - **Blocking wait is always available**. Even on platforms without a native `waitpid(2)` or `wait4(2)` syscall, `waitpid PID, 0` works — 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`](wait) — block for *any* child; equivalent to `waitpid -1, 0` on systems that support it - [`fork`](fork) — create the children you will later reap with `waitpid` - [`kill`](kill) — send a signal to the same PIDs and process groups `waitpid` accepts - [`$?`](../perlvar) — exit status of the reaped child; decode as `$? >> 8` for the exit code, `$? & 127` for the signal - [`${^CHILD_ERROR_NATIVE}`](../perlvar) — raw platform status word for the same child - [`POSIX`](../../POSIX) — source of `WNOHANG` and the rest of `:sys_wait_h`