|Linux Kernel Development Third Edition|
|summary||A thorough guide to the design and implementation of the 2.6 Linux kernel tailored for developers.|
From there on out, Love divides the kernel up and proceeds to ease the reader into each realm that he covers. You won't get full coverage of the kernel but he delivers the most important chunks that he can in 400 pages and makes good on keeping the material in focus. Every chapter seems to follow a pattern of a few pages of generic remedial kernel design talk then a few pages of Linux specific historical approaches to said design followed by the meat and potatoes in 10 to 40 pages depending on how much code is cited. A short paragraph or two tidies up each chapter to segue into the next one. I failed to find any weaknesses in Love's writing. While he struggles to keep the reader engaged and entertained at times, there's simply too much explaining to be done for him to waste pages on wit and banter. If any of that is to be found, it's sprinkled around the intros and outros surrounding some genuinely solid technical writing. To keep this review relatively concise, I'll only fully cover the content in the first half of the book.
Chapters three and four focus on processes and how the kernel manages them. Love glosses over some basic concepts (i.e. the state transition diagram of a process) about process creation but also includes small code snippets ranging from function signatures to iterative algorithms that do the heavy lifting when initializing and maintaining processes and their hierarchical structures. If you've ever wondered exactly what happens during a fork or how zombie processes are managed, it's all answered here in English. The book moves on to Linux's relatively new completely fair scheduler (CFS) and also describes how to switch out schedulers (the older schedulers appear to remain unused in the code if you want to swap them back in). Love concentrates on kernel/sched.c and kernel/sched_fair.c as he explains the code and flags that control waking, sleeping, preemption and context switching. For me this was one of the most interesting parts of the book where the reader gets to see timeslice and 'nice' factors at work in the actual code. The runnable processes are managed in a red-black tree and Love takes care to show how these are cached and used in the code. As I read these chapters, I couldn't help but wonder how companies like Google tailor the Linux kernel to their needs inside their massive server farms — the care to 'waste not' is already so evident in Love's explanations that tweaking through settings and flags or even rewriting seems like a hard route to save cycles.
Chapter five is a brief how-to about system calls in Linux. This chapter details how to create a system call and how to register it, but also gives background on how the kernel handles system calls and explains concisely how Linux handles system calls in regards to security and stability. Most importantly this chapter explains why you should rarely — if ever — resort to system calls (if it's not accepted as part of the kernel, you face future conflicts with the syscall number).
Chapter six was a bit of a surprise to me but outlines in depth four data structures (linked lists, queues, maps and red black trees). If you code only for Linux and you are rolling your own of any of these data structures then this chapter is for you. It's a bit of a flashback for me but important to note so that one does not duplicate these efforts inside the already expansive code in the kernel. Indeed, this topic is an addition to the book that was not present in the second edition.
Chapter seven is a good illustration of Love's ability to ease the reader into the kernel. He starts off giving a high level introduction to hardware interrupts and their superiority to hardware polling. Form there he explains interrupt handlers and finally the top half (handler) versus the bottom half (deferred workload). This four page intro to the chapter helps beginners like myself prepare for the coming sections on writing a hardware interrupt handler, registering it, unregistering it, disabling all or some handlers, explaining /proc/interrupts and checking contexts. This chapter lays the foundation for following chapters and shows the basics of interrupt handlers. Chapter eight, of course, covers exactly what was left unexplained in the prior chapter — the bottom half. And again the chapter eases into it with an explanation detailing bottom halves. Love gives just the right amount of background (a few paragraphs) to help the reader understand why we are about to discuss softirqs (statically defined bottom halves), tasklets (dynamically defined bottom halves built on top of softirqs) and work queues at great length.
Chapters nine and ten begin with topics the reader might already have some familiarity with: race conditions. Nine begins with the standard topic of the kinds of problems race conditions pose and how one can handle them. The reason for this is the advent of symmetrical multiprocessing (SMP) support that has faced increasing demand in modern operating systems. Love covers what questions the reader should be asking themselves when writing code that may be adversely affected by more than one processor. Love warns the reader that this is not something that can be tacked on at the tail end of development; it must be in the developer's mind from the start. This leads nicely into chapter ten which recalls these problems and explains the many different ways they can be addressed inside the Linux kernel. For each of these approaches, Love outlines the C functions that are available with a brief description. Love lists them in increasing complexity and decreasing frequency: atomic operations, spin locks, semaphores, mutex, completion variables, sequential locks and the Big Kernel Lock (BKL). For each of these, Love provides bullets of guidelines on when to use them versus the others. The most useful of the tables int his chapter are those that contain requirement/recommended tables that help prescribe the reader a solution. But Love advises that the simplest mechanism should be employed unless more complexity is demanded. He also advises the reader to try out several options before settling on the best way to enforce synchronization and handle concurrency. Aside from the specific technical details, this chapter was full of useful rules and guidelines to keep in mind.
The rest of the book covers — in equally excellent detail — the topics of: timers and their management, memory management, VFS, address space, I/O, page caching, debugging and portability. Love also gives some short pointers on code style, creating patches and how to join the community in the final chapter. Skimming the ToC from the second edition (also on 2.6) reveals no major changes to topics aside from some reordering and updating of sample code (like the completely fair scheduler). It's clear that Love has set out to provide a comprehensive guide to the Linux kernel and if you are looking to work intimately with the kernel for fun or for profit then this is the definitive book for delving below the surface of Linux.
You can purchase Linux Kernel Development Third Edition from amazon.com. Slashdot welcomes readers' book reviews -- to see your own review here, read the book review guidelines, then visit the submission page.