Skip to main content

Module 4: Systems-Level Programming: Case Studies

These case studies make the kernel boundary visible: syscalls, file descriptors, pipes, signals, mmap, threads, sockets, and tracing.


Case Study 1: strace Shows The Real Program

Scenario: A C program "hangs" while reading input. The source looks fine. strace shows it blocked on read(0, ...).

Source anchor: strace(1) documents the Linux system-call tracer and the syscall-level evidence it exposes.

Module concepts: syscall, blocking I/O, tracing, kernel boundary.

Wrong Approach

Debug only source code.

Better Approach

Trace syscalls:

openat(...)
read(0, ...)
write(1, ...)
close(...)

Tradeoff Table

ChoiceGainCost
Read source onlyFamiliar workflowMisses kernel-boundary behavior
Trace syscalls with straceImmediate blocking and I/O evidenceLinux-specific tool and noisy output
Add ad hoc print debuggingEasy to startCan hide timing or ordering issues

Failure Mode

The program is blamed for a logic bug when it is actually blocked in a kernel call waiting on input or another file descriptor event.

Required Artifact

Run or mock strace output and annotate five syscalls.

Project / Capstone Connection

Use syscall traces as evidence in later debugging reports for shells, servers, and IPC exercises.


Case Study 2: Shell Pipeline With pipe, fork, dup2, exec

Scenario: Implement cat file | grep error. The learner forks two children but forgets to close unused pipe ends, so grep waits forever.

Source anchor: Linux man pages for pipe(2), dup(2), and related process calls define the descriptor semantics that make shell pipelines work.

Module concepts: pipe, fork, dup2, exec, fd inheritance.

Wrong Approach

Only connect the happy-path descriptors.

Better Approach

Close every unused end in parent and children:

child 1:
stdout -> pipe write
close read end

child 2:
stdin -> pipe read
close write end

parent:
close both pipe ends
wait children

Tradeoff Table

ChoiceGainCost
Minimal pipe/dup2 wiringSmall initial codeEasy to leak descriptors and hang readers
Explicit close plan per processCorrect EOF behaviorMore bookkeeping
Helper abstraction for pipeline stagesReusable process setupMore indirection to debug

Failure Mode

One extra write end remains open in the parent or sibling process, so the reader never sees EOF and appears stuck.

Required Artifact

Draw fd tables for parent and both children before and after dup2.

Project / Capstone Connection

Use this descriptor accounting model when building shells, supervisors, or command runners later on.


Case Study 3: Signal Handler Does Too Much

Scenario: A SIGINT handler calls printf, malloc, and complex cleanup. The program occasionally deadlocks or corrupts state.

Source anchor: Linux signal-safety(7) documents which functions are async-signal-safe.

Module concepts: signal, async-signal-safety, reentrancy, cleanup flag.

Wrong Approach

Run normal application logic inside the signal handler.

Better Approach

Set a flag or write to a pipe:

volatile sig_atomic_t stop = 0;

void handler(int sig) {
stop = 1;
}

Tradeoff Table

ChoiceGainCost
Full cleanup in handlerSeems directReentrancy and deadlock risk
Set flag and defer cleanupSafe control transferMain loop must cooperate
Self-pipe/eventfd patternIntegrates with event loopExtra fd setup

Failure Mode

The handler interrupts code already inside libc or allocator internals, then reenters unsafe functions and deadlocks or corrupts process state.

Required Artifact

Write a signal-safety review: handler actions, safe functions, deferred cleanup.

Project / Capstone Connection

Carry this pattern into daemons, shells, and service processes that need clean interrupt handling.


Case Study 4: mmap File Update Surprise

Scenario: A file is memory-mapped and modified. The learner assumes every store is immediately durable and visible in all desired ways.

Source anchor: Linux mmap(2) and msync(2) document mapping and synchronization behavior.

Module concepts: mmap, shared/private mapping, page cache, msync.

Wrong Approach

"Memory assignment equals disk write."

Better Approach

Choose mapping and sync semantics:

MAP_SHARED:
changes can propagate to file

MAP_PRIVATE:
copy-on-write private changes

durability:
msync/fsync as required

Tradeoff Table

ChoiceGainCost
Assume stores are durableSimplifies mental modelIncorrect crash and visibility assumptions
MAP_SHARED + explicit sync planShared-file semantics are clearMust handle flushing and ordering
MAP_PRIVATE for local transformsIsolates mutationsChanges do not update the file

Failure Mode

The program appears to update the file in memory, but after a crash or another reader's observation the expected durability or sharing semantics are not there.

Required Artifact

Write an mmap behavior table for MAP_SHARED vs MAP_PRIVATE and crash points.

Project / Capstone Connection

Use this decision model in file-backed indexes, log viewers, and memory-mapped tooling later in the program.


Case Study 5: Thread Lifecycle Leak

Scenario: A server creates pthreads for background work but never joins or detaches them. Resource usage grows.

Source anchor: POSIX pthread lifecycle docs explain joinable and detached threads. See pthread_create(3) and pthread_join(3).

Module concepts: pthread_create, join, detach, lifecycle.

Wrong Approach

"When the thread function returns, everything is cleaned up."

Better Approach

Decide lifecycle:

joinable:
parent must join and collect result

detached:
no join, resources released automatically

Tradeoff Table

ChoiceGainCost
Leave lifecycle implicitLess code at creation siteResource leaks and unclear shutdown
Joinable threads with explicit joinCollect results and errorsRequires shutdown coordination
Detached fire-and-forget threadsSimpler cleanup pathHarder observability and control

Failure Mode

Finished threads accumulate unreclaimed resources, and long-running servers slowly exhaust limits or become harder to shut down cleanly.

Required Artifact

Write a thread lifecycle plan with join/detach decision and shutdown path.

Project / Capstone Connection

Apply this lifecycle policy to worker pools, background tasks, and concurrency features in later systems projects.


Source Map

SourceUse it for
strace(1)syscall tracing
pipe(2) and dup(2)shell pipeline mechanics
signal-safety(7)safe signal handlers
mmap(2) and msync(2)memory-mapped files
pthread_create(3)thread lifecycle

Completion Standard

  • At least three artifacts are completed.
  • At least one artifact includes fd tables.
  • At least one artifact includes syscall trace evidence.