中断线程化的注册

来源:互联网 发布:福建网络安全教育 编辑:程序博客网 时间:2024/06/13 07:52
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_threadstatic intsetup_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_FIFOsched_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;  }