# Spinlock

A spinlock is the simplest mutual-exclusion primitive there is:

```
while (!try_acquire_lock()) {
    /* keep checking */
}
```

The waiter doesn't go to sleep. It burns CPU on a tight loop until the lock becomes available.

## When this is the right choice

Putting a thread to sleep and waking it back up costs hundreds of nanoseconds to microseconds. If the critical section is shorter than that, sleeping is *more* expensive than spinning. Short, fast, predictable critical sections — a few pointer updates, an atomic counter — are exactly what spinlocks are for.

The whole design rests on one assumption: **the holder will release the lock very soon.** Nobody is going to preempt a thread in the middle of a 20-nanosecond section. The holder finishes before anyone notices.

## When the assumption breaks

Anything that turns a "20 nanosecond" section into something longer ruins the math:

- A page fault inside the critical section. The kernel has to allocate a physical page and update the mapping — microseconds, not nanoseconds.
- A syscall on the slow path.
- Preemption by the scheduler, especially while the holder is mid-fault. See [[linux-preemption-models]].

When this happens, the cost isn't "one thread waited longer." It's `t × N`, where `N` is the number of waiters spinning. On a 96-vCPU machine with hundreds of contended backends, this multiplier melts CPU.

[[linux-7-postgres-regression]] is the canonical instance: PostgreSQL's `StrategyGetBuffer` holds a global spinlock while touching shared memory that may not be mapped yet. Under `PREEMPT_NONE` the holder finished the fault and released. Under `PREEMPT_LAZY` the scheduler can preempt mid-fault, multiplying the spin time by every waiting backend.

## Mitigations

- Make the critical section actually short — no syscalls, no first-touch memory accesses.
- Pre-fault and pre-map memory the section will touch (e.g., [[huge-pages]] reduce the number of first-touch faults by orders of magnitude).
- Use Restartable Sequences (`rseq`) so the kernel signals preemption and userspace can restart the section. Linux-specific.
- Fall back to a sleeping mutex when contention or section length grows beyond what spinning is good for.
