【问题标题】:Why does the Linux kernel enable interrupts in preempt_schedule_irq?为什么 Linux 内核在 preempt_schedule_irq 中启用中断?
【发布时间】:2018-07-01 05:06:49
【问题描述】:

我正在阅读 Linux 源代码以了解调度的工作原理。我了解到在可抢占内核(设置了CONFIG_PREEMPT)中,通过调用preempt_schedule_irq 从中断处理程序返回内核空间后有机会进行抢占。

不过,我也在preempt_schedule_irq中找到了如下代码sn-p

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中已经禁用了抢占,即使有中断,也不会重新安排抢占。

那么在这里抢占调度程序到底有什么意义呢?我想我一定错过了什么,但我不明白。

【问题讨论】:

  • 不是和优先级倒置有关吗?
  • 感谢提供线索,我不知道,所以我会调查一下。
  • @Jean-BaptisteYunès 嗨,我昨天做了一些搜索,但我仍然不太明白它与优先级反转的关系。我看不到它的优先级在哪里改变,启用中断如何帮助防止这种情况?假设有 3 个进程,其优先级为 A
  • 我自己不明白这一切的目的是什么,但你认为这可能与高优先级优先调度有关,我想到了优先级反转问题。乍一看,这一切似乎很奇怪而且没有用,但我怀疑它是。

标签: c linux linux-kernel interrupt


【解决方案1】:

简短回答:因为应尽可能启用中断,仅禁用以保护最小的关键部分。随意将禁用超出您的关键部分扩展到您正在调用的函数的非关键部分,因为您假设在某些时候该函数会禁用它们,这是糟糕的设计。

为什么 __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

【讨论】:

    猜你喜欢
    • 2019-12-21
    • 1970-01-01
    • 2013-08-31
    • 2017-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多