我敢肯定有一个很好的理由,但是我看不出它是什么。__handle_irq_event_percpu
内核内部遍历为特定IRQ行注册的所有处理程序,并对其进行调用。我不明白的是为什么在到达第一个处理程序返回时没有退出此循环IRQ_HANDLED
?这似乎是一个简单的性能改进,因此必须有一些我不理解的地方。
有人知道为什么吗?
在Linux源代码树中,__ handle_irq_event_percpu()位于kernel / irq / handle.c中:
irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags)
{
irqreturn_t retval = IRQ_NONE;
unsigned int irq = desc->irq_data.irq;
struct irqaction *action;
record_irq_time(desc);
for_each_action_of_desc(desc, action) {
irqreturn_t res;
trace_irq_handler_entry(irq, action);
res = action->handler(irq, action->dev_id);
trace_irq_handler_exit(irq, action, res);
if (WARN_ONCE(!irqs_disabled(),"irq %u handler %pS enabled interrupts\n",
irq, action->handler))
local_irq_disable();
switch (res) {
case IRQ_WAKE_THREAD:
/*
* Catch drivers which return WAKE_THREAD but
* did not set up a thread function
*/
if (unlikely(!action->thread_fn)) {
warn_no_thread(irq, action);
break;
}
__irq_wake_thread(desc, action);
/* Fall through - to add to randomness */
case IRQ_HANDLED:
*flags |= action->flags;
break;
default:
break;
}
retval |= res;
}
return retval;
}
该for_each_action_of_desc(DESC,动作)在IRQ描述符的动作列表宏游记:
#define for_each_action_of_desc(desc, act) \
for (act = desc->action; act; act = act->next)
[...]
struct irq_desc {
struct irq_common_data irq_common_data;
struct irq_data irq_data;
unsigned int __percpu *kstat_irqs;
irq_flow_handler_t handle_irq;
struct irqaction *action; /* IRQ action list */
[...]
struct irqaction {
irq_handler_t handler;
void *dev_id;
void __percpu *percpu_dev_id;
struct irqaction *next;
irq_handler_t thread_fn;
struct task_struct *thread;
struct irqaction *secondary;
unsigned int irq;
unsigned int flags;
unsigned long thread_flags;
unsigned long thread_mask;
const char *name;
struct proc_dir_entry *dir;
} ____cacheline_internodealigned_in_smp;
如果中断线由多个设备共享,则动作列表中有多个条目。因此,几个设备可能会同时进入中断状态。因此,将为共享线路的所有设备调用该操作,以检查是否有事情要做。
注意:
因此,请再次重申:如果先前的中断仍在处理中,则可能会从同一设备错过同一条线上的另一个中断。那讲得通。