Kernel Primitives/Locking
From Linux Drivers
Locking scenarios
Irq Handler | Softirq | Tasklet | Timer | User Context | |
Interrupt | |||||
Softirq | |||||
Tasklet | |||||
Timer | |||||
User Context |
|
|
|
|
|
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 | ||||||||||
Irq Handler B | ||||||||||
Softirq A | ||||||||||
Softirq B | ||||||||||
Tasklet A | ||||||||||
Tasklet B | ||||||||||
Timer A | ||||||||||
Timer B | ||||||||||
User Context A | user: spin_lock_bh() softirq: spin_lock() |
|||||||||
User Context B |
user context: spin_lock_bh(), spin_unlock_bh() softirq:
Implementation of spin lock
UP | SMP | |
Non-preemptible | Do nothing | spin |
Preemtible | Disable and Enable preemption by preempt_disable() and preempt_enable |
include/linux/spinlock.h
#define raw_spin_lock(lock) _raw_spin_lock(lock) static inline void spin_lock(spinlock_t *lock) { raw_spin_lock(&lock->rlock); }
include/linux/spinilock_api_up.h
#define __LOCK(lock) \ do { preempt_disable(); __acquire(lock); (void)(lock); } while (0) #define _raw_spin_lock(lock) __LOCK(lock)
include/linux/spinilock_api_smp.h
#define raw_spin_unlock(lock) _raw_spin_unlock(lock) static inline void spin_unlock(spinlock_t *lock) { raw_spin_unlock(&lock->rlock); }
include/linux/spinilock_api_up.h
#define __UNLOCK(lock) \ do { preempt_enable(); __release(lock); (void)(lock); } while (0) #define _raw_spin_unlock(lock) __UNLOCK(lock)
Reference
- Unreliable Guide To Locking by Rusty Russell
- The new way of ioctl(): ioctl handler is protected by BKL, but unlock_ioctl is not protected. unlocked_ioctl is preferred handler of ioctl.