Skip to main content

Source: Operating Systems: Three Easy Pieces (OSTEP) — Chapter 5 (Interlude), Arpaci-Dusseau & Arpaci-Dusseau

Interlude: Process API

Interludes

Interludes focus on practical OS APIs — how real systems let you create and control processes. Skip them only if you dislike useful things (employers usually do not).

Crux: what interfaces should the OS present for process creation and control — powerful, usable, and fast?

UNIX’s answer is an odd but brilliant trio: fork(), exec(), and wait().

fork() — create a near-copy​

fork() creates a new process that is an almost exact copy of the caller:

  • Own address space, registers, PC, …
  • Does not restart at main — both parent and child return from fork()
  • Parent return value: child’s PID
  • Child return value: 0
  • On failure: negative (check and exit)
int rc = fork();
if (rc < 0) { /* fail */ }
else if (rc == 0) { /* child */ }
else { /* parent: rc is child pid */ }

Output order of parent vs child is nondeterministic — the scheduler decides who runs first.

wait() — parent blocks until child finishes​

wait() (or waitpid()) lets a parent delay until a child exits. Then:

  • Child always effectively “prints first” (if parent waits before its own print)
  • wait() returns the child’s PID (when it reaps that child)

Without wait(), a short-lived parent can exit while the child still runs; with it, the shell can show the next prompt only after the command completes.

exec() — replace the program image​

exec() (e.g. execvp) does not create a new process. It transforms the current one:

  1. Load new code + static data from an executable
  2. Re-init heap / stack / etc.
  3. Jump into the new program with argv

A successful exec never returns. Code after execvp(...) is only reached if exec failed.

Quiz

Rank the sequence

1 / 1

Order the steps exec() performs to transform the calling process (top = first).

OrderDrag the handle to rearrange — top should be first.

  1. 1Jump into the new program, passing argv
  2. 2Re-initialize the heap, stack, and other regions
  3. 3Load new code and static data from the executable

Drag items into the correct order (or use ↑↓), then check.

Why separate fork and exec?​

A UNIX shell is just a user program: prompt → parse → fork → (optional setup) → exec → wait → prompt again.

The gap between fork and exec is where the shell implements:

FeatureTrick in the child before exec
wc file > out.txtclose(STDOUT_FILENO); open("out.txt", …) — next free fd is usually 1
Pipes a | bpipe(); connect one child’s stdout to the other’s stdin
Env / cwd tweaksChange environment without changing the target program
Lampson’s law (getting it right)

Many process-creation APIs are possible. Separating fork and exec is simple and extremely powerful — the UNIX designers got it right.

Quiz

Rank the sequence

1 / 1

Order the steps a UNIX shell performs to run one command (top = first).

OrderDrag the handle to rearrange — top should be first.

  1. 1wait for the child to finish in the parent
  2. 2exec the requested program in the child
  3. 3fork a child process
  4. 4parse the command line typed at the prompt

Drag items into the correct order (or use ↑↓), then check.

Interactive: fork → wait → exec → redirect​

Step through the same story as OSTEP’s p1–p4 examples.

Try:

  • fork() — two return values; hello printed once; race on print order
  • fork + wait — parent blocks → deterministic child-then-parent
  • fork + exec — child becomes wc; post-exec code is dead
  • I/O redirect — rearrange fds so wc writes to a file

Check your understanding​

Quiz

fork, exec, wait

1 / 4

After a successful fork(), the child…

Pick an answer to see if you are right.

Coding challenges​

Piston cannot really fork/exec — these C drills classify return values the way your local homework will. Real unistd.h calls stay in the lab below.

Homework lab: Process API (C on your machine)​

Write real programs with fork / exec / wait / pipe on a UNIX-like system (Linux, macOS, WSL). Use notes and screenshots below — saved in this browser (IndexedDB).

Reference: OSTEP cpu-api homework.

Lab

Homework: Process API (code)

0/8 started

Loading lab…

Process control, users, tools​

Beyond create/run/wait:

Tool / APIRole
Signals (kill, Ctrl-C → SIGINT, Ctrl-Z → SIGTSTP)Pause, resume, terminate processes
UsersUsually you may only signal your processes
Superuser (root)Can control any process — use rarely and carefully
ps / top / killInspect load; send signals from the shell
RTFM

man 2 fork, man 2 execve, man 2 wait, and your shell’s man page beat random blog posts. Colleagues who say “RTFM” mean: read the man pages.

Summary​

TermMeaning
PIDNumeric name of a process
fork()Create child ≈ copy of parent; return values differ
wait() / waitpid()Parent waits to reap a child
exec() familyReplace current program image
Shellfork → setup (redirect/pipe) → exec → wait
Signals / users / rootWho may control which processes

Next: Limited Direct Execution — traps, timers, and context switches.

Further Reading​

  • Remzi & Andrea Arpaci-Dusseau — Operating Systems: Three Easy Pieces Ch. 5
  • W. Richard Stevens & Stephen A. Rago — Advanced Programming in the UNIX Environment (process control chapters)
  • OSTEP homework code: cpu-api