您的位置:首页 > 其它

spin_lock, spin_lock_irq, spin_lock_irqsave的区别

2016-12-27 10:45 537 查看
kernel version: 2.6.26

linux kernel代码中有很多自旋锁的使用场景,同时存在很多spin_lock的接口定义,那么怎么去区分这些接口的使用场景呢?

首先来看spin_lock的实现:

#define spin_lock(lock)         _spin_lock(lock)

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);
}


spin_lock_irq的实现,我们按照smp来看:

#define spin_lock_irq(lock)     _spin_lock_irq(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);
}


spin_lock_irqsave的实现

#define spin_lock_irqsave(lock, flags)  flags = _spin_lock_irqsave(lock)

unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock)
{
unsigned long flags;

local_irq_save(flags);
preempt_disable();
spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
/*
* On lockdep we dont want the hand-coded irq-enable of
* _raw_spin_lock_flags() code, because lockdep assumes
* that interrupts are not re-enabled during lock-acquire:
*/
#ifdef CONFIG_LOCKDEP
LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
#else
_raw_spin_lock_flags(lock, &flags);
#endif
return flags;
}


显而易见,spin_lock_irq还调用了local_irq_disable函数,禁用本地中断;

假设当进程A调用spin_lock访问临界区时,如果中断来临,刚好调度到这个cpu核上,并且也去获取spin_lock,此时进程A已经被设置为TASK_INTERRUPT,同时中断处理程序因为拿不到锁,一直在忙等,进程调度无法调度进程A,导致死锁。而如果这个中断是在另一个cpu核上,就不会出现这种情况,因为另一个cpu核的中断并不会导致进程A运行状态被设置为TASK_INTERRUPT,只是被调度换出。

所以在使用spin_lock接口时,需要注意是否会在中断处理中获取锁。

而spin_lock_irqsave在进入临界区前,会保存当前中断状态flag,关闭本地中断,然后进入临界区,在退出临界区时,把保存的flag写回到中断寄存器。

spin_lock_irq在进入临界区前不保存中断状态,关中断,进入临界区,在退出临界区时,开中断。

spin_lock_irqsave锁返回时,中断状态不会被改变,调用spin_lock_irqsave前是开中断返回就开中断。

spin_lock_irq锁返回时,永远都是开中断,即使spin_lock_irq前是关中断
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spin-lock