Linux IRQ 处理程序中的固有竞争条件

Inherent race condition in Linux IRQ handlers

假设有一个端口映射 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 处理程序中是否存在固有的竞争条件?例如,如果设备在 "clear IRQ" outb 调用之后但在 handler 函数 returns IRQ_HANDLED 之前生成另一个中断,会发生什么情况?

我能想到三种情况:

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

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

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

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

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