Linux kernel 当任务正在执行关键部分,但需要在禁用抢占的单处理器系统上调度时会发生什么情况?

Linux kernel 当任务正在执行关键部分,但需要在禁用抢占的单处理器系统上调度时会发生什么情况?,linux-kernel,kernel,scheduling,spinlock,preemption,Linux Kernel,Kernel,Scheduling,Spinlock,Preemption,下面是一个场景。假设内核任务在禁用抢占的单处理器系统上运行。该任务获得旋转锁。现在它正在执行它的关键部分。此时,如果此任务的可用时间片过期,并且必须将其计划出来,该怎么办 spin_lock是否有防止这种情况发生的机制 可以安排吗?如果是,那么关键部分会发生什么情况 它能被IRQ打断吗?(假设已禁用抢占) 这种情况可行吗?换句话说,这种情况会发生吗 从内核代码中,我了解到自旋锁基本上是禁用抢占的单处理器上的nop。准确地说,它所做的只是barrier() 我理解为什么它是一个nop(因为它是一个

下面是一个场景。假设内核任务在禁用抢占的单处理器系统上运行。该任务获得旋转锁。现在它正在执行它的关键部分。此时,如果此任务的可用时间片过期,并且必须将其计划出来,该怎么办

  • spin_lock
    是否有防止这种情况发生的机制
  • 可以安排吗?如果是,那么关键部分会发生什么情况
  • 它能被IRQ打断吗?(假设已禁用抢占)
  • 这种情况可行吗?换句话说,这种情况会发生吗
  • 从内核代码中,我了解到自旋锁基本上是禁用抢占的单处理器上的
    nop
    。准确地说,它所做的只是
    barrier()
    我理解为什么它是一个
    nop
    (因为它是一个单处理器,没有其他任务可以在那一刻处理数据),但我仍然不理解它是如何不间断的(由于IRQ或调度)。 我错过了什么?指向Linux内核代码的指针表明了这一点,这可能非常有用

    我的基本假设是:

    32位Linux内核实际上
    spin_lock()
    在尝试获取锁之前通过调用
    preempt_disable()
    禁用抢占,因此场景1、#2、#3永远不会发生。 从最近的源代码中,最终调用,在调用
    spin\u acquire()
    获取锁之前调用
    preempt\u disable()
    <通常在中断上下文中使用的code>spin\u lock\u irqsave()具有类似的上下文


    关于#3,如果变量在进程/中断上下文之间共享,则应始终使用
    spin\u lock\u irq()/spin\u lock\u irqsave()
    而不是
    spin\u lock()
    ,以避免死锁情况。

    处理时间片过期的机制是计时器中断。中断将设置进程的TIF_需要重新设置标志。当从计时器的中断上下文返回到关键部分时,将检查是否由于TIF_需要_RESCHED标志而抢占进程。因为抢占被禁用,所以不会发生任何事情,它将返回到您的关键部分

    当关键部分结束时,锁的释放将调用preempt_enable()以重新启用抢占。在那一刻,另一项检查是关于是否抢先的。由于设置了TIF_NEEDS_RESCHED标志并且现在启用了抢占,因此进程将被抢占

  • 自旋锁禁用抢占
  • 否,因为已禁用抢占
  • 对。有一些自旋锁版本会禁用IRQ以防止出现这种情况
  • 否,因为自旋锁禁用抢占
  • 自旋锁在unitprocessor系统上根本不存在,因为它们没有意义。如果不拥有锁的线程试图获取锁,这意味着拥有锁的线程当前处于休眠状态(只有一个cpu)。所以,没有理由去旋转等待睡着的东西。出于这个原因,在这些情况下,自旋锁被优化为只禁用抢占,这样其他线程就不会触及关键部分