interviewpath
  • 0day streak
  • 10total XP
  • Level 1
0/7

Unit 3 · OS & concurrency · Lesson 1 of 11

Processes, threads, system calls and scheduling

Processes, threads, system calls and the scheduler are the vocabulary for explaining where time goes and what is isolated from what. Interviews use them to check that you can trace a request from user code into the kernel and back, and reason about the cost of switching between tasks.
About 5 hFocus mode

Step 1: Learn the ideas

  • Process abstraction: address space, file descriptors, credentials
  • Threads versus processes; Linux tasks and clone flags
  • User mode, kernel mode and limited direct execution
  • Traps: system calls, exceptions and interrupts
  • Process API: fork, exec, wait, exit and zombies
  • Context switches: saved state, direct and indirect costs
  • Scheduling metrics and policies: FIFO, SJF, STCF, round robin, MLFQ
  • Proportional share and Linux fair scheduling (CFS, EEVDF)
  • Multiprocessor scheduling, affinity and load balancing
  • Kernel threads versus user-level threads and coroutines

Why it matters

Most systems questions eventually become "what is the CPU doing, on whose behalf, and what does switching cost?" Explaining why a service with thousands of threads slows down, why a container with a CPU limit shows latency spikes, or why an async runtime stalls behind one slow call all rests on a few mechanisms: processes and threads, the user/kernel boundary and the scheduler. Infrastructure, SRE and low-level interviews expect you to trace these paths precisely; backend interviews use them to check that your performance intuitions have a mechanical basis.

Core ideas

Process versus thread. A process bundles an address space, open file descriptors, credentials and signal handling with one or more threads. A thread is an execution context: registers, program counter, stack pointer and thread-local storage. Threads of one process share memory, so communication is cheap and isolation is absent: a wild pointer in one thread corrupts all of them. On Linux both are tasks created by clone(), differing only in what they share.

Limited direct execution. User code runs directly on the CPU in user mode, where privileged instructions and device access are forbidden. The kernel regains control only through a trap: a system call (deliberate, such as syscall on x86-64 or ecall on RISC-V), an exception (page fault, illegal instruction) or an interrupt (a device or the timer). The hardware raises the privilege level and jumps to a handler the kernel registered at boot; the kernel saves user registers, validates arguments (user pointers are untrusted), does the work and returns with an instruction that drops privilege. The timer interrupt is what makes preemption possible.

A blocking call, end to end. read() on a socket with no data traps into the kernel, finds the receive queue empty, puts the thread on a wait queue and calls the scheduler, which runs another thread. When a packet arrives, the interrupt path queues the data and marks the thread runnable. After some run-queue delay the scheduler resumes it inside the kernel, which copies the data out and returns to user mode.

Context switches. A thread switch saves and restores general registers, stack pointer, program counter and, when used, floating-point and vector state. Switching to another process also changes the page-table root, so cached translations are useless unless the TLB tags entries with address-space IDs. The direct cost is small; the indirect cost of cold caches, TLB misses and lost branch history is often larger. A system call is not a context switch: it is a mode switch within the same thread, and the scheduler is involved only if the call blocks. Some calls, such as reading the clock on Linux, avoid the trap entirely through the vDSO.

Scheduling. Policies trade turnaround time (batch work: SJF, STCF) against response time (interactive work: round robin). Shorter time slices improve responsiveness but add switching overhead. MLFQ approximates shortest-job-first without knowing job lengths by watching whether a task uses its whole slice, and needs periodic priority boosts to prevent starvation. Proportional-share schedulers track the CPU each task has received: Linux's fair class used CFS (virtual runtime in a red-black tree) and began moving to EEVDF in kernel 6.6. Multiprocessor schedulers keep per-CPU run queues for cache affinity and migrate tasks to balance load.

Creating processes. fork() duplicates the caller cheaply thanks to copy-on-write; exec() replaces the program image; wait() collects the exit status, and until then the dead child stays a zombie. Separating fork from exec lets a shell rewire file descriptors in the child before the new program starts.

Common misconceptions

  • "A system call is a context switch." It changes privilege, not the running thread; only blocking or preemption invokes the scheduler.
  • "Threads are always cheaper than processes." Creation and switching are cheaper, but shared state brings lock and allocator contention and no fault isolation; process-per-worker designs trade memory for robustness.
  • "More threads means more throughput." For CPU-bound work, threads beyond the core count add switches and cache churn; for blocking I/O they help only until another resource saturates.
  • "fork() copies the whole address space." It copies page tables and marks pages copy-on-write; data is copied on first write. A large parent still pays for page-table copying and later write faults.
  • "The kernel is a separate process serving system calls." Kernel code runs in the context of the calling thread, of an interrupt or of a kernel thread; there is no server to message.
  • "A higher priority guarantees low latency." Fair schedulers give proportional shares, not deadlines; latency still depends on how many runnable tasks compete.

How to approach it

Practice telling the blocking-read story aloud in under two minutes, then deepen one level at a time: what the hardware saves, what the kernel saves, where the thread sleeps. Measure instead of quoting numbers: time a null system call and a pipe ping-pong between two processes pinned to one CPU, then compare with two threads. On Linux, /proc/<pid>/status shows voluntary and involuntary context switches: many involuntary switches suggest CPU contention, many voluntary ones suggest blocking. Graduate interviews usually stop at processes versus threads and fork/exec; mid-level ones probe the system-call path and scheduling tradeoffs; senior ones connect scheduler behavior to tail latency and container CPU limits.

Suggested order

  1. 1Read OSTEP Ch. 4 (The Abstraction: The Process) and Ch. 5 (Interlude: Process API) for process states and fork, exec and wait.
  2. 2Read OSTEP Ch. 6 (Mechanism: Limited Direct Execution) closely: restricted operations, traps and switching between processes.
  3. 3Read the xv6 book Ch. 4 (Traps and system calls) and Ch. 8 (Scheduling) to see a real trap path and a context-switch routine in code.
  4. 4Read OSTEP Ch. 7, 8 and 10 for scheduling metrics, MLFQ and multiprocessor scheduling; skim Ch. 9 (Scheduling: Proportional Share) and sched(7) for how Linux exposes policies.
  5. 5Do the OSTEP Ch. 6 measurement homework: time a null system call and a pinned pipe ping-pong, and write down your sources of error.
  6. 6Do the 6.1810 system calls lab, then the Multithreading lab to write a context switch yourself.
  7. 7For more depth, do the traps lab and the OSTEP shell project.

Step 2: Check off what you can do

Tap each one you can genuinely do or explain. Each earns 10 XP.

Step 3: Go deeper

  • Operating Systems: Three Easy PiecesStart here

    University of Wisconsin–Madison (free online book)

    Section: Ch. 6: Mechanism: Limited Direct Execution

    Primary explanation of user and kernel mode, traps, the timer interrupt and context switching.

    Open(opens in a new tab)Link responded, 5 Oct 2026
  • Operating Systems: Three Easy Pieces

    University of Wisconsin–Madison (free online book)

    Section: Ch. 8: Scheduling: The Multi-Level Feedback Queue

    How a scheduler balances turnaround and response time without knowing job lengths; read Ch. 7 first.

    Open(opens in a new tab)Link responded, 5 Oct 2026
  • MIT 6.1810 Operating System Engineering (xv6)Start here

    MIT PDOS

    Section: xv6 book, Ch. 4: Traps and system calls

    A complete, readable trap and system-call path in a real kernel, register by register.

    Open(opens in a new tab)Link responded, 5 Oct 2026
  • MIT 6.1810 Operating System Engineering (xv6)

    MIT PDOS

    Section: xv6 book, Ch. 8: Scheduling

    Shows exactly which registers a context switch saves and how the scheduler loop hands the CPU between processes.

    Open(opens in a new tab)Link responded, 5 Oct 2026
  • The Linux man-pages project (man7.org)

    man7.org (Linux man-pages project)

    Section: sched(7)

    How Linux exposes scheduling policies, priorities, nice values and CPU affinity to applications.

    Open(opens in a new tab)Link responded, 5 Oct 2026

Step 4: Practice

Start with the measurement homework on Linux (a VM is fine; macOS numbers describe a different kernel). Pin both processes to one CPU with taskset or sched_setaffinity, run many iterations and report a distribution rather than one number, then repeat with two threads and compare. Next do the system calls lab and the Multithreading lab, writing down for each what state crosses the user/kernel boundary. The scheduling simulators, traps lab and shell project are for depth; lab-xv6 is the umbrella entry for the whole xv6 lab sequence.

Record attempts on each problem’s page (+15 XP, +10 more when solved on your own).

Step 5: Test yourself

Answer each one out loud or on paper before you finish the lesson.

  1. Question 1Why can a user program not simply disable interrupts to keep the CPU?
  2. Question 2What happens to a thread between the arrival of its packet and the return of read()?
  3. Question 3Why is a context switch between processes more expensive than one between threads of the same process?
  4. Question 4What does a high rate of involuntary context switches tell you, and what would you check next?
  5. Question 5How does MLFQ keep long-running jobs from starving, and how could a program game it?
  6. Question 6Why can Linux read the clock without entering the kernel?
  7. Question 7When would you choose processes over threads for a worker pool?

You’re done when you can

  • Trace a blocking read() from the system-call instruction to the return to user space in under three minutes, without notes.
  • State what a thread switch saves and what a process switch additionally changes, and name two indirect costs.
  • Report your own measured null-system-call and context-switch costs together with the method and its sources of error.
  • Compute average turnaround and response time for a small job mix under FIFO, SJF and round robin without mistakes.
  • Explain the zombie state and why a shell forks before it execs.

Finish the lesson

How confident do you feel?

Lesson complete!

+50 XP

Reviews will come up on the Practice tab so it sticks.

Unlocks next: Virtual memory and memory management, I/O models, readiness and event loops, Locks, condition variables, atomics and memory ordering, Throughput, latency, Little's law and Amdahl's law, Containers, VMs, namespaces and cgroups

Your notes and study time

Log study time