spin_lock_irqsave 与 spin_lock_irq
在 SMP 机器上,我们必须使用中断上下文中的 spin_lock_irqsave
而不是 spin_lock_irq
。
为什么我们要保存标志(其中包含 IF)?
是否还有另一个中断例程可以打断我们?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
spin_lock_irqsave
主要用于在获取自旋锁之前保存中断状态,这是因为当在中断上下文中获取锁时,自旋锁会禁用中断,并在解锁时重新启用它。保存中断状态,以便再次恢复中断。示例:
spin_lock_irq
将禁用中断 x 并获取锁,spin_unlock_irq
将启用中断 x。因此,在释放锁后的第三步中,我们将启用中断 x,该中断在获取锁之前已被禁用。
因此,只有当您确定中断未被禁用时,您才应该
spin_lock_irq
,否则您应该始终使用spin_lock_irqsave
。spin_lock_irqsave
is basically used to save the interrupt state before taking the spin lock, this is because spin lock disables the interrupt, when the lock is taken in interrupt context, and re-enables it when while unlocking. The interrupt state is saved so that it should reinstate the interrupts again.Example:
spin_lock_irq
will disable the interrupt x and take the the lockspin_unlock_irq
will enable the interrupt x.So in the 3rd step above after releasing the lock we will have interrupt x enabled which was earlier disabled before the lock was acquired.
So only when you are sure that interrupts are not disabled only then you should
spin_lock_irq
otherwise you should always usespin_lock_irqsave
.如果在代码开始锁定之前中断已被禁用,那么当您调用
spin_unlock_irq
时,您将以一种可能不需要的方式强制重新启用中断。相反,如果您还通过spin_lock_irqsave
将当前中断启用状态保存在flags
中,则在释放锁后尝试使用相同的flags
重新启用中断,该函数只会恢复之前的状态(因此不一定启用中断)。spin_lock_irqsave
示例:spin_lock_irq
示例(不带 irqsave):If interrupts are already disabled before your code starts locking, when you call
spin_unlock_irq
you will forcibly re-enable interrupts in a potentially unwanted manner. If instead you also save the current interrupt enable state inflags
throughspin_lock_irqsave
, attempting to re-enable interrupts with the sameflags
after releasing the lock, the function will just restore the previous state (thus not necessarily enabling interrupts).Example with
spin_lock_irqsave
:Example with
spin_lock_irq
( without irqsave ):除了
spin_lock_irq
之外,还需要spin_lock_irqsave
,这与除了local_irq_disable
之外还需要local_irq_save(flags)
的原因非常相似。以下是 Robert Love 所著的《Linux 内核开发第二版》中对该要求的一个很好的解释。The need for
spin_lock_irqsave
besidesspin_lock_irq
is quite similar to the reasonlocal_irq_save(flags)
is needed besideslocal_irq_disable
. Here is a good explanation of this requirement taken from Linux Kernel Development Second Edition by Robert Love.阅读 为什么在中断上下文中执行的内核代码/线程无法休眠? 链接到 Robert Loves 文章,我读了这个:
Reading Why kernel code/thread executing in interrupt context cannot sleep? which links to Robert Loves article, I read this :
下面是linux内核4.15.18中的部分代码,其中显示spiin_lock_irq()将调用__raw_spin_lock_irq()。但是,它不会保存任何标志,如下面的代码部分所示,但会禁用中断。
下面的代码显示了 spin_lock_irqsave(),它保存当前阶段的标志,然后抢占禁用。
Below is part of code in linux kernel 4.15.18, which shows that spiin_lock_irq() will call __raw_spin_lock_irq(). However, it will not save any flags as you can see below part of the code but disable the interrupt.
Below code shows spin_lock_irqsave() which saves the current stage of flag and then preempt disable.
我认为这种说法根本不真实。对于硬中断和软中断之间的共享,可以在软中断中使用 spin_lock_irq 。
每当您想在持有锁时防止硬中断或软中断抢占时,就可以使用 _irq 或 _irqsave。 _irqsave 还保存 EFLAGS 以供以后恢复。
spin_lock_irq 在 irq 处理程序中使用总是错误的,因为解锁会重新启用 IRQ,而这应该由调用者完成。根据
kernel/irq/handle.c:__handle_irq_event_percpu
,如果您的处理程序在启用 IRQ 的情况下返回,这将生成警告spin_lock_irqsave 是通用的,但我很难找到一个您不能使用其他任何东西的特定用例。当您想要将解锁/锁定放入可能从硬中断和非硬中断调用的函数中时,它可能很有用,因为在这种情况下,您不能使用 spin_lock_irq 或 spin_lock(_bh)
I don't think this statement is true at all. For sharing between hardirq and softirq, it's fine to just use spin_lock_irq in the softirq.
you use _irq or _irqsave whenever you want to prevent preemption by EITHER hard OR softirq while holding the lock. the _irqsave one also saves EFLAGS for later restoration.
spin_lock_irq will always be wrong to use in an irq handler since unlocking re-enables IRQ which should be done by the caller. And according to
kernel/irq/handle.c:__handle_irq_event_percpu
, This will generate a warning if your handler returns with IRQ enabledspin_lock_irqsave is universal but I struggle to find a specific use case where you can use nothing else. Maybe it's useful when you want to put un/locking into a function that might be called from both hardirq AND non-hardirq because in this case, you cannot use spin_lock_irq or spin_lock(_bh)
这个问题从错误的断言开始:
这些都不应该从中断中使用
上下文,在 SMP 或 UP 上。也就是说,
spin_lock_irqsave()
可以从中断上下文中使用,因为更通用
(它可以在中断和正常上下文中使用),但是
您应该从中断上下文中使用
spin_lock()
,以及来自正常上下文的
spin_lock_irq()
或spin_lock_irqsave()
。使用
spin_lock_irq()
几乎总是错误的在中断上下文中执行此操作,即 SMP 或 UP。它可能会起作用
因为大多数中断处理程序在本地启用 IRQ 的情况下运行,
但你不应该这样做。
更新:由于有些人误读了这个答案,让我澄清一下
它只解释了什么是中断,什么不是中断
上下文锁定。这里没有声明
spin_lock()
应该仅在中断上下文中使用。可以在一个进程中使用
上下文也是如此,例如如果不需要锁定中断
语境。
This question starts from the false assertion:
Neither of these should be used from interrupt
context, on SMP or on UP. That said,
spin_lock_irqsave()
may be used from interrupt context, as being more universal
(it can be used in both interrupt and normal contexts), but
you are supposed to use
spin_lock()
from interrupt context,and
spin_lock_irq()
orspin_lock_irqsave()
from normal context.The use of
spin_lock_irq()
is almost always the wrong thingto do in interrupt context, being this SMP or UP. It may work
because most interrupt handlers run with IRQs locally enabled,
but you shouldn't try that.
UPDATE: as some people misread this answer, let me clarify that
it only explains what is for and what is not for an interrupt
context locking. There is no claim here that
spin_lock()
shouldonly be used in interrupt context. It can be used in a process
context too, for example if there is no need to lock in interrupt
context.