Learn operating systems: the best books to read in order
This curriculum takes an intermediate learner from solid OS conceptual foundations through hands-on implementation details and finally into advanced internals and real-world systems design. Each stage builds directly on the vocabulary and mental models of the previous one, moving from "how OSes work" to "how to build and reason about them at a deep level."
Foundations & Core Concepts
BeginnerBuild a clear mental model of the core OS abstractions: processes, threads, scheduling, memory management, and file systems — enough to reason about any OS confidently.
▸ Study plan for this stage
Pace: 8–10 weeks, ~40–50 pages/day (Chapters 1–4 of Modern Operating Systems, approximately 400–500 pages total)
- Process abstraction: what a process is, process states, process control blocks (PCBs), and context switching
- Thread model: threads vs. processes, thread scheduling, synchronization primitives (mutexes, semaphores, monitors), and race conditions
- CPU scheduling algorithms: FCFS, SJF, round-robin, priority scheduling, and how to evaluate scheduling trade-offs
- Memory management: address spaces, virtual memory, paging, segmentation, and page replacement algorithms (LRU, FIFO, etc.)
- File systems: inodes, directory structures, file allocation strategies (contiguous, linked, indexed), and reliability mechanisms
- Concurrency and deadlock: mutual exclusion, deadlock conditions, prevention/avoidance/detection strategies
- I/O and device management: interrupt handling, DMA, buffering, and device driver abstractions
- OS design trade-offs: performance vs. simplicity, fairness vs. efficiency, and security vs. usability
- What is a process, and how does it differ from a program? Describe the process state diagram and when transitions occur.
- Explain the difference between threads and processes. What are the advantages and disadvantages of multithreading?
- Compare and contrast at least three CPU scheduling algorithms (e.g., FCFS, SJF, round-robin). Which would you choose for an interactive system and why?
- How does virtual memory work? Explain the roles of paging, page tables, and the TLB in translating virtual addresses to physical addresses.
- What is a page replacement algorithm? Describe LRU and FIFO, and explain why LRU generally performs better.
- Describe the structure of a file system. What is an inode, and how does indexed allocation differ from linked allocation?
- What are the four conditions necessary for deadlock? Name at least two strategies to prevent or avoid deadlock.
- What is a race condition, and how do mutexes and semaphores prevent them? Give a concrete example.
- Implement a simple process scheduler in a language of your choice (C, Python, or Java). Simulate FCFS, SJF, and round-robin scheduling on a set of processes with varying burst times. Compare average waiting time and turnaround time.
- Write a multi-threaded program that demonstrates a race condition (e.g., multiple threads incrementing a shared counter without synchronization), then fix it using a mutex or semaphore. Measure the difference in correctness.
- Simulate a paging system: implement a virtual-to-physical address translator with a page table and TLB. Test different page replacement algorithms (LRU, FIFO) on a sequence of memory accesses and compare page fault rates.
- Design and implement a simple file system in memory (or on disk) with inodes, a directory structure, and at least one file allocation strategy. Support basic operations: create, read, write, delete, and list files.
- Create a deadlock scenario (e.g., two threads acquiring locks in different orders) and implement a solution using either deadlock prevention (lock ordering) or avoidance (banker's algorithm for a simplified case).
- Write a producer-consumer program using semaphores or condition variables. Experiment with different buffer sizes and producer/consumer speeds to understand synchronization trade-offs.
Next up: This stage establishes the foundational mental models (processes, threads, memory, files) that are prerequisites for understanding advanced topics like distributed systems, security, and performance optimization in subsequent stages.

A comprehensive and authoritative survey of OS concepts including processes, threads, memory, file systems, and I/O. Read after OSTEP to reinforce and broaden every concept with Tanenbaum's rigorous treatment.
Concurrency & Systems Programming
IntermediateMaster concurrency primitives — mutexes, semaphores, condition variables, and lock-free structures — and understand how to write correct, performant multi-threaded systems code.
▸ Study plan for this stage
Pace: 8–10 weeks, ~40–50 pages/day (mix of dense theory and practical code examples; expect slower pace for Herlihy due to mathematical rigor)
- Memory consistency models and happens-before relationships — understanding when writes become visible across threads
- Mutual exclusion via locks and mutexes — implementing and reasoning about critical sections without race conditions
- Semaphores and condition variables — coordinating between threads and signaling state changes
- Lock-free and wait-free algorithms — designing concurrent data structures without explicit locks using atomic operations and CAS
- POSIX threading API — thread creation, synchronization primitives, and practical patterns for real systems
- Deadlock detection and prevention — recognizing circular wait conditions and designing lock hierarchies
- Performance and scalability — contention analysis, lock granularity, and measuring concurrent system behavior
- Correctness verification — reasoning about invariants, linearizability, and testing multi-threaded code
- What is the difference between sequential consistency and weaker memory models, and why do modern processors not guarantee sequential consistency?
- How do mutexes prevent race conditions, and what is the cost of lock contention on system performance?
- Explain the difference between a semaphore and a condition variable — when would you use each?
- What makes a lock-free algorithm correct, and how do compare-and-swap (CAS) operations enable non-blocking synchronization?
- Walk through the POSIX API for creating a thread, protecting shared data with a mutex, and signaling a condition variable — what are the key function calls and error handling patterns?
- How can deadlock occur in a multi-threaded program, and what strategies prevent it?
- What is linearizability, and how do you verify that a concurrent data structure is linearizable?
- How do you measure and optimize lock contention in a real multi-threaded system?
- Implement a thread-safe bounded queue using a mutex and condition variables (Herlihy Ch. 4–5, Butenhof Ch. 3–4); test with multiple producers and consumers
- Build a simple lock-free stack using CAS operations (Herlihy Ch. 11); compare performance against a mutex-protected stack under varying contention
- Write a POSIX multi-threaded program that spawns N threads, each incrementing a shared counter with proper synchronization; measure contention and identify bottlenecks
- Implement a reader-writer lock using mutexes and condition variables (Butenhof Ch. 6); benchmark read-heavy vs. write-heavy workloads
- Design and implement a thread-safe hash table with fine-grained locking (bucket-level locks); profile and optimize for scalability
- Create a deadlock scenario (e.g., two threads acquiring locks in opposite order), then fix it using lock ordering; verify the fix with stress testing
- Implement a simple thread pool with a work queue and condition variables (Butenhof Ch. 5); submit tasks and measure throughput
- Write a concurrent producer-consumer system using semaphores (Herlihy Ch. 5); verify correctness under edge cases (empty/full buffer)
Next up: This stage equips you with the theoretical foundations and practical tools to reason about concurrent systems; the next stage will apply these primitives to building real distributed systems, where you'll face additional challenges like network failures, partial ordering, and consensus.

The definitive deep-dive into concurrent algorithms and synchronization theory. It gives the formal underpinning for everything hinted at in OSTEP's concurrency section.

The canonical practical guide to POSIX threads — read after Herlihy to ground the theory in the actual API that real Unix/Linux systems expose.
OS Internals & Implementation
IntermediateUnderstand how a real operating system kernel is structured and implemented, including memory management internals, scheduling algorithms, and system calls at the source-code level.
▸ Study plan for this stage
Pace: 8–10 weeks, ~40–50 pages/day. Start with "Linux Kernel Development" (Weeks 1–4, ~25 pages/day for foundational concepts), then transition to "Understanding The Linux Kernel" (Weeks 5–10, ~50 pages/day for deeper implementation details). Allocate 1–2 days per week for hands-on exercises and kernel ex
- Kernel architecture and subsystems: process management, memory management, filesystem, and I/O subsystems as integrated components
- Process and thread management: task structures, scheduling algorithms (CFS, real-time), context switching, and process lifecycle
- Memory management internals: paging, segmentation, virtual address translation, page tables, and the buddy allocator
- Interrupt handling and exception processing: interrupt handlers, softirqs, tasklets, and how the kernel responds to hardware events
- System calls: the user-kernel boundary, how syscalls transition from user space to kernel space, and common syscall implementations
- Synchronization primitives: spinlocks, semaphores, mutexes, and how the kernel protects shared data structures
- Virtual filesystem (VFS) abstraction: how different filesystems are plugged into a unified interface
- Module loading and kernel extensions: how kernel modules are compiled, loaded, and interact with the running kernel
- Explain the role of the task_struct in Linux and how it represents a process in the kernel. What key information does it store?
- Describe the Completely Fair Scheduler (CFS) algorithm: how does it track process fairness and make scheduling decisions?
- Walk through the steps of a system call from user space to kernel space, including privilege transitions and return to user mode.
- How does Linux implement virtual memory using page tables and the Memory Management Unit (MMU)? What is the role of the buddy allocator?
- Explain interrupt handling in Linux: what is the difference between hardware interrupts, softirqs, and tasklets, and when is each used?
- What is the Virtual Filesystem (VFS) abstraction, and how does it allow Linux to support multiple filesystem types transparently?
- Read and annotate the task_struct definition in the Linux kernel source (include/linux/sched.h) and trace how a process is created via fork() and exec().
- Build a custom kernel module that uses printk() to log process scheduling events; observe CFS scheduling decisions in real time via dmesg.
- Write a simple system call tracer using strace to intercept syscalls, then examine the corresponding kernel code in arch/x86/entry/syscalls/ to understand the transition.
- Modify a kernel module to allocate and deallocate memory using kmalloc() and kfree(); inspect the buddy allocator behavior by reading /proc/buddyinfo before and after.
- Create a kernel module that registers an interrupt handler and observe how it responds to hardware interrupts; correlate with /proc/interrupts.
- Write a simple filesystem module or study the ext4 filesystem code to understand how the VFS layer abstracts filesystem operations (read, write, open, close).
Next up: This stage provides the foundational knowledge of kernel internals needed to understand advanced topics such as performance optimization, kernel debugging, security mechanisms (SELinux, capabilities), and specialized subsystems (networking stack, device drivers).

A highly readable tour of the Linux kernel's internals — scheduling, memory, VFS, and more. It bridges the gap between OS theory and a production kernel millions of systems run today.

Goes deeper than Love's book into kernel data structures and algorithms. Read second in this stage to fill in the lower-level details after Love provides the high-level map.
Advanced Topics: Storage, Distributed Systems & Design
ExpertReason deeply about file systems, storage stacks, distributed OS concerns, and the design trade-offs that shaped historical and modern operating systems.
▸ Study plan for this stage
Pace: 12–14 weeks, ~40–50 pages/day (FreeBSD book: 6–7 weeks; Tanenbaum: 6–7 weeks)
- File system architecture and design trade-offs: inodes, block allocation, journaling, and performance optimization strategies
- Storage stack layers: disk scheduling, buffer caches, page replacement algorithms, and I/O subsystem design
- Virtual memory and memory management in practice: paging, swapping, and kernel memory allocation patterns
- Distributed OS concerns: clock synchronization, consistency models, distributed deadlock, and network communication protocols
- Process and thread scheduling in multi-processor and distributed contexts: load balancing and fairness
- Concurrency control mechanisms: locks, semaphores, condition variables, and their real-world implementation pitfalls
- System design trade-offs: simplicity vs. performance, consistency vs. availability, and centralization vs. distribution
- Historical evolution of OS design decisions and how constraints shaped modern architectures
- How does the FreeBSD file system (UFS/UFS2) balance inode management, block allocation, and performance, and what design choices differ from other file systems?
- Explain the role of the buffer cache in the storage stack and how it interacts with page replacement policies to optimize I/O performance.
- What are the key challenges in implementing virtual memory across multiple processors, and how do page replacement algorithms like LRU address them?
- Describe the trade-offs between strong consistency and availability in distributed systems, and how clock synchronization affects distributed decision-making.
- How do lock contention and deadlock scenarios arise in multi-threaded kernels, and what strategies (e.g., lock-free data structures, hierarchical locking) mitigate them?
- Compare centralized vs. distributed approaches to resource allocation and scheduling in operating systems, citing specific examples from the books.
- What design constraints (hardware limitations, performance requirements, fault tolerance) shaped the evolution of OS architectures, and how do they persist in modern systems?
- Trace through FreeBSD's UFS inode and block allocation algorithms: diagram how a file write operation navigates the cylinder groups, block pointers, and indirect blocks.
- Implement a simplified buffer cache simulator in C/Python that tracks page eviction under different replacement policies (FIFO, LRU, Clock) and measure hit rates on realistic I/O traces.
- Analyze FreeBSD's soft updates mechanism: write a detailed explanation of how it ensures file system consistency without full journaling, then compare its trade-offs to modern journaling approaches.
- Design a distributed clock synchronization algorithm (e.g., based on Tanenbaum's coverage): implement a prototype that handles Byzantine failures and measure convergence time.
- Conduct a hands-on experiment: modify a kernel module or use strace/dtrace to observe lock contention in a multi-threaded workload; identify bottlenecks and propose lock-free alternatives.
- Create a comparative analysis matrix of file system designs (UFS, ext4, BTRFS, ZFS): evaluate each across consistency guarantees, crash recovery, performance, and scalability dimensions.
Next up: This stage equips you with deep understanding of how storage, memory, and distributed coordination work in real systems, providing the foundation to tackle specialized topics like cloud OS architectures, containerization, and modern microkernel designs that build upon or challenge these classical principles.

A masterclass in OS design decisions — covering the BSD kernel's process model, virtual memory, and file systems with the perspective of the people who built it.

Pairs OS design principles with the full source of the MINIX microkernel, giving the learner a complete, buildable OS to study. Ideal capstone for someone who has absorbed all prior stages.
Discussion
Keep reading
Paths that share books, cover the same subject, or open a related topic.