Spinlock (vs. Mutex) (Slideshow)

Mutual Exclusion: Spinlock

Atomic context must not sleepbusy waiting

  • The only locking possibility in atomic context

  • Can also be used in process context

    • Cheap - no context switch if lock is held

    • Interrupts off on local CPU ⟶ anti-realtime

How does it work?

  • On a Uniprocessor

    • Disable interrupts

    • ⟶ preemption disabled

    • ⟶ lock in its simplest form

  • On a Multiprocessor

    • Set “locked” flag (atomically)

    • Disable interrupts on local processor

    • ⟶ no preemption on local processor

    • Remote processors busy wait around the “locked” flag (atomically trying to test-and-set it)

Spinlock Initialization

#include <linux/spinlock.h>

spinlock_t lock;
void spin_lock_init(spinlock_t* lock);
  • No destructor available

Simple Lock/Unlock

#include <linux/spinlock.h>

void spin_lock(spinlock_t *lock);
int spin_trylock(spinlock_t *lock);
void spin_unlock(spinlock_t *lock);

Careful

  • No nesting (no recursive locks) ⟶ deadlock

  • If you find yourself using spin_trylock()

    • your code is likely broken

    • you rather want to wait for something

Simple is not Bulletproof: Interrupt State

  • Multiple spinlocks can be acquired in non-trivial call chains

  • Most variations don’t keep track of interrupt state

    • Too easy to re-enable interrupts too early

    • One cannot always control the call chain

unsigned long irqflags;

spin_lock_irqsave(&lock, irqflags);
...
spin_unlock_irqrestore(&lock, irqflags);

Mutual Exclusion: Conclusion

There is always a tradeoff

  • Spinlocks are good

    • No expensive context switch during lock contention

    • Can be used in (between) interrupt context and process context

  • Spinlocks are bad

    • No sleep! (⟶ no easy memory allocation, no easy this, no easy that)

    • Must be held very short ⟶ no scheduling/preemption on local processor

  • Mutexes are good

    • Sleeping allowed

    • Everything’s easy

  • Mutexes are bad

    • Expensive context switch during lock contention

    • Cannot be used in interrupt context

    • ⟶ no easy data sharing between process and interrupt context