Skip to content
/linux-syscalls

Process & Thread · Section 2

wait4(2)

Wait for a child process to change state and collect its exit information and resource usage.

Signature

#include <sys/wait.h>
#include <sys/resource.h>

pid_t wait4(pid_t pid, int * wstatus, int options, struct rusage * rusage);
pid
Target. > 0: specific child PID. 0: any child in the caller's process group. -1: any child. < -1: child in process group |pid|.
wstatus
If non-NULL, receives the encoded exit status. Decode with WIFEXITED, WEXITSTATUS, WIFSIGNALED, WTERMSIG, WCOREDUMP.
options
Bitwise OR of WNOHANG (don't block), WUNTRACED (also report stopped), WCONTINUED (also report continued), __WCLONE / __WALL (control which children are eligible — relevant for ptrace-tracees and clone() children).
rusage
If non-NULL, receives the child's resource usage. NULL is fine when only the exit status is needed.

Description

wait4() blocks the caller until a child process changes state — exits, is killed by a signal, or (with WUNTRACED / WCONTINUED) stops or resumes. It returns the PID of the affected child and, via wstatus, an integer encoding the cause (decoded with WIFEXITED, WEXITSTATUS, WIFSIGNALED, WTERMSIG, etc.). If rusage is non-NULL, the child's CPU time and memory usage are returned in *rusage. pid > 0 waits for that specific child; pid == 0 waits for any child in the caller's process group; pid == -1 waits for any child; pid < -1 waits for any child in process group |pid|. wait4() is the canonical kernel mechanism that turns zombies into reaped exit notifications. wait() and waitpid() are libc wrappers; waitid() is the modern, more flexible alternative.

Architecture mapping

ArchitectureNumberABIEntry point
x86 (i386)114i386sys_wait4
x64 (x86_64)61commonsys_wait4
ARM64 (aarch64)260

Kernel history

Introduced in Linux 1.0.

  1. 1.0

    wait4() has been part of Linux since 1.0, inherited from BSD as a superset of POSIX wait() (BSD added the rusage argument).

  2. 2.6.9

    waitid() was added as a more capable variant with finer-grained idtype (P_PID, P_PGID, P_ALL, P_PIDFD) and richer siginfo_t output — the modern replacement, though wait4() is still ubiquitous because glibc's waitpid() uses it under the hood.

seccomp & containers

Docker default profile

Allowed

Podman default profile

Allowed

wait4() and waitid() are allowed by Docker / Podman default profiles. Blocking them is rarely useful — every process that spawns children needs to reap them or the kernel accumulates zombies indefinitely (until the parent dies and they reparent to init).

libseccomp

seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(wait4),  0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(waitid), 0);

strace example

$ strace -f -e wait4 bash -c 'sleep 0.1 &; wait'
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 13284
+++ exited with 0 +++

wait4() in strace shows the decoded WIF* macros: '{WIFEXITED(s) && WEXITSTATUS(s) == 42}' or '{WIFSIGNALED(s) && WTERMSIG(s) == SIGSEGV}'. The WNOHANG return of 0 is normal in poll-loops; persistent ECHILD with active children suggests a SIGCHLD-to-SIG_IGN footgun.

Security & observability

wait4() is not directly a security primitive but its presence is part of the lifecycle: a process that fork()/execve()s children but never wait4()s them leaves zombies in /proc — a leak signature. Container init processes (tini, dumb-init, Pod's pause) exist primarily to reap orphaned children; without one, defunct entries pile up. eBPF tracepoint sched_process_exit covers the same lifecycle event from the kernel side and is preferred for monitoring because it doesn't rely on the parent calling wait4().

Errors

ECHILD
No matching children exist — either there are none, or they were all reaped already, or the caller has set SIGCHLD to SIG_IGN (which auto-reaps).
EINTR
Interrupted by a signal that did not have SA_RESTART set.
EINVAL

Flags

WNOHANG
1
Return 0 immediately if no child has changed state, instead of blocking. The polling-loop idiom.
WUNTRACED
2
Also report children that have stopped (e.g. via SIGSTOP). Used by debuggers and job-control shells.
WCONTINUED
8
Also report children that have resumed after being stopped (SIGCONT).
__WCLONE
0x80000000
__WALL
0x40000000
Wait for any child regardless of clone semantics (default excludes some kernel-thread-like clones). Used by strace and gdb.

Related syscalls