spin_lock_irqsave vs spin_lock_irq
-
23-09-2019 - |
题
在SMP机,我们必须使用 spin_lock_irqsave
而不 spin_lock_irq
从中断的上下文。
为什么我们要保存的标记(这包含如果)?
是否有另一个中断程序可能中断我们吗?
解决方案
我是新来的内核,但是从我从罗伯特·爱的书“Linux内核开发”聚集,如果中断是在处理器上的代码开始锁定,当你调用spin_unlock_irq你会在错误解除锁定之前已被禁用方式。如果保存的标志,并与标志放开,功能spin_lock_irqsave将只恢复到中断到以前的状态。
实施例与spin_lock_irqsave
spinlock_t mLock = SPIN_LOCK_UNLOCK;
unsigned long flags;
spin_lock_irqsave(&mLock, flags); // save the state, if locked already it is saved in flags
// Critical section
spin_unlock_irqrestore(&mLock, flags); // return to the formally state specified in flags
实施例与spin_lock_irq
(无irqsave):
spinlock_t mLock = SPIN_LOCK_UNLOCK;
unsigned long flags;
spin_lock_irq(&mLock); // Does not know if already locked
// Critical section
spin_unlock_irq(&mLock); // Could result in an error unlock...
其他提示
spin_lock_irqsave
基本上是用于保存的中断之前的状态下采取的旋锁,这是因为旋锁禁止中断,当锁采取在中断的情况下,并重新启用它,当同时解锁。中断状态是保存,所以它应该恢复中断一次。
例如:
- 可以说,中断x是残疾前旋锁被收购
spin_lock_irq
将禁止中断x和采取的锁spin_unlock_irq
将使该中断。
因此,在第3上述步骤之后释放锁,我们将中断x启用了其较早的禁用以前的锁被收购。
所以只有当你是肯定的中断是不是残疾人才那么你应该 spin_lock_irq
否则你应该始终使用 spin_lock_irqsave
.
在需要除了spin_lock_irqsave
spin_lock_irq
非常类似于需要除了local_irq_save(flags)
local_irq_disable
的原因。这里是由罗伯特·爱的Linux内核开发第二版采取了这一要求一个很好的解释。
在local_irq_disable()例程是危险的,如果中断是 已经它的调用之前禁用。相应的调用 local_irq_enable()无条件使能中断,尽管 事实上,他们是断的开始。取而代之的是,需要一种机制 对中断恢复到以前的状态。这是一个共同关注 因为在内核中给定的代码路径可以达到既和 没有中断功能,这取决于调用链。例如, 想象前面的代码片段是一个更大的功能的一部分。 试想一下,这个功能是由其他两个功能,一个叫这 禁止中断和一个其中没有。因为它正在成为 更难为核心的增长规模和复杂性要知道所有的代码 路径导致到一个函数,它是更安全保存的状态 禁用它之前中断系统。然后,当你准备好 重新启用中断,您只需将它们恢复到原来的状态:
unsigned long flags;
local_irq_save(flags); /* interrupts are now disabled */ /* ... */
local_irq_restore(flags); /* interrupts are restored to their previous
state */
请注意,这些方法是部分地作为宏至少实现的,所以 标志参数(其必须被定义为一个无符号长整数)是 看似按值传递。此参数包含 包含中断的状态架构特定的数据 系统。因为至少有一个支持的体系结构结合 堆栈信息进值(啊哈,SPARC),标志不能被传递 到另一个功能(具体而言,它必须保持相同的堆栈上 帧)。出于这个原因,调用保存和调用恢复 中断必须发生在相同的功能。
所有先前的功能可以由两个中断调用并 进程上下文
阅读 为什么核码线执行在中断背景下不能睡觉? 其链接到罗伯特*爱 文章, 我这样说的:
一些中断的处理程序(知 Linux作为快速处理程序的中断)的运行 与所有中断的地方 处理残疾人。这样做是为了 确保处理程序的中断运行 没有中断,尽快 可能的。更是如此,所有中断 处理程序的运行与其目前的 断线无所有 处理器。这确保了两个 中断的处理程序一样的 断线不行 同时进行。它还可以防止设备 驱动程序的作家具有处理 递中断,其复杂 编程。
以下是在Linux内核18年4月15日,的代码的一部分,其示出了该spiin_lock_irq()将调用__raw_spin_lock_irq()。然而,将不保存任何标志,你可以看到下面的代码的一部分,但禁止中断。
static inline void __raw_spin_lock_irq(raw_spinlock_t *lock)
{
local_irq_disable();
preempt_disable();
spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
}
下面代码所示spin_lock_irqsave()这节省了标志的当前阶段,然后抢先禁用。
static inline unsigned long __raw_spin_lock_irqsave(raw_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
* do_raw_spin_lock_flags() code, because lockdep assumes
* that interrupts are not re-enabled during lock-acquire:
*/
#ifdef CONFIG_LOCKDEP
LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
#else
do_raw_spin_lock_flags(lock, &flags);
#endif
return flags;
}
此问题来自假断言开始:
On an SMP machine we must use spin_lock_irqsave and not spin_lock_irq from interrupt context.
的这些也不应该被从中断使用
背景下,SMP或UP。这就是说,spin_lock_irqsave()
可从中断上下文所使用的,为更普遍的
(它可以在两个中断和正常的环境中使用),但
你应该使用spin_lock()
从中断上下文,
和spin_lock_irq()
或spin_lock_irqsave()
从正常上下文。
使用spin_lock_irq()
的几乎总是错误的事情
在中断上下文做的,是这SMP或UP。它可能工作
因为用的IRQ运行大多数中断处理程序在本地启用,
但你不应该尝试的。