为什么 irqs_disabled() 是一种不安全的禁用抢占的方法?

为什么 irqs_disabled() 是一种不安全的禁用抢占的方法?

可抢占内核下的正确锁定:保持内核代码抢占安全文章说,

但请记住,“禁用 irqs” 是一种根本上不安全的禁用抢占的方式 - 任何将抢占计数减少到 0 的 spin_unlock() 都可能会触发重新调度。一个简单的 printk() 可能会触发重新安排。

如果 IRQ 被禁用,那么该 CPU 内核上的定时器中断也应该被禁用。自然,它应该依次禁用调度程序(抢占)。为什么调用 irqsdisabled() 来禁用抢占是不安全的方法?

此外, printk() 如何触发重新安排?

答案1

是的,如果 IRQ 被禁用,定时器中断将被禁用并且任务调度不再发生。不安全的部分是“如果”:如果您依赖于禁用的 IRQ,您需要绝对确保在禁用 IRQ 的情况下运行的所有代码都遵守这一点。这在内核中可能相当困难,因为自旋锁自行禁用和启用抢占(在某些情况下与 IRQ 一起),许多代码都使用锁,包括printk(以确保日志消息不会混淆)。每当锁被释放时,即使 IRQ 被禁用,您也会面临重新安排的风险(以运行等待锁的代码):preempt_enable()显式调用__preempt_schedule()当其计数器达到零时,因此不需要定时器中断。

因此,使用适当的抢占支持功能会更安全,特别是在面向未来方面:您可能很清楚您现在正在编写的代码中的约束,但其他人不会更改它(并且“某人否则”包括“六个月后的你”)。

答案2

因为定时器中断(或一般中断)并不是内核抢占的唯一原因。有些函数仍然可以触发抢占(例如 cond_resched()),这些函数期望显式禁用抢占。

相关内容