【问题标题】:Inherent race condition in Linux IRQ handlersLinux IRQ 处理程序中的固有竞争条件
【发布时间】:2015-12-03 02:57:14
【问题描述】:

假设有一个端口映射的 I/O 设备在 IRQ 线上任意产生中断。可以通过对特定寄存器的单个 outb 调用来清除设备的挂起中断。

此外,假设后续中断处理程序通过request_irq分配给相关的IRQ行:

irqreturn_t handler(int irq, void *data)
{
        /* clear pending IRQ on device */
        outb(0, CLEAR_IRQ_REGISTER_ADDR);

        /* device may generate another IRQ at this point,
         * but this handler function has not yet returned */

        /* signal kernel that IRQ has been handled */
        return IRQ_HANDLED;
}

此 IRQ 处理程序中是否存在固有的竞争条件?例如,如果设备在“清除 IRQ”outb 调用之后,但在handler 函数返回IRQ_HANDLED 之前产生了另一个中断,会发生什么?

我能想到三种情况:

  1. 由于设备和 Linux 内核之间的死锁,IRQ 行冻结并且无法再处理。
  2. Linux 内核在返回后立即再次执行handler,以处理第二个中断。
  3. Linux 内核中断handler,第二次调用handler

【问题讨论】:

    标签: linux linux-kernel interrupt race-condition interrupt-handling


    【解决方案1】:

    场景 2 是正确的。中断处理程序在本地 CPU 上禁用中断的情况下运行。因此,从您的处理程序返回后,中断控制器将看到另一个中断发生,并且您的处理程序将再次被调用。

    但可能发生的情况是,如果您的速度不够快,您可能会错过一些中断,并且在您仍在处理第一个中断时会发生多个中断。这不应该发生在您的情况下,因为您必须清除挂起的中断。

    安迪的回答是关于另一个问题。您必须锁定对设备和资源的访问权限,因为您的处理程序可能同时在不同的 CPU 上运行。

    【讨论】:

    • 假设我返回IRQ_NONE而不是IRQ_HANDLED:处理程序是否仍会被再次调用,或者这种情况会导致死锁?
    • 如果它不是共享的,或者如果它是共享的并且所有的处理程序都返回IRQ_NONE,它将被再次调用,但可能会被虚假的IRQ处理逻辑禁用一段时间。
    【解决方案2】:

    在 SMP 系统上,显然存在竞争的可能性。中断对于 CPU 来说是本地的,因为它们中的大多数都实现了 LAPIC 控制器。因此,您必须通过临界区同步算法来保护您的数据和设备访问。由于中断上下文,这里最适合的是spin_lock_irqsave()

    【讨论】:

    • 您是说场景#3 的结果是:对处理程序的初始调用在第一次调用返回之前被对同一处理程序的第二次调用中断?
    • This question about spin_lock_irqspin_lock_irqsave 帮助我理解了这个话题。
    • @izzy 对不起,我没有完全按照。我担心在 IRQ 处理函数中执行了所有 I/O 操作之后发生的死锁。因此我不相信自旋锁会解决这个问题,因为它们只会跨越 handler 函数。换句话说:spin_unlock_irq 调用将固有地发生在 return IRQ_HANDLED 行之前,因此仍然可能存在竞争条件。
    猜你喜欢
    • 2014-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-23
    • 2011-09-23
    • 2012-04-15
    • 1970-01-01
    • 2011-04-01
    相关资源
    最近更新 更多