Linux内核中断处理程序互斥保护?

Ian*_*han 13 linux interrupt linux-device-driver linux-kernel

我是否需要保护我的中断处理程序被多次调用同一个中断?

鉴于以下代码,我不确定我应该进行的系统调用.我正在使用当前的实现获得罕见的随机死锁: -

void interrupt_handler(void)
{
    down_interruptible(&sem);  // or use a lock here ?

    clear_intr(); // clear interrupt source on H/W

    wake_up_interruptible(...);

    up(&sem); // unlock?

    return IRQ_HANDLED;
}

void set/clear_intr()
{
    spin_lock_irq(&lock);
    RMW(x); // set/clear a bit by read/modify/write the H/W interrupt routing register
    spin_unlock_irq(&lock);
}

void read()
{
    set_intr();  // same as clear_intr, but sets a bit
    wait_event_interruptible(...);
}
Run Code Online (Sandbox Code Playgroud)
  1. 应该interrupt_handler:down_interruptiblespin_lock_irq/ spin_lock_irqsave/ local_irq_disable
  2. 应该set/clear_intr:spin_lock_irqspin_lock_irqsave/ local_irq_disable
  3. 可以(H/W - >内核 - >驱动程序处理程序)继续生成/获取中断,直到它被清除?interrupt_handler在它内部可以继续被叫吗?
  4. 如果当前实现的中断处理程序是可重入的,那么它会阻塞down_interruptible吗?

来自LDD3: -

必须是可重入的 - 必须能够同时在多个上下文中运行.


编辑1)经过一些很好的帮助,建议是: -

  1. down_interruptible从内部移除interrupt_handler
  2. 移动spin_lock_irq外部设置/清除方法(不需要spin_lock_irqsave你说?)我真的没有看到这个好处?!

代码: -

void interrupt_handler(void)
{
    read_reg(y); // eg of other stuff in the handler

    spin_lock_irq(&lock);

    clear_intr(); // clear interrupt source on H/W

    spin_unlock_irq(&lock);

    wake_up_interruptible(...);

    return IRQ_HANDLED;
}

void set/clear_intr()
{
    RMW(x);
}

void read()
{
    error_checks(); // eg of some other stuff in the read method

    spin_lock_irq(&lock);

    set_intr();  // same as clear_intr, but sets a bit

    spin_unlock_irq(&lock);

    wait_event_interruptible(...);

    // more code here...
}
Run Code Online (Sandbox Code Playgroud)

编辑2)在阅读了更多SO帖子之后:阅读为什么在中断上下文中执行的内核代码/线程无法休眠?链接到Robert Loves的文章,我读到了这个:

某些中断处理程序(在Linux中称为快速中断处理程序)在本地处理器上的所有中断都禁用的情况下运行.这样做是为了确保中断处理程序尽可能快地运行而不会中断.更重要的是,所有中断处理程序在所有处理器上禁用其当前中断线时运行.这可确保同一中断线的两个中断处理程序不会同时运行.它还可以防止设备驱动程序编写者必须处理递归中断,这会使编程变得复杂.

我启用了快速中断(SA_INTERRUPT)!所以不需要互斥锁/锁/信号量/旋转/等待/睡眠/等/等等!

Has*_*kun 12

不要在中断上下文中使用信号量,spin_lock_irqsave而是使用.引用LDD3:

如果您有一个可以由(硬件或软件)中断上下文中运行的代码执行的自旋锁,则必须使用一种禁用中断的spin_lock形式.否则可能会使系统死锁.如果您没有在硬件中断处理程序中访问您的锁,但是您通过软件中断(在代码中运行了一个tasklet,例如,第7章中介绍的主题),您可以使用spin_lock_bh安全地避免死锁允许硬件中断得到服务.

至于第2点,让你的set_intrclear_intr要求调用者锁定自旋锁,否则你会发现你的代码死锁.再次来自LDD3:

为了使您的锁定正常工作,您必须编写一些函数,并假设其调用者已经获取了相关的锁定.通常,只能以这种方式编写内部静态函数; 从外部调用的函数必须显式处理锁定.当您编写对锁定做出假设的内部函数时,请自己(以及与您的代码一起工作的任何其他人)帮忙并明确记录这些假设.几个月之后回来并确定你是否需要持有一个锁以调用特定功能可能非常困难.