These docs are under active development and cover the v0.20 Kobicha security model.
On this page
reference 3 min read

Process lifecycle reference

This is the detailed counterpart to Process lifecycle. That page explains how a process ends and is cleaned up; this one gives the exact calls — how a process terminates, what its exit status encodes, and how a parent collects it.

Ending a process

A process can end itself in a few ways, differing in how much tidying happens first:

Call What it does
exit() The orderly end. Runs every handler registered with atexit/on_exit (in reverse order of registration), flushes and closes the standard I/O streams, removes temporary files, then terminates.
_exit() / _Exit() The immediate end. Terminates at once — no registered handlers run and the standard I/O streams are not flushed — though open file descriptors are still closed. Used when a process must stop without running cleanup, such as a child after a failed exec.
exit_group() Ends the whole process — every thread in it — not just the calling one. This is what ordinary termination uses: a normal exit(), and a return from the program's entry point, both end the entire process.

Returning from the program's entry point is equivalent to calling exit() with the returned value.

At the lowest level the raw _exit system call ends only the calling thread; the library _exit and ordinary termination route through exit_group so the whole process ends. Ending one thread while the rest of the process keeps running is the unusual case.

A process can also be ended from outside, by a signal rather than by a call of its own — covered under signals. Either way, it leaves an exit status behind.

The exit status

When a process ends it leaves a small exit status for its parent to read. It records one of two outcomes:

  • Ended on its own — carries an exit code: the low 8 bits of the value passed to exit/_exit (so 0–255, with 0 conventionally meaning success).
  • Ended by a signal — carries the number of the signal that ended it, plus a flag for whether the process produced a core dump.

The status is a packed value, read not directly but through a set of macros:

Macro Tells you
WIFEXITED the process ended on its own — if so, WEXITSTATUS gives its exit code
WIFSIGNALED the process was ended by a signal — if so, WTERMSIG gives the signal number and WCOREDUMP whether it dumped core
WIFSTOPPED the process was stopped (not ended) by a signal — WSTOPSIG gives which
WIFCONTINUED the process was resumed by a continue signal

Collecting the result

A parent collects a finished child's status — and in doing so clears the zombie — with one of the wait calls. They differ in which child they target and how much they report:

Call What it offers
wait Wait for any child to end; return its PID and status. The simplest form.
waitpid Wait for a chosen target (see below). Options adjust the behaviour: WNOHANG returns immediately if nothing is ready (a poll rather than a wait), and WUNTRACED/WCONTINUED also report children that have stopped or resumed, not only ended.
waitid The most precise form. It can target a child by a pidfd (P_PIDFD) — the reliable handle from Creating processes — as well as by PID, by process group, or any child. It reports through a structured record (which child, and what happened: ended, killed, core-dumped, stopped, continued). Which kinds of change to wait for are chosen explicitly — WEXITED for children that have ended, WSTOPPED for those stopped by a signal, WCONTINUED for those resumed — and its WNOWAIT option peeks at the result while leaving the child collectable again later.
wait4 Like waitpid, and additionally returns the child's resource usage — processor time consumed, peak memory, and so on.

waitpid's target is chosen by a single number: a positive value waits for that exact PID; -1 for any child; 0 for any child in the caller's own process group; and a value below -1 for any child in the process group whose ID is its absolute value.

Two further options matter for threads and other clone-created children, which may not notify their parent with SIGCHLD the way an ordinary child does: __WCLONE waits only for such clone children, and __WALL waits for every child regardless of type.