kernel synchronization
Inside a modern kernel, many things can touch the same data at the same time: several CPUs each running kernel code, an interrupt arriving in the middle of an update, and the kernel preempting one task to run another. If two of them modify a shared list or counter without coordination, the data corrupts. Kernel synchronization is the set of techniques the kernel uses to keep its own internal data consistent under this fierce concurrency. It is the same problem as locking shared data in any concurrent program, but with extra hard constraints, because some kernel code runs where it absolutely cannot sleep or be interrupted.
Concretely, the kernel chooses among several tools by context. A spinlock is a busy-wait lock: a CPU just loops until it acquires the lock, which is fine for very short critical sections and is the only safe choice in interrupt context (where the code cannot sleep) — but wastes CPU if held long. A mutex or semaphore can put the waiter to sleep, which is efficient for longer waits but only usable in code that is allowed to sleep (not in an interrupt handler). To avoid locking entirely, the kernel uses per-CPU data (each CPU has its own copy, so no sharing, no lock) and read-copy-update (RCU), which lets many readers proceed with no locks while writers make a new version and free the old one only after all readers finish. The kernel also synchronizes by disabling preemption or disabling interrupts on the local CPU to make a sequence atomic against those specific disruptions.
It matters because a kernel bug here can hang or crash the whole machine, not just one app, and because the rules are subtle: taking a sleeping lock in interrupt context, or doing slow work while holding a spinlock, is a classic disaster. A crucial honest point is that a lock protects data only if every path that touches that data takes the same lock — one careless unsynchronized access anywhere reintroduces the race, exactly as with a semaphore in user space.
Two CPUs both try to add an entry to the same kernel list at once. Without a lock, both read the same tail pointer, and one update overwrites the other — a lost entry and a corrupt list. With a spinlock around the list update, the second CPU spins for the few instructions the first needs, then proceeds; the list stays consistent. If instead the update could take a long time, the kernel would use a mutex so the waiter sleeps rather than burns a CPU.
Pick the lock by context: spinlock for short, non-sleeping work; mutex for longer, sleepable work.
RCU is not a free lunch: it shines for read-mostly data because readers take no lock, but writers pay a cost and must wait for a grace period before reclaiming old data. Choosing the wrong primitive — a sleeping lock where you cannot sleep, or a spinlock held too long — is a leading cause of kernel deadlocks and stalls.