Linux内核中断处理程序互斥保护?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6570419/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Linux kernel interrupt handler mutex protection?
提问by Ian Vaughan
Do I need to protect my interrupt handler being called many times for the same interrupt?
我是否需要保护我的中断处理程序因同一个中断被多次调用?
Given the following code, I am not sure on the system calls I should make. I am getting rare, random dead-locks with this current implementation :-
鉴于以下代码,我不确定应该进行哪些系统调用。我在当前的实现中遇到了罕见的随机死锁:-
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(...);
}
- Should
interrupt_handler
:down_interruptible
bespin_lock_irq
/spin_lock_irqsave
/local_irq_disable
? - Should
set/clear_intr
:spin_lock_irq
bespin_lock_irqsave
/local_irq_disable
? - Can it (H/W -> kernel -> driver handler) keep generating/getting interrupts until its cleared? Can the
interrupt_handler
keep getting called while within it? - If as currently implemented the interrupt handler is reentrant then will it block on the
down_interruptible
?
- 应该
interrupt_handler
:down_interruptible
是spin_lock_irq
/spin_lock_irqsave
/local_irq_disable
? - 应该
set/clear_intr
:spin_lock_irq
是spin_lock_irqsave
/local_irq_disable
? - 它(硬件 -> 内核 -> 驱动程序处理程序)可以一直产生/获取中断直到被清除吗?可以在其中
interrupt_handler
继续被调用吗? - 如果当前实现的中断处理程序是可重入的,那么它会阻塞
down_interruptible
吗?
From LDD3 :-
从 LDD3 :-
must be reentrant—it must be capable of running in more than one context at the same time.
必须是可重入的——它必须能够同时在多个上下文中运行。
Edit 1) after some nice help, suggestions are :-
编辑 1) 经过一些很好的帮助,建议是:-
- remove
down_interruptible
from withininterrupt_handler
- Move
spin_lock_irq
outside set/clear methods (no need forspin_lock_irqsave
you say?) I really don't see the benefit to this?!
down_interruptible
从内部移除interrupt_handler
- 移动
spin_lock_irq
外设置/清除方法(不需要spin_lock_irqsave
你说什么?)我实在看不出效益这个?
Code :-
代码 :-
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...
}
Edit2) After reading some more SO posts : reading Why kernel code/thread executing in interrupt context cannot sleep?which links to Robert Loves article, I read this :
编辑2)阅读更多SO帖子后:阅读为什么在中断上下文中执行的内核代码/线程无法睡眠?链接到 Robert Loves文章,我读到了这个:
some interrupt handlers (known in Linux as fast interrupt handlers) run with all interrupts on the local processor disabled. This is done to ensure that the interrupt handler runs without interruption, as quickly as possible. More so, all interrupt handlers run with their current interrupt line disabled on all processors. This ensures that two interrupt handlers for the same interrupt line do not run concurrently. It also prevents device driver writers from having to handle recursive interrupts, which complicate programming.
一些中断处理程序(在 Linux 中称为快速中断处理程序)在禁用本地处理器上的所有中断的情况下运行。这样做是为了确保中断处理程序尽可能快地无中断地运行。更重要的是,所有中断处理程序都在所有处理器上禁用其当前中断线的情况下运行。这确保同一中断线的两个中断处理程序不会同时运行。它还可以防止设备驱动程序编写者处理递归中断,这会使编程复杂化。
And I have fast interrupts enabled (SA_INTERRUPT)! So no need for mutex/locks/semaphores/spins/waits/sleeps/etc/etc!
而且我启用了快速中断(SA_INTERRUPT)!所以不需要互斥锁/锁/信号量/自旋/等待/睡眠/等/等!
采纳答案by Hasturkun
Don't use semaphores in interrupt context, use spin_lock_irqsave
instead. quoting LDD3:
不要在中断上下文中使用信号量,spin_lock_irqsave
而是使用。引用 LDD3:
If you have a spinlock that can be taken by code that runs in (hardware or software) interrupt context, you must use one of the forms of spin_lock that disables interrupts. Doing otherwise can deadlock the system, sooner or later. If you do not access your lock in a hardware interrupt handler, but you do via software interrupts (in code that runs out of a tasklet, for example, a topic covered in Chapter 7), you can use spin_lock_bh to safely avoid deadlocks while still allowing hardware interrupts to be serviced.
如果您有一个可以被在(硬件或软件)中断上下文中运行的代码获取的自旋锁,您必须使用禁用中断的 spin_lock 形式之一。否则迟早会导致系统死锁。如果您不在硬件中断处理程序中访问您的锁,而是通过软件中断访问您的锁(在用完 tasklet 的代码中,例如,第 7 章中介绍的主题),您可以使用 spin_lock_bh 安全地避免死锁,同时仍然允许服务硬件中断。
As for point 2, make your set_intr
and clear_intr
require the caller to lock the spinlock, otherwise you'll find your code deadlocking. Again from LDD3:
至于第 2 点,让你的set_intr
和clear_intr
要求调用者锁定自旋锁,否则你会发现你的代码死锁。再次来自 LDD3:
To make your locking work properly, you have to write some functions with the assumption that their caller has already acquired the relevant lock(s). Usually, only your internal, static functions can be written in this way; functions called from outside must handle locking explicitly. When you write internal functions that make assumptions about locking, do yourself (and anybody else who works with your code) a favor and document those assumptions explicitly. It can be very hard to come back months later and figure out whether you need to hold a lock to call a particular function or not.
为了使您的锁定正常工作,您必须编写一些函数,并假设它们的调用者已经获得了相关的锁。通常,只有您的内部静态函数才能以这种方式编写;从外部调用的函数必须显式地处理锁定。当您编写对锁定做出假设的内部函数时,请帮您自己(以及使用您的代码的任何其他人)一个忙,并明确记录这些假设。几个月后很难再回来并弄清楚是否需要持有锁来调用特定的函数。
回答by a.saurabh
Use spinlock in interrupt context because you don't want to sleep in interrupt context if you didn't acquired a lock.
在中断上下文中使用自旋锁,因为如果您没有获得锁,您不想在中断上下文中休眠。
回答by preetam
The code you posted does not look like a device driver irq handler. The irq handlers in kernel drivers return irqreturn_t and take in int irq_no, void * data as arguements.
您发布的代码看起来不像设备驱动程序 irq 处理程序。内核驱动程序中的 irq 处理程序返回 irqreturn_t 并接收 int irq_no, void * data 作为参数。
You have also not specified if you are registering a threaded handler or a non threaded handler. A non threaded irq handler cannot have any sleeping calls whether or not you hold any spinlocks. wait_event, mutex, semaphore, etc, are all sleeping calls and must not be used in a non threaded irq handler. You can however, hold a spinlock to prevent interruption to your interrupt handler. This will ensure that maskable irqs and scheduler do not interrupt your irq handler in the middle.
您也没有指定是注册线程处理程序还是非线程处理程序。无论您是否持有任何自旋锁,非线程 irq 处理程序都不能有任何睡眠调用。wait_event、mutex、semaphore 等都是休眠调用,不得在非线程 irq 处理程序中使用。但是,您可以持有自旋锁以防止中断处理程序。这将确保可屏蔽的 irq 和调度程序不会在中间中断您的 irq 处理程序。
In a threaded irq handler, such things as sleeping calls (wait queues, mutex, etc) can be used but are still not recommended.
在线程化 irq 处理程序中,可以使用诸如休眠调用(等待队列、互斥锁等)之类的东西,但仍然不推荐使用。