16

最近在看Linux Kernel Development,有几个关于禁用抢占的问题。

  1. 在第 7 章的“中断控制”部分,它说:

    此外,禁用中断也会禁用内核抢占。

    我还从书中读到内核抢占可能发生在以下情况:

    当中断处理程序退出时,在返回内核空间之前。
    当内核代码再次变得可抢占时。
    如果内核中的任务显式调用 schedule()
    如果内核中的任务阻塞(这导致调用 schedule())

    但我无法将禁用中断与这些情况联系起来。

  2. 据我所知,自旋锁会使用preempt_disable()函数禁用抢占。

    帖子究竟什么是“自旋锁”? 说:

    在单核机器上,自旋锁只是“禁用中断”或“提高 IRQL”,它完全阻止线程调度。

    preempt_disable()是否通过禁用中断来禁用抢占?

4

4 回答 4

16

我不是调度大师,但我想解释一下我的看法。这里有几件事。

  1. preempt_disable()不会禁用 IRQ。它只是增加了一个thread_info->preempt_count变量。
  2. 禁用中断也会禁用抢占,因为在那之后调度程序不工作 - 但仅在单 CPU 机器上。在 SMP 上这还不够,因为当您关闭一个 CPU 上的中断时,另一个/其他 CPU 仍然会异步执行/执行某些操作。
  3. 大锁(意味着 - 关闭所有 CPU 上的所有中断)正在显着降低系统速度 - 所以这就是它不再使用的原因。这也是 preempt_disable() 不关闭 IRQ 的原因。

你可以看到 preempt_disable() 是什么。试试这个: 1. 获得一个自旋锁。2.调用schedule()

在 dmesg 中,您将看到类似“BUG:原子时调度”的内容。当调度程序检测到您的进程在原子(非抢占式)上下文中但它自行调度时,就会发生这种情况。

祝你好运。

于 2013-12-26T16:08:58.793 回答
2

在我编写的用于监视/分析任务的测试内核模块中,我尝试通过以下方式禁用中断:

1 - 使用 local_irq_save()

2 - 使用 spin_lock_irqsave()

3 - 手动 disable_irq() 到 /proc/interrupts 中的所有 IRQ

在所有 3 种情况下,我仍然可以使用 hrtimer 来测量时间,即使 IRQ 被禁用(并且我正在监视的任务也被抢占)。

我觉得这个 veeeeerrrryyyy 很奇怪......我个人期待 Sebastian Mountaniol 指出的 -> 没有中断 - 没有时钟。没有时钟 - 没有计时器...

单核、单 CPU 上的 Linux 内核 2.6.32 ......谁能有更好的解释?

于 2014-02-11T16:15:54.363 回答
1
  1. preempt_disable()不会禁用中断。但是,它会增加抢占计数器的计数。假设您preempt_disable()在代码路径中调用 n 次,抢占只会在第 n 次启用preempt_enable()
  2. 禁用中断以防止抢占:不是一种安全的方法。这无疑会禁用正常的内核抢占,因为scheduler_tick()不会在系统滴答时被调用(没有调用中断处理程序)。但是,如果程序触发了调度函数,如果没有被调用,就会发生抢占preempt_disable()
  3. 在 linuxraw_spin_lock() 中,不禁用可能导致死锁的本地中断。例如,如果调用中断处理程序并尝试锁定已持有的自旋锁,则除非进程本身释放它,否则它将无法锁定,这是不可能的,因为不会发生中断返回。因此,最好使用raw_spin_lock_irq()禁用中断的 。
于 2020-07-20T17:13:01.090 回答
0

中断禁用会禁用某些形式的内核抢占,但还有其他方式可以发生内核抢占。出于这个原因,禁用中断不被认为是防止内核抢占的安全方法。

例如,在禁用中断的情况下, cond_resched() 仍会导致抢占,但如果显式禁用抢占则不会。

这就是为什么,关于你的第二个问题,自旋锁不使用中断禁用来禁用抢占。它们显式调用 preempt_disable() 来增加 preempt_count,并禁用所有可能发生抢占的方式,除非显式调用 schedule()。

于 2020-09-16T01:26:17.047 回答