我正在阅读linux源代码以了解调度的工作原理。我了解到,在一个可抢占的内核(CONFIG_PREEMPT
已设置)中,通过调用preempt_schedule_irq
从中断处理程序返回内核空间后,有可能抢占。
但是,我还在preempt_schedule_irq
中找到了以下代码段do {
preempt_disable();
local_irq_enable(); //why enable interrupt here?
__schedule(true); //interrupt would be disabled inside it
local_irq_disable();
sched_preempt_enable_no_resched();
} while (need_resched());
里面有一个local_irq_enable()
电话,这种混淆了我。为什么我们需要在at the start of __schedule
it would disabled again之后启用中断?
我的谦虚猜测是,这为首先安排优先级较高的进程提供了机会。但是,它没有意义,因为preempt_schedule_irq
中的抢占已被禁用,即使存在中断,也不会有抢占重新安排。
那么究竟什么在这里取代调度程序呢?我想我一定错过了一些东西,但我不知道。
答案 0 :(得分:1)
简短的回答:由于应尽可能启用中断,因此仅禁用此中断是为了保护最少的关键部分。随意地将禁用范围从关键部分扩展到要调用的函数的非关键部分,因为您假设在某个时候该函数将禁用它们,这是错误的设计。
为什么__schedule()不能禁止中断,因为它是第一条指令?因为不需要,所以__schedule()开头的代码不是关键部分,因此在浪费之前显式禁用中断是很重要的。 __schedule()的作者不遗余力地最大化了可以处理中断的时间,为什么不通过不启用中断来忽略这种机会呢?
此外,您不能保证__schedule()将来可能会做什么。由于__schedule()的开头不是关键部分,因此无法保证在禁用中断之前不会添加更多内容。请记住,将要更改__schedule()的人不必考虑调用者之一决定依靠__schedule()很快将其关闭的事实来使中断保持禁用状态。 __schedule()在调用时完全不关心中断状态。
您应该在代码的关键部分周围禁用/启用中断,而不要依赖于您正在调用的其他函数的内部机制,并希望它不会改变。
如果仔细查看调度程序的历史记录,您会发现中断禁用之前的代码已随时间而改变。深入了解提交,您会发现自从实现内核中的抢占的第一个提交一直追溯到2.5以来的第一次提交,就存在启用中断的“ sti”:https://github.com/schwabe/tglx-history/blob/ec332cd30cf1ccde914a87330ff66744414c8d24/arch/i386/kernel/entry.S#L235