synchronize_irq()分析

       大家知道,中断处理目前一般会为上半部和下半部,上半部为硬中断处理,下半部一般为软中断、tasklet或workqueue来处理。同时内核中为了提高实时性,推出中断线程化,即下半部用中断线程处理(每个中断一个中断线程)。synchronize_irq()用于等待PENDING状态的中断处理函数结束(中断处理包括硬中断的处理以及中断线程的处理)。

synchronize_irq()函数如下所示:

/**
 *    synchronize_irq - wait for pending IRQ handlers (on other CPUs)
 *    @irq: interrupt number to wait for
 *
 *    This function waits for any pending IRQ handlers for this interrupt
 *    to complete before returning. If you use this function while
 *    holding a resource the IRQ handler may need you will deadlock.
 *
 *    This function may be called - with care - from IRQ context.
 */
void synchronize_irq(unsigned int irq)
{
    struct irq_desc *desc = irq_to_desc(irq); //获取中断描述符

    if (desc) {
        __synchronize_hardirq(desc); //等待硬中断处理结束
        /*
         * We made sure that no hardirq handler is
         * running. Now verify that no threaded handlers are
         * active.
         */
        wait_event(desc->wait_for_threads,
               !atomic_read(&desc->threads_active)); //等待中断线程处理结束
    }
}
EXPORT_SYMBOL(synchronize_irq);

等待硬中断处理

其中 __synchronize_hardirq()函数用于等待硬中断的处理完成,在函数handle_irq_event()中处理硬中断之前设置IRQD_IRQ_INPROGRESS,在处理完成后清IRQD_IRQ_INPROGRESS。 __synchronize_hardirq()检查IRQD_IRQ_INPROGRESS是否清除。

static void __synchronize_hardirq(struct irq_desc *desc)
{
    bool inprogress;

    do {
        unsigned long flags;

        /*
         * Wait until we're out of the critical section.  This might
         * give the wrong answer due to the lack of memory barriers.
         */
        while (irqd_irq_inprogress(&desc->irq_data))
            cpu_relax();

        /* Ok, that indicated we're done: double-check carefully. */
        raw_spin_lock_irqsave(&desc->lock, flags);
        inprogress = irqd_irq_inprogress(&desc->irq_data);
        raw_spin_unlock_irqrestore(&desc->lock, flags);

        /* Oops, that failed? */
    } while (inprogress);
}
其中
static inline bool irqd_irq_inprogress(struct irq_data *d)
{
    return __irqd_to_state(d) & IRQD_IRQ_INPROGRESS;
}

而该flag的设置在 函数handle_irq_event()中
irqreturn_t handle_irq_event(struct irq_desc *desc)
{
    irqreturn_t ret;

    desc->istate &= ~IRQS_PENDING;
    irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS); //设置IRQD_IRQ_INPROGRESS
    raw_spin_unlock(&desc->lock);

    ret = handle_irq_event_percpu(desc);

    raw_spin_lock(&desc->lock);
    irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS); //结束hardirq处理,清IRQD_IRQ_INPROGRESS
    return ret;
}

等待中断线程处理

       等待中断线程的处理完成通过等待队列完成,在申请中断时对每个中断中中断描述符的desc->wait_for_threads进行初始化(在函数__set_irq()中):

在中断线程irq_thread()完成后唤醒等待队列:

/*
 * Interrupt handler thread
 */
static int irq_thread(void *data)
{
    struct callback_head on_exit_work;
    struct irqaction *action = data;
    struct irq_desc *desc = irq_to_desc(action->irq);
    irqreturn_t (*handler_fn)(struct irq_desc *desc,
            struct irqaction *action);

    if (force_irqthreads && test_bit(IRQTF_FORCED_THREAD,
                    &action->thread_flags))
        handler_fn = irq_forced_thread_fn;
    else
        handler_fn = irq_thread_fn; //设置中断线程处理handler

    init_task_work(&on_exit_work, irq_thread_dtor);
    task_work_add(current, &on_exit_work, false);

    irq_thread_check_affinity(desc, action); //设置中断线程CPU亲和性即中断线程跑在哪些CPU上,继承于中断的亲和性

    while (!irq_wait_for_interrupt(action)) {
        irqreturn_t action_ret;

        irq_thread_check_affinity(desc, action);

        action_ret = handler_fn(desc, action);
        if (action_ret == IRQ_WAKE_THREAD)
            irq_wake_secondary(desc, action);

        wake_threads_waitq(desc); //唤醒等待队列
    }
    /*
     * This is the regular exit path. __free_irq() is stopping the
     * thread via kthread_stop() after calling
     * synchronize_hardirq(). So neither IRQTF_RUNTHREAD nor the
     * oneshot mask bit can be set.
     */
    task_work_cancel(current, irq_thread_dtor);
    return 0;
}

static void wake_threads_waitq(struct irq_desc *desc)
{
    if (atomic_dec_and_test(&desc->threads_active))
        wake_up(&desc->wait_for_threads);
}

 

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值