7/32 · 5 min
Where a new process comes from
Every process except the first is created by another. On Unix the mechanism is two calls that do one thing each, and the split is what makes shells possible.
fork
fork() duplicates the calling process. Both continue from the same line, and the return value is the only way to tell them apart:
pid_t pid = fork();
if (pid == 0) {
// child: fork returned 0
} else if (pid > 0) {
// parent: fork returned the child's pid
} else {
// failed
}The child gets a copy of the memory, the open files and the working directory. It does not share memory with the parent: a variable changed in one is unchanged in the other.
Copy on write
Copying an entire address space would make fork unusable for a large process. So nothing is copied. Both processes point at the same physical pages, marked read only, and a page is duplicated only when one of them writes to it.
A process using 2GB forks in under a millisecond, and pays only for the pages that actually diverge.
exec
exec replaces the current program with a different one. Same process id, same open files, entirely new code and memory.
if (fork() == 0) {
execlp("ls", "ls", "-l", NULL);
// only reached if exec failed
}That is what a shell does on every command. The split matters because between the fork and the exec the child can change things, and that window is how redirection works:
ls > out.txt # child reopens its output as out.txt, then execs lsls knows nothing about the file. It writes to its output, which the shell already pointed elsewhere.
Zombies and orphans
A finished process keeps its exit status until the parent collects it with wait. Until then it is a zombie: no memory, no CPU, just an entry in the process table.
A parent that never calls wait leaks those entries, and the table is finite. The table filling up is a real outage and looks like the machine refusing to start anything.
An orphan is the opposite: the parent exited first. The child is adopted by PID 1, which does call wait, so orphans are harmless.
| Cause | Harmful | |
|---|---|---|
| Zombie | parent alive, not reaping | yes, leaks table entries |
| Orphan | parent exited first | no, PID 1 adopts it |