非抢占式 Linux 内核上的 spin_lock
我读到,在具有 1 个 CPU 和非抢占式 Linux 内核 (2.6.x) 的系统上, spin_lock 调用相当于空调用,因此以这种方式实现。
我无法理解:它不应该相当于在互斥体上睡眠吗?例如,即使在非抢占式内核上,中断处理程序仍然可以执行,或者我可能会调用一个函数来使原始线程进入睡眠状态。因此,空 spin_lock 调用并不像作为互斥体实现那样“安全”。
有什么我不明白的吗?
I read that on a system with 1 CPU and non preemtive linux kernel (2.6.x) a spin_lock call is equivalent to an empty call, and thus implemented that way.
I can't understand that: shouldn't it be equivalent to a sleep on a mutex? Even on non-preemtive kernels interrupt handlers may still be executed for example or I might call a function that would put the original thread to sleep. So it's not true that an empty spin_lock call is "safe" as it would be if it was implemented as a mutex.
Is there something I don't get?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果您要在非抢占式内核上使用 spin_lock() 来保护数据免受中断处理程序的影响,则会出现死锁(在单处理器计算机上)。
如果中断处理程序在其他内核代码持有锁时运行,它将永远旋转,因为常规内核代码无法恢复和释放锁。
仅当锁持有者始终能够运行完成时才能使用自旋锁。
对于中断处理程序可能需要的锁,解决方案是使用 spin_lock_irqsave(),它会在持有自旋锁时禁用中断。对于1个cpu,没有中断处理程序可以运行,因此不会出现死锁。在 smp 上,中断处理程序可能会开始在另一个 cpu 上旋转,但由于持有锁的 cpu 无法被中断,因此锁最终会被释放。
If you were to use
spin_lock()
on a non-preemptive kernel to shield data against an interrupt handler, you'd deadlock (on a single-processor machine).If the interrupt handler runs while other kernel code holds the lock, it will spin forever, as there is no way for the regular kernel code to resume and release the lock.
Spinlocks can only be used if the lock holder can always run to completion.
The solution for a lock that might be wanted by an interrupt handler is to use
spin_lock_irqsave()
, which disables interrupts while the spinlock is held. With 1 cpu, no interrupt handler can run, so there will not be a deadlock. On smp, an interrupt handler might start spinning on another cpu, but since the cpu holding the lock can't be interrupted, the lock will eventually be released.回答你的问题的两个部分:
spin_lock()
不应该防止中断处理程序 - 只能保护用户上下文内核代码。spin_lock_irqsave()
是中断禁用版本,这不是非抢占式单处理器上的无操作。持有自旋锁时不允许休眠。这是“原子调度”错误。如果你想睡觉,你必须使用互斥锁(同样 - 这些不是非抢占式单处理器上的无操作)。
To answer the two parts of your question:
spin_lock()
isn't supposed to protect against interrupt handlers - only user context kernel code.spin_lock_irqsave()
is the interrupt-disabling version, and this isn't a no-op on a non-preemptive uniprocessor.It is not allowed to sleep while holding a spin lock. This is the "Scheduling while atomic" bug. If you want to sleep, you have to use a mutex instead (again - these aren't a no-op on non-preemptive uniprocessor).
引自 Jonathan Corbet、Alessandro Rubini 和 Greg Kroah-Hartman 的《Linux 设备驱动程序》:
如果您对可由在中断上下文(硬件或软件)中运行的代码获取的自旋锁感兴趣,则必须使用一种禁用中断的
spin_lock_*
形式。如果不这样做,当您进入临界区时,一旦中断到达,系统就会死锁。Quoted from «Linux Device Drivers», by Jonathan Corbet, Alessandro Rubini and Greg Kroah-Hartman:
If you're interested in a spinlock that can be taken by code running in interrupt context (hardware or software), you must use a form of
spin_lock_*
that disables interrupts. Not doing so will deadlock the system as soon as an interrupt arrives while you have entered your critical section.根据定义,如果您使用非抢占式内核,则不会被抢占。如果你自己进行多任务处理,那不是内核的问题;而是内核的问题。那是你的问题。中断处理程序仍可能被执行,但它们不会导致上下文切换。
By definition, if you're using a non-preemptive kernel, you won't be preempted. If you do your own multitasking, that's not the kernel's problem; that's your problem. Interrupt handlers may still be executed, but they won't cause context switches.