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.