Week 7 — Processes, Syscalls, Signals, a Mini-Shell, and System Startup
Overview
This week crosses from the machine into the operating system: how Linux runs programs, and how the system itself comes up. It consolidates the processes/syscalls week with the boot/systemd week because they bracket the same story — the kernel boots, user space starts, and then processes are created, scheduled, and torn down. You will learn the process lifecycle (fork/exec/wait), system calls as the user↔︎kernel boundary, signals, and /proc, then build a mini-shell that ties them together. You will also trace how a system gets from firmware through the kernel to systemd-managed services and journald logs.
This is where the assembly/ABI knowledge (Weeks 4–5) meets the kernel: a syscall is a controlled trap into the kernel with its own register convention. The mini-shell and /proc inspection are direct precursors to the capstone’s syslens.
Readings
- HLW Ch. 8: processes and resource utilization. Extract: the process lifecycle, scheduling, and resource limits.
- HLW Ch. 2: process commands. Extract:
ps,/proc, signals from the shell. - HLW Ch. 5–7: how the kernel boots, how user space starts, and system configuration/logging/journald. Extract: the firmware→kernel→init→services chain.
Key Concepts
The process lifecycle
A process is a running program with its own address space (Week 8), file descriptors, and registers. fork clones the calling process (copy-on-write address space); exec replaces the image with a new program; wait reaps a child’s exit status. This fork/exec/wait pattern is how every program on the system is launched, and building a shell makes it concrete.
System calls — the user/kernel boundary
A syscall is the controlled entry into the kernel: load the syscall number and arguments into registers (an ABI like Week 5’s, but for the kernel — on AArch64, x8 holds the number, args go in x0–x5, and svc #0 traps), and the kernel executes in privileged mode and returns in x0. strace reveals the syscalls a program makes — often the clearest way to understand what software actually does. Syscalls are the only way user code touches files, memory mappings, processes, and devices.
The x86-64 equivalent is the same idea with a different register convention: the syscall number goes in rax, arguments in rdi, rsi, rdx, r10, r8, r9 (note r10, not rcx — the syscall instruction clobbers rcx), and the dedicated syscall instruction traps, returning in rax. Two things differ from ARM64 worth noting: the kernel syscall ABI is not the same as the function-call ABI on either platform (e.g. x86-64 user calls pass the 4th arg in rcx, but syscalls use r10), and syscall numbers differ between ISAs — write is not the same number on ARM64 and x86-64 — which is why a statically-encoded syscall is non-portable and why strace output is ISA-specific.
Signals and /proc
Signals are asynchronous notifications (SIGINT, SIGTERM, SIGCHLD, SIGSEGV); a process installs handlers or takes the default. A shell uses them for job control. /proc is a virtual filesystem exposing kernel state as files — /proc/[pid]/status, maps, fd, stat — readable with ordinary I/O, the basis of every process-inspection tool (and the capstone).
System startup
Power-on → firmware → bootloader → kernel (decompress, init hardware, mount root) → the first user process (PID 1, systemd) → service units brought up per dependency order → journald collecting logs. Understanding units, dependencies, and journalctl is essential for operating any Linux system (and the Jetson in Course 1).
Theory Exercises
- Explain
fork/exec/waitand draw the process tree for a shell running a pipeline. - Describe the AArch64 syscall mechanism (number in
x8, argsx0–x5,svc, return inx0) and the x86-64 one (number inrax, argsrdi/rsi/rdx/r10/r8/r9,syscall); explain why the syscall ABI differs from the function-call ABI (Week 5) on each, and why syscall numbers are not portable across ISAs. - Explain how copy-on-write makes
forkcheap and what happens on the first write after fork. - List the fields of
/proc/[pid]/statyou’d need to compute a process’s CPU usage; explain/proc/[pid]/maps. - Trace the boot chain from firmware to a running service; explain how systemd orders units by dependency.
Implementation
Build a mini-shell (labs/week07-processes-boot): parse a command line, fork/exec, wait, support pipes (|) and redirection (>/<) via dup2, and handle SIGINT/job control. Read process info from /proc. Separately, write a small program that prints another process’s status by parsing /proc/[pid]/. Inspect a service’s status and logs with systemctl/journalctl.
Measurement / Inspection
strace your mini-shell and a real program; compare the syscalls. Verify pipes/redirection work like the system shell. Parse /proc/[pid]/stat to report a process’s state and CPU time and cross-check with ps. Walk a unit’s dependency tree (systemctl list-dependencies) and read its journalctl logs.
Expected baselines: the mini-shell runs pipelines and redirections correctly and handles Ctrl-C via signals; strace shows the expected fork/execve/dup2/wait pattern; /proc parsing matches ps. The boot/service trace shows a coherent dependency-ordered startup.
Connections
The /proc parsing and process model are the core of the Week 10 syslens capstone. The syscall boundary builds on Week 5’s ABI; the address space referenced here is detailed in Week 8. Process/systemd knowledge is used directly to deploy and operate the Jetson runtime in Course 1.
Further Reading
- HLW Ch. 2, 5–8; CS:APP (Bryant & O’Hallaron) Ch. 8 — exceptional control flow and the x86-64 syscall path.
- The Linux Programming Interface (Kerrisk) — processes, signals, and syscalls (reference).
man 2 fork,man 2 execve,man 5 proc,man 1 systemctl.