Zih*_*han 5 c linux interrupt linux-kernel
我正在阅读 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());
Run Code Online (Sandbox Code Playgroud)
里面有一个local_irq_enable()电话,这让我很困惑。为什么我们需要在这里启用中断,因为在开始时__schedule它会再次禁用?
我的粗略猜测是,这为首先安排优先级较高的进程提供了机会。然而,这是没有意义的,因为抢占已经被禁用preempt_schedule_irq,即使有中断,也不会有抢占重新安排。
那么抢占调度程序到底有什么意义呢?我想我一定错过了什么,但我不明白。
简短的回答:因为应该尽可能地启用中断,只有禁用中断才能保护最小的关键部分。任意地将禁用范围超出关键部分扩展到您正在调用的函数的非关键部分,因为您假设该函数在某些时候将禁用它们,这是糟糕的设计。
为什么 __schedule() 不禁用中断,因为它是第一条指令?因为不需要,所以 __schedule() 开头的代码不是关键部分,因此在浪费之前显式禁用中断。__schedule() 的作者不遗余力地最大化处理中断的时间,为什么不启用中断而忽略这个机会呢?
另外,您无法保证 __schedule() 将来会做什么。由于 __schedule() 的开头不是关键部分,因此您无法保证在中断禁用之前不会添加更多内容。请记住,要对 __schedule() 进行更改的人不必考虑到调用者之一决定禁用中断,因为 __schedule() 很快就会关闭中断。__schedule() 被调用时根本不考虑中断状态。
您应该禁用/启用代码关键部分的中断,而不是依赖于您正在调用的其他函数的内部机制并希望它不会改变。
如果您查看调度程序的历史记录,您会发现中断禁用之前的代码随着时间的推移而发生了变化。深入挖掘提交,您会发现自从第一次提交在内核中实现抢占以来,就存在启用中断的“sti”,一直追溯到 2.5: https: //github.com/schwabe/tglx-history/blob /ec332cd30cf1ccde914a87330ff66744414c8d24/arch/i386/kernel/entry.S#L235