Kernel Primitives/Locking

From Linux Drivers
Jump to: navigation, search

Locking scenarios

Irq Handler Softirq Tasklet Timer User Context
Interrupt
Softirq
Tasklet
Timer
User Context
  • user: spin_lock_irqsave/spin_unlock_irqrestore
  • interrupt: spin_lock/spin_unlock
  • user: spin_lock_bh/spin_unlock_bh
  • softirq: spin_lock/spin_unlock
  • user: spin_lock_bh/spin_unlock_bh
  • tasklet: spin_lock/spin_unlock
  • user: spin_lock_bh/spin_unlock_bh
  • timer: spin_lock/spin_unlock
  • user: down_interruptible/up
  • If the critical section is only accessible by single process, the critical section is not reentrant, thus locking is not required.


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

Personal tools
Namespaces

Variants
Actions
Navigation
Toolbox