wait()/waitpid() and reaping a child
When a parent starts a child process, the child eventually finishes - but the parent often needs to know two things: that it finished, and how it finished (did it succeed? crash? exit with an error code?). The wait family of calls is how a parent learns this. wait() and waitpid() pause the parent until a child terminates, then hand back that child's exit status. Picture a parent waiting at the school gate: they do not leave until their kid comes out, and when the kid arrives they find out how the day went.
There is a second, subtler job here called reaping. When a process terminates, the kernel cannot fully erase it yet - it has to keep a tiny record (the PID and the exit status) around so the parent can read how the child ended. A terminated-but-not-yet-collected child is a zombie, and it lingers until the parent calls wait. The wait call does double duty: it returns the exit status to the parent, and it tells the kernel 'I have collected this; you may now free the last traces of the child.' That collection is reaping. waitpid() is the more flexible version - it lets you wait for a specific child by PID, or check without blocking (the WNOHANG option) so the parent can keep working and poll. To decode the status, you use macros: WIFEXITED(status) is true if the child exited normally, and then WEXITSTATUS(status) gives the code it passed to exit(); WIFSIGNALED(status) is true if a signal killed it, and WTERMSIG(status) tells you which one.
Why it matters: reaping is not optional housekeeping - a parent that never waits for its children leaves a trail of zombies that occupy PID-table slots, and on a long-running server that is a slow resource leak. wait is also how the shell knows a command finished and whether to print an error. The status macros matter because the raw status integer is not the exit code - you must use WIFEXITED/WEXITSTATUS to read it correctly, a step beginners routinely skip and then misread the number.
int status; pid_t done = waitpid(pid, &status, 0); if (WIFEXITED(status)) printf("exited with %d\n", WEXITSTATUS(status)); else if (WIFSIGNALED(status)) printf("killed by signal %d\n", WTERMSIG(status)); - the parent blocks until that child ends, then decodes the packed status integer with the macros.
waitpid blocks for the child, then WIFEXITED/WEXITSTATUS unpack how it ended.
Do not read the raw status integer as the exit code - it packs both the exit code and signal info. Always use WIFEXITED then WEXITSTATUS (and WIFSIGNALED/WTERMSIG) to interpret it correctly.