非抢占式 Linux 内核上的 spin_lock

发布于 2024-09-12 00:34:46 字数 217 浏览 5 评论 0原文

我读到,在具有 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

家住魔仙堡 2024-09-19 00:34:46

如果您要在非抢占式内核上使用 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.

云醉月微眠 2024-09-19 00:34:46

回答你的问题的两个部分:

即使在非抢占式内核上,中断处理程序仍然可以执行,例如......

spin_lock() 不应该防止中断处理程序 - 只能保护用户上下文内核代码。 spin_lock_irqsave() 是中断禁用版本,这不是非抢占式单处理器上的无操作。

...或者我可能会调用一个函数来使原始线程进入睡眠状态。

持有自旋锁时不允许休眠。这是“原子调度”错误。如果你想睡觉,你必须使用互斥锁(同样 - 这些不是非抢占式单处理器上的无操作)。

To answer the two parts of your question:

Even on non-preemtive kernels interrupt handlers may still be executed for example ...

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.

...or I might call a function that would put the original thread to sleep.

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).

忘羡 2024-09-19 00:34:46

引自 Jonathan Corbet、Alessandro Rubini 和 Greg Kroah-Hartman 的《Linux 设备驱动程序》

如果一个非抢占式单处理器系统曾经在一个
锁上,它就会永远旋转;没有其他线程能够
获取CPU来释放锁(因为它无法让出)。
因此,单处理器系统上的自旋锁操作无需
启用抢占被优化为不执行任何操作,但以下情况除外
改变 IRQ 屏蔽状态的那些(在 Linux 中,这将是
spin_lock_irqsave())。因为抢占,即使你从未
期望你的代码能够在SMP系统上运行,你仍然需要实现
正确锁定。

如果您对可由在中断上下文(硬件或软件)中运行的代码获取的自旋锁感兴趣,则必须使用一种禁用中断的 spin_lock_* 形式。如果不这样做,当您进入临界区时,一旦中断到达,系统就会死锁。

Quoted from «Linux Device Drivers», by Jonathan Corbet, Alessandro Rubini and Greg Kroah-Hartman:

If a nonpreemptive uniprocessor system ever went into a spin on a
lock, it would spin forever; no other thread would ever be able to
obtain the CPU to release the lock (because it couldn't yield).
Because of this, spinlock operations on uniprocessor systems without
preemption enabled are optimized to do nothing, with the exception of
the ones that change the IRQ masking status (in Linux, that would be
spin_lock_irqsave()). Because of preemption, even if you never
expect your code to run on an SMP system, you still need to implement
proper locking.

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.

浅黛梨妆こ 2024-09-19 00:34:46

根据定义,如果您使用非抢占式内核,则不会被抢占。如果你自己进行多任务处理,那不是内核的问题;而是内核的问题。那是你的问题。中断处理程序仍可能被执行,但它们不会导致上下文切换。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文