Linux System Programming · intermediate · ~10 min

wait and waitpid

Collect a child's exit status.

Overview

wait(&status) and waitpid(pid, &status, opts) suspend the parent until a child terminates, returning the child's PID and exit status. Without wait, exited children linger as zombies — entries in the process table with no memory, holding only an exit code waiting to be collected.

Why it matters

In a fork-based program, the parent must collect each child's exit code or accept that zombies will pile up. On a long-running server that spawns hundreds of subprocesses an hour, missed wait calls eventually fill the kernel's process table and the system fails to fork new children.

Core concepts

Status macros. WIFEXITED(status) is true if the child exited normally; WEXITSTATUS(status) extracts the exit code. WIFSIGNALED / WTERMSIG tell you about signals. waitpid flags. WNOHANG makes wait non-blocking (returns 0 if no child has exited yet). SIGCHLD. When a child exits, the parent gets a SIGCHLD; you can install a handler that calls waitpid in a loop.

Syntax notes

int status;
pid_t kid = waitpid(child, &status, 0);
if (WIFEXITED(status)) printf("exited with %d\n", WEXITSTATUS(status));
else if (WIFSIGNALED(status)) printf("killed by signal %d\n", WTERMSIG(status));

Lesson

When a child exits, the kernel keeps a small record (the zombie) until the parent calls wait or waitpid. int waitpid(pid_t pid, int *status, int options) blocks (or polls with WNOHANG) until the specified child terminates.

Decode status with WIFEXITED + WEXITSTATUS for normal exits, WIFSIGNALED + WTERMSIG for signal kills.

Code examples

int st;
waitpid(pid, &st, 0);
if (WIFEXITED(st))   printf("exit %d\n", WEXITSTATUS(st));
if (WIFSIGNALED(st)) printf("killed by signal %d\n", WTERMSIG(st));

Common mistakes

  • Forgetting WIFEXITED before WEXITSTATUS — the macro extracts a specific bit field.

Debugging tips

ps -ef | grep defunct lists zombies — each is a child you forgot to wait on. Modern Linux has prctl(PR_SET_CHILD_SUBREAPER, 1) so a parent can claim grandchildren, useful in service managers.

Memory safety

Wait is about resource hygiene, not memory. The kernel keeps a small struct for each unreaped child; long-running servers must reap (or use SIGCHLD handler + waitpid-loop) to avoid accumulating them.

Real-world uses

Every shell after every command, every web server with a per-connection child, cron, init/systemd's reaper.

Practice tasks

  1. Fork a child that prints and _exit(7); have the parent print its exit code via WEXITSTATUS. 2. Fork 5 children and waitpid for each. 3. Install a SIGCHLD handler that calls waitpid(-1, &st, WNOHANG) in a loop.

Summary

wait collects exited children's status and cleans them out of the process table. Pair every fork with a wait (or a SIGCHLD handler) to avoid zombies. The fork/exec/wait triad is the heart of Unix process management.

Practice with these exercises