Unit 1.4 · about 4 h
233 / 324File descriptors, pipes, signals and process lifecycle
Assume Programming's shell-processes-environment unit, including signal exit conventions. This unit exposes descriptor references, pipe endpoint counts and child status records that make shell pipelines and process supervisors work.
- implement
You can now
- Implement a parent-child pipe with deliberate redirection, closure and reaping on each path.
- Predict shared open-file offsets and close-on-exec behavior across dup, fork and exec.
- Diagnose a retained pipe writer or zombie from kernel state rather than from a timeout alone.
- Distinguish signal notification, delivery, termination and status collection.
Covers
- File descriptors, open-file state, pipes and redirection
- Signals, exit status, zombies, orphans and lifecycle ownership
Study, in this order
4 steps
- Descriptor entries versus open descriptionsAlgoMaster Operating Systems - selected observation route
The Three-Level Model through Descriptor Flags vs. File Status Flags; Observing Descriptors Through
/proc; Demonstrating Shared and Independent Offsets - Signals and child ownershipAlgoMaster Operating Systems - selected observation route
The Signal Lifecycle; Dispositions: Default, Ignore, or Catch; Why Handlers Must Be Tiny; Interrupted System Calls and
EINTR; Signal Masks and Pending Signals;SIGCHLD: Notification, Not ReapingDepth · Then read Zombies and Orphans: What Exactly Is a Zombie?, Reaping Without Blocking, What Is an Orphan? and Subreapers and Process Supervisors. Leave multithreaded signal coordination to concurrency.
- Wait status and child statesLinux proc and strace references
DESCRIPTION:
wait()andwaitpid(), status macros,waitid()andWNOWAIT; NOTES on zombies - Offsets shared through fork and dupOperating Systems: Three Easy Pieces - selected foundations
Chapter 39, Sections 39.4 to 39.6, especially Shared File Table Entries:
fork()Anddup()
Focus on
- A descriptor entry holds its own close-on-exec flag; the open file description holds the shared offset and status flags. A repeated open creates independent open state.
- After
dup2, close unused pipe endpoints in both processes.EOFrequires an empty pipe and no remaining write references; parent exit is not the definition ofEOF. - Signals have dispositions and per-thread masks.
SIGCHLDcan coalesce; drain waitable children rather than counting notifications. - A zombie has already released its user memory and descriptors. An orphan changes parent; Linux can adopt it through a subreaper rather than the host PID 1.
Reproduce closed-book
os.pipe pairs. Fork one child, dup2 its request-read end onto fd 0 and response-write end onto fd 1, close all original endpoints and execl /bin/cat. In the parent close the child-only ends, write b'abc\n' with a partial-write loop, close the request writer, read the response until EOF and waitpid the child. Assert exactly b'abc\n' and normal exit 0. Run strace -f -e trace=process,pipe,pipe2,dup2,read,write,close -- python3 -I pipes.py. In a separate empty pipe, set the reader nonblocking: retaining the writer gives BlockingIOError, closing the last writer gives b''. Finally fork a child that sets SIGTERM to SIG_DFL, announces readiness through a pipe and waits; signal it only after readiness. Use waitid with WEXITED|WNOWAIT to observe /proc/<pid>/status state Z, then waitpid and verify WIFSIGNALED with WTERMSIG==SIGTERM. Use no sleep as an ordering guarantee.Traps
- Keeping a spare write descriptor open and waiting for EOF forever. Inheritance and duplication both retain references.
- Assuming Python's newly created descriptors survive exec. They are non-inheritable by default; deliberate
dup2onto standard I/O is inheritable unless requested otherwise. - Calling arbitrary logging or allocation from a native signal handler, or assuming shell status \(128+\text{signal}\) is the raw wait status.
Practice
The section mini-project covers this: a supervised pipe worker with a descriptor ownership diagram, deliberate leaked-writer regression test, signal termination, zombie observation, and guaranteed closure and reaping on success and failure.
Self-test
-
A child reads through an inherited regular-file descriptor. Does the parent's offset advance?
Yes, if both entries still refer to the same inherited open file description. Separate open calls would have independent offsets. -
The producer exited, but an unrelated child inherited its pipe writer. Will an empty pipe return EOF?
No. A write reference still exists. A blocking reader waits and a nonblocking reader reportsEAGAINuntil the last writer closes. -
Why does one
SIGCHLDhandler invocation not imply one terminated child?Standard signals can coalesce andSIGCHLDcan report other child state changes. Reap in a loop withwaitpid(-1, ..., WNOHANG), handling the documented return cases. -
Can
SIGKILLremove a zombie's retained status record?No. It is already terminated. Its parent or adopter must collect the record; signal delivery is not reaping.
Completion criterion
Stop when
The pipe round trip passes, your nonblocking leak test distinguishes EAGAIN from EOF, and your signal test observes then reaps the zombie with a correctly decoded wait status.
Leads to
- 1.9 Namespaces, cgroups and container boundaries Carry lifecycle ownership into a PID namespace.
- 3.4 Sockets, partial reads and writes, and message framing Extend descriptor ownership and partial-I/O handling to byte-stream sockets.
Comes after
- 1.3 Processes, system calls, fork, exec and schedulingGive the child deliberate I/O and termination ownership.
Resources for this unit
- Operating Systems: Three Easy Pieces - selected foundations Read Chapters 4-7, 13-15, 18-21, 36, 39-40, 42 and 45. Work from process state to address translation, devices, files, journaling and integrity. For every chapter, draw the owned state and one failure boundary instead of collecting summaries.
- AlgoMaster Operating Systems - selected observation route After OSTEP, use the matching lessons as a second explanation and recall check: fork, exec, wait, and exit; Zombies and Orphans; Signals; Context Switching; The Process Address Space; Paging; The TLB: Hits, Misses, and Invalidation; Page Faults; Copy-on-Write; mmap and Memory-Mapped Files; How malloc Works; VSZ, RSS, PSS, and What They Mean; File Descriptors; The Page Cache and Write-Back; Durability and fsync; Crash Consistency; Linux Namespaces; Control Groups; PID 1 and Signal Handling; Container Resource Failures; and the Investigating lessons. Treat quizzes as recall checks and keep your own traces as evidence.
- Linux proc and strace references Use proc(5), getrusage(2), mmap(2), fsync(2), rename(2), wait(2) and signal(7) while tracing a parent-child pipe, page faults, file publication and a resource-limit failure. Record exact commands and raw observations.
Also in this section
- MIT 6.1810 - selected xv6 process and memory labs Use Fall 2025 Lectures 1, 3-6, 8 and 10-11. Complete the util lab, one syscall task, and the page-table inspection plus ugetpid task from pgtbl. Add cow only if copy-on-write remains unclear. Keep all work in your own course checkout and stop before the full xv6 sequence.
- OSTEP homework - process, paging, disk and integrity simulators Solve process-run.py, paging-linear-translate.py, paging-policy.py, disk.py, fsck.py and checksum.py for at least two seeds each before using the answer flag. Then reproduce one prediction using strace, /proc or a small local program.
- Nand2Tetris - Projects 1 and 4 only Use Project 1 for Boolean logic and Project 4 for machine-language execution only if the binary or instruction-level entry check fails. Do not take the full course as a second systems curriculum.
- Algorithmica - Algorithms for Modern Hardware Use the Instruction-Level Parallelism, SIMD Parallelism and RAM & CPU Caches chapters for measured pipeline, branch, vectorization, bandwidth, latency and cache-line effects. The figures are the author's Zen 2 measurements at a fixed 2 GHz: predict and measure your own.
- MIT 6.S894 Accelerated Computing - Throughput Processors Use Lecture 2 for the processor model behind this section: superscalar issue, out-of-order execution, speculation and SIMD's need for coherent control. The labs run on the course's remote machines and target AVX-512 and NVIDIA GPUs, so they belong to the GPU track.
- Auto-Vectorization in LLVM Use The Loop Vectorizer Usage and Diagnostics sections for the Clang remarks the pipelines unit asks for; the Features list is optional depth.
- AlgoMaster: hardware and container storage companions Use Memory Ordering, Barriers, and False Sharing (coherence and false-sharing headings only); Huge Pages, NUMA, and ASLR (NUMA headings only); Storage Hardware; RAID Fundamentals (comparison and backup boundaries); and Container File Systems. These fill hardware and image-layer gaps outside the pool's selected OS revision lessons.