自旋锁:
自旋锁实际上是一种忙等待,只有SMP或者支持抢占内核的系统支持。
另外需要注意的是,拥有自旋锁期间一定要避免休眠。原因是获得自旋锁时将抢占暂时关闭。一些copy_from_user、kmalloc等会导致休眠。
还有一种变体需要关闭中断,原因是中断发生时,中断服务函数有可能会获取一个自旋锁(这很有可能),而被中断的函数已经获得了这个自旋锁。这样中断服务函数只能自旋,而被中断的函数也没有机会释放自旋锁。
因此,一般的做法是,若是在中断上下文中(硬中断或者软中断)有机会使用自旋锁,则一定要使用某个禁止中断的自旋锁形式。若是只在软中断中访问自旋锁,则一定要使用spin_lock_bh,这样能防止死锁,同时又不需要禁止硬件中断。
A 定义:
typedef struct {
raw_spinlock_t raw_lock;
#ifdef CONFIG_GENERIC_LOCKBREAK
unsigned int break_lock;
#endif
#ifdef CONFIG_DEBUG_SPINLOCK
unsigned int magic, owner_cpu;
void *owner;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lockdep_map dep_map;
#endif
} spinlock_t;
B 静态声明
DEFINE_SPINLOCK(i2c_lock);
i2c_lock = SPIN_LOCK_UNLOCKED;
C 动态声明
spinlock_t *lock;
spin_lock_init(lock);
D 获取、释放
spin_lock,spin_lock_irq,spin_lock_irqsave
spin_unlock, spin_unlock_irq, spin_unlock_irqsave
void __lockfunc _spin_lock(spinlock_t *lock)
{
preempt_disable();
spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
}
void __lockfunc _spin_lock_irq(spinlock_t *lock)
{
local_irq_disable();
preempt_disable();
spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
}
上面可以看到preepmt_disable将抢占关闭。
#define spin_lock_irqsave(lock, flags) \
do { \
typecheck(unsigned long, flags); \
_spin_lock_irqsave(lock, flags); \
} while (0)
从中可以看出,自旋锁的获取和释放只是开启或者关闭抢占标志。
读写自旋锁:
读写自旋锁是为了一定程度上解决自旋锁浪费CPU资源问题。读操作可以并发,写操作是独占。
typedef struct {
raw_rwlock_t raw_lock;
#ifdef CONFIG_GENERIC_LOCKBREAK
unsigned int break_lock;
#endif
#ifdef CONFIG_DEBUG_SPINLOCK
unsigned int magic, owner_cpu;
void *owner;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lockdep_map dep_map;
#endif
} rwlock_t;
A,静态初始化
rwlock_t lock=RW_LOCK_UNLOCKED;
B,动态初始化
rwlock_t *lock;
rw_lock_init(lock);
C、读锁
read_lock read_unlock read_lock_irq read_lock_irqsave
void __lockfunc _read_lock(rwlock_t *lock)
{
preempt_disable();
rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);
LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock);
}
void __lockfunc _read_unlock(rwlock_t *lock)
{
rwlock_release(&lock->dep_map, 1, _RET_IP_);
_raw_read_unlock(lock);
preempt_enable();
}
void __lockfunc _read_lock_irq(rwlock_t *lock)
{
local_irq_disable();
preempt_disable();
rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);
LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock);
}
unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock)
{
unsigned long flags;
local_irq_save(flags);
preempt_disable();
rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);
LOCK_CONTENDED_FLAGS(lock, _raw_read_trylock, _raw_read_lock,
_raw_read_lock_flags, &flags);
return flags;
}
D、写锁
write_lock write_unlock
void __lockfunc _write_lock(rwlock_t *lock)
{
preempt_disable();
rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_);
LOCK_CONTENDED(lock, _raw_write_trylock, _raw_write_lock);
}
void __lockfunc _write_unlock(rwlock_t *lock)
{
rwlock_release(&lock->dep_map, 1, _RET_IP_);
_raw_write_unlock(lock);
preempt_enable();
}
写饥饿:当有大量写操作时,写操作会自旋在写自旋上。因为读自旋锁能自由的获取,从而导致写自旋等待所有读自旋锁释放。