OS Foundations and Process Model
Work through examples, try the reasoning yourself, then put it into practice.
View SlidesBefore you start
- Trace a map and parent/child graph with integer identifiers.
What you will practice
- Reconstruct fork/exit/wait histories including already-zombie child adoption.
- Maintain parent/child invariants and distinguish privilege changes from scheduling.
In this lesson
Lesson
5 min readOS Foundations and Process Model
Build a process table that remains consistent as parents exit and children are reaped. Prepare by tracing maps and parent/child relationships. The executable model tracks identity, parenthood and zombie state; it does not implement an actual scheduler, address space or system-call interface.
Separate privilege from scheduling
A system call enters a controlled kernel path to request an operation. The kernel validates arguments and permissions. That privilege transition can return to the same process: it need not schedule another process. A context switch changes the running execution context, saving/restoring registers and other machine state. Costs depend on architecture and workload; tagged TLBs can retain translations, so not every process switch necessarily flushes the entire TLB. The virtual-memory module works through address-space tags explicitly.
A process includes more than executable code: address-space mappings, registers, open-resource references and scheduling metadata. READY means eligible for CPU; RUNNING means executing; BLOCKED means waiting for an event; ZOMBIE means execution has ended but bookkeeping remains for collection. A zombie is not a blocked process waiting to resume.
Fork, exec, exit and wait do different work
Fork creates a child identity with a logically copied execution environment. Exec replaces a process's program image while keeping its identity; it does not create a second child PID. Exit ends execution, and wait collects a child's exit information and permits final bookkeeping removal. The simulator reduces these operations to Fork, Exit and Wait; it has no Exec or exit-status field.
Its initial process is PID 1 with parent 0. Successful Fork calls issue 2, 3, 4, ...; failed calls return -1 without consuming a PID. Only an existing living parent may fork. PID 1 never exits in this model. Adoption is always to PID 1, which is a teaching policy rather than a claim about every host configuration.
Work a parent exit with both kinds of children
Create 2 under init, then 3 and 4 under 2. Process 3 exits first:
| Event | PID 2 | PID 3 | PID 4 |
|---|---|---|---|
| after creation | live, parent 1 | live, parent 2 | live, parent 2 |
| Exit(3) | live, parent 1 | zombie, parent 2 | live, parent 2 |
| Exit(2) | zombie, parent 1 | zombie, parent 1 | live, parent 1 |
| Wait(1) returns 2 | removed | zombie, parent 1 | live, parent 1 |
| Wait(1) returns 3 | removed | removed | live, parent 1 |
| Wait(1) returns -1 | removed | removed | still live |
Exit reparents all existing children, including zombies, without changing their zombie state. Otherwise removing PID 2 could leave PID 3 with a nonexistent parent and no intended reaper. Wait chooses the smallest zombie child PID, not the earliest exit and not the smallest living child. Reaping removes only that process, not its adopted descendants.
This resolves a historical wording mismatch: the supplied reference already adopted zombies, while the old statement mentioned living children only. Use the explicit all-child rule when implementing or updating a prior solution.
Derive the data invariants
A PID lookup maps to its parent and zombie flag. If you also keep a set of children per process, each non-init process must appear in exactly its parent's set. Adoption therefore updates three things: the child's parent, the old parent's child set, and init's child set. Updating only the parent field can make Parent look correct while Wait never discovers the child.
Exit marks the process zombie after moving its children; repeating Exit has no additional effect. Exit of an unknown PID does nothing. Wait removes the chosen child from both the PID table and its parent's child set. Parent of a removed PID returns -1; IsZombie returns false. PID numbers are not reused.
A straightforward implementation scans the parent's child set to select the minimum zombie ID, costing O(children) per Wait. Exit also scans its children. Sorting every process table entry is unnecessary for either operation. The exercise prioritizes correct lifecycle state over designing a production PID allocator or wait queue.
Complete the trace and diagnose a bug
Create 2 and 3 under PID 1. Exit 3, then Exit 2. Predict two Wait(1) results, then Fork(2), then Fork(1). Explain why order of exit is insufficient.
Check your predictions
Wait returns 2 then 3 because it orders by PID. Fork(2) returns -1 because 2 was removed. Fork(1) returns 4: reaping never rewinds the PID counter and a failed Fork consumes no PID. A queue of exit notifications alone would return 3 first unless selection explicitly implements the contract.
Implement process-table, then test a child that exits before its parent and
one that exits afterward. For independent transfer, sketch how adding exit
status would change the Wait result without changing adoption. Later, connect
BLOCKED to the semaphore model and address-space identity to the tagged TLB;
those are separate state machines that share the process identity.
Practice sequence
Use the order below for a guided path, or choose an item to revisit. A pass records a successful attempt; try a fresh example later to check what you can reconstruct.
- Step 1
Process Table
- Step 2
OS Foundations Checkpoint
Processes, privilege, and lifecycle invariants.