devm_request_threaded_irq->request_threaded_irq->__setup_irq 中的下面这段code中可以看到中断线程化设置的过程
/*
* Create a handler thread when a thread function is supplied
* and the interrupt does not nest into another interrupt
* thread.
*/
//if条件成立,所以继续调用setup_irq_thread,从这里看中断线程化其实可以设置两个线程
if (new->thread_fn && !nested) {
ret = setup_irq_thread(new, irq, false);
if (ret)
goto out_mput;
if (new->secondary) {
ret = setup_irq_thread(new->secondary, irq, true);
if (ret)
goto out_thread;
}
}
这里继续看setup_irq_thread
static int
setup_irq_thread(struct irqaction *new, unsigned int irq, bool secondary)
{
struct task_struct *t;
struct sched_param param = {
.sched_priority = MAX_USER_RT_PRIO/2,
};
//这里假定secondary为null,因此调用kthread_create 创建一个thread.
if (!secondary) {
t = kthread_create(irq_thread, new, "irq/%d-%s", irq,
new->name);
} else {
t = kthread_create(irq_thread, new, "irq/%d-s-%s", irq,
new->name);
param.sched_priority -= 1;
}
if (IS_ERR(t))
return PTR_ERR(t);
//haha 从这里可以看出这个thread的调度策略是SCHED_FIFO
sched_setscheduler_nocheck(t, SCHED_FIFO, ¶m);
/*
* We keep the reference to the task struct even if
* the thread dies to avoid that the interrupt code
* references an already freed task_struct.
*/
get_task_struct(t);
new->thread = t;
/*
* Tell the thread to set its affinity. This is
* important for shared interrupt handlers as we do
* not invoke setup_affinity() for the secondary
* handlers as everything is already set up. Even for
* interrupts marked with IRQF_NO_BALANCE this is
* correct as we want the thread to move to the cpu(s)
* on which the requesting code placed the interrupt.
*/
set_bit(IRQTF_AFFINITY, &new->thread_flags);
return 0;
}
注意这里只是创建thread ,这时候thread并没有运行,知道irq的回调函数返回IRQ_WAKE_THREAD的时候,才会通过__irq_wake_thread 来运行这个thread
最终处理中断的函数为
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);
//这里会执行irq的回调函数,可以看到只有这里返回IRQ_WAKE_THREAD,才会调用__irq_wake_thread 来运行中断的线程
res = action->handler(irq, action->dev_id);
trace_irq_handler_exit(irq, action, res);
if (WARN_ONCE(!irqs_disabled(),"irq %u handler %pF 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->wake_up_process 来wakeup在调用devm_request_threaded_irq时候为线程建立的thread
__irq_wake_thread(desc, action);
/* Fall through to add to randomness */
case IRQ_HANDLED:
*flags |= action->flags;
break;
default:
break;
}
retval |= res;
}
return retval;
}
中断线程化的注册
最新推荐文章于 2024-12-20 09:30:00 发布