Table of Contents
Pete Zaitcev gives the following summary:
If you are in a process context (any syscall) and want to
lock other process out, use a semaphore. You can take a semaphore
and sleep (copy_from_user*(
or
kmalloc(x,GFP_KERNEL)
).
Otherwise (== data can be touched in an interrupt), use
spin_lock_irqsave()
and
spin_unlock_irqrestore()
.
Avoid holding spinlock for more than 5 lines of code and
across any function call (except accessors like
readb
).
The following table lists the minimum locking requirements between various contexts. In some cases, the same context can only be running on one CPU at a time, so no locking is required for that context (eg. a particular thread can only run on one CPU at a time, but if it needs shares data with another thread, locking is required).
Remember the advice above: you can always use
spin_lock_irqsave()
, which is a superset
of all other spinlock primitives.
Table 5.1. Table of Locking Requirements
IRQ Handler A | IRQ Handler B | Softirq A | Softirq B | Tasklet A | Tasklet B | Timer A | Timer B | User Context A | User Context B | |
IRQ Handler A | None | |||||||||
IRQ Handler B | spin_lock_irqsave | None | ||||||||
Softirq A | spin_lock_irq | spin_lock_irq | spin_lock | |||||||
Softirq B | spin_lock_irq | spin_lock_irq | spin_lock | spin_lock | ||||||
Tasklet A | spin_lock_irq | spin_lock_irq | spin_lock | spin_lock | None | |||||
Tasklet B | spin_lock_irq | spin_lock_irq | spin_lock | spin_lock | spin_lock | None | ||||
Timer A | spin_lock_irq | spin_lock_irq | spin_lock | spin_lock | spin_lock | spin_lock | None | |||
Timer B | spin_lock_irq | spin_lock_irq | spin_lock | spin_lock | spin_lock | spin_lock | spin_lock | None | ||
User Context A | spin_lock_irq | spin_lock_irq | spin_lock_bh | spin_lock_bh | spin_lock_bh | spin_lock_bh | spin_lock_bh | spin_lock_bh | None | |
User Context B | spin_lock_irq | spin_lock_irq | spin_lock_bh | spin_lock_bh | spin_lock_bh | spin_lock_bh | spin_lock_bh | spin_lock_bh | down_interruptible | None |