为什么禁用中断禁用内核抢占以及spinlock如何禁用抢占

时间:2013-12-25 06:32:23

标签: linux linux-kernel interrupt spinlock preemption

我最近正在阅读 Linux内核开发,我有一些与禁用抢占相关的问题。

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

      

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

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

      

    当中断处理程序退出时,返回内核空间之前   当内核代码再次成为可抢占时   如果内核中的任务明确调用schedule()
      如果内核中的任务阻塞(导致调用schedule())

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

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

    帖子What exactly are "spin-locks"? 表示:

      

    在单核心机器上,自旋锁只是一个“禁用中断”或“引发IRQL”,它会完全阻止线程调度。

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

4 个答案:

答案 0 :(得分:9)

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

  1. preempt_disable()不会禁用IRQ 。它只会增加thread_info->preempt_count变量。
  2. 禁用中断还会禁用抢占,因为调度程序在此之后不起作用 - 但仅限于单CPU计算机上。在SMP上它是不够的,因为当你关闭一个CPU上的中断时,另一个/其他人仍然会异步地做/做某事。
  3. Big Lock(意味着 - 关闭所有CPU上的所有中断)正在大大降低系统速度 - 所以这就是为什么它不再使用了。这也是preempt_disable()不关闭IRQ的原因。
  4. 你可以看到什么是preempt_disable()。试试这个: 1.获得一个旋锁。 2.通话时间表()

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

    祝你好运。

答案 1 :(得分:2)

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

1 - 使用local_irq_save()

2 - 使用spin_lock_irqsave()

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

在所有3个案例中,我仍然可以使用hrtimer来测量时间,即使IRQ被禁用(我正在监视的任务也被抢占)。

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

Linux内核2.6.32在单核,单CPU上......任何人都可以有更好的解释吗?

答案 2 :(得分:0)

  1. preempt_disable()不会禁用中断。但是,它会增加抢占计数器的计数。假设您在代码路径中调用preempt_disable() n次,则抢占将仅在第n个preempt_enable()处启用。
  2. 禁用中断以防止抢占:这不是安全的方法。毫无疑问,这将禁用正常的内核抢占,因为不会在系统运行时调用scheduler_tick()(不调用中断处理程序)。但是,如果程序触发了调度功能,则如果未调用preempt_disable(),则会发生抢占。
  3. 在Linux中,raw_spin_lock()不会禁用可能导致死锁的本地中断。例如,如果调用了一个中断处理程序试图锁定已经持有的自旋锁,则除非进程本身释放了它,否则将无法执行该操作,因为不会发生中断返回。 因此,最好使用raw_spin_lock_irq()来禁用中断。

答案 3 :(得分:0)

禁用中断会禁用某些形式的内核抢占,但是还有其他方式可以发生内核抢占。因此,禁用中断不是防止内核抢占的安全方法。

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

这就是为什么关于第二个问题,自旋锁不使用中断禁用来禁用抢占的原因。他们显式调用preempt_disable(),从而增加preempt_count的数量,并禁用除对schedule()的显式调用以外的所有可能发生的抢占方式。