中断六

继续分析asm_do_IRQ里的irq_exit

/kernel/softirq.c

/*
 * Exit an interrupt context. Process softirqs if needed and possible:
 */
void irq_exit(void)
{
        account_system_vtime(current); //空函数include/linux/hardirq.h

        trace_hardirq_exit();  //中断上下文切换
        sub_preempt_count(IRQ_EXIT_OFFSET);
        if (!in_interrupt() && local_softirq_pending())  //判断是否有硬件中断里,如果不是,判断是否有软件中断需要执行
                invoke_softirq();

#ifdef CONFIG_NO_HZ
        /* Make sure that timer wheel updates are propagated */
        rcu_irq_exit();
        if (idle_cpu(smp_processor_id()) && !in_interrupt() && !need_resched())
                tick_nohz_stop_sched_tick(0);
#endif
        preempt_enable_no_resched();
}

./include/linux/irqflags.h:

# define trace_hardirq_exit()        do { current->hardirq_context--; } while (0)


/kernel/softirq.c

#ifdef __ARCH_IRQ_EXIT_IRQS_DISABLED
# define invoke_softirq()       __do_softirq()
#else
# define invoke_softirq()       do_softirq()
#endif

asmlinkage void do_softirq(void)
{
        __u32 pending;
        unsigned long flags;

        if (in_interrupt())
                return;

        local_irq_save(flags);

        pending = local_softirq_pending();

        if (pending)
                __do_softirq();

        local_irq_restore(flags);
}

#define MAX_SOFTIRQ_RESTART 10  //执行的循环次数,即软中断个数

asmlinkage void __do_softirq(void)
{
        struct softirq_action *h;
        __u32 pending;
        int max_restart = MAX_SOFTIRQ_RESTART;
        int cpu;

        pending = local_softirq_pending();
        account_system_vtime(current);

        __local_bh_disable((unsigned long)__builtin_return_address(0));
        lockdep_softirq_enter();

        cpu = smp_processor_id();
restart:
        /* Reset the pending bitmask before enabling irqs */
        set_softirq_pending(0);

        local_irq_enable();

        h = softirq_vec;     //此定义了软中断将要执行的函数,包括TIMER  TASKLET HIxxxx的 在open_softirq中将其赋值了目前发现有三个地方,一个是时钟那里init_timers,另外两个是中断出事化那里

        do {
                if (pending & 1) {
                        int prev_count = preempt_count();
                        kstat_incr_softirqs_this_cpu(h - softirq_vec);

                        trace_softirq_entry(h, softirq_vec);
                        h->action(h);   //调用了open_softirq里的软中断执行函数
                        trace_softirq_exit(h, softirq_vec);
                        if (unlikely(prev_count != preempt_count())) {
                                printk(KERN_ERR "huh, entered softirq %td %s %p"
                                       "with preempt_count %08x,"
                                       " exited with %08x?\n", h - softirq_vec,
                                       softirq_to_name[h - softirq_vec],
                                       h->action, prev_count, preempt_count());
                                preempt_count() = prev_count;
                        }

                        rcu_bh_qsctr_inc(cpu);
                }

                h++;
                pending >>= 1;
        } while (pending);

        local_irq_disable();

        pending = local_softirq_pending();
        if (pending && --max_restart)
                goto restart;

        if (pending)
                wakeup_softirqd();

        lockdep_softirq_exit();

        account_system_vtime(current);
        _local_bh_enable();
}

kernel/softirq.c

void __init softirq_init(void)

{

................................

        open_softirq(TASKLET_SOFTIRQ, tasklet_action);
        open_softirq(HI_SOFTIRQ, tasklet_hi_action);

}

kernel/softirq.c

static void tasklet_action(struct softirq_action *a)
{
        struct tasklet_struct *list;

        local_irq_disable();
        list = __get_cpu_var(tasklet_vec).head;
        __get_cpu_var(tasklet_vec).head = NULL;
        __get_cpu_var(tasklet_vec).tail = &__get_cpu_var(tasklet_vec).head;
        local_irq_enable();

        while (list) {
                struct tasklet_struct *t = list;

                list = list->next;   //整个tasklet_struct链表遍历

                if (tasklet_trylock(t)) {
                        if (!atomic_read(&t->count)) {
                                if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
                                        BUG();
                                t->func(t->data);  //执行函数
                                tasklet_unlock(t);
                                continue;

                        }
                        tasklet_unlock(t);
                }

                local_irq_disable();
                t->next = NULL;
                *__get_cpu_var(tasklet_vec).tail = t;
                __get_cpu_var(tasklet_vec).tail = &(t->next);
                __raise_softirq_irqoff(TASKLET_SOFTIRQ);
                local_irq_enable();
        }
}

static void tasklet_hi_action(struct softirq_action *a)
{
        struct tasklet_struct *list;

        local_irq_disable();
        list = __get_cpu_var(tasklet_hi_vec).head;
        __get_cpu_var(tasklet_hi_vec).head = NULL;
        __get_cpu_var(tasklet_hi_vec).tail = &__get_cpu_var(tasklet_hi_vec).head;
        local_irq_enable();

        while (list) {
                struct tasklet_struct *t = list;

                list = list->next;  //遍历链表

                if (tasklet_trylock(t)) {
                        if (!atomic_read(&t->count)) {
                                if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
                                        BUG();
                                t->func(t->data);  //执行函数

                                tasklet_unlock(t);
                                continue;
                        }
                        tasklet_unlock(t);
                }

                local_irq_disable();
                t->next = NULL;
                *__get_cpu_var(tasklet_hi_vec).tail = t;
                __get_cpu_var(tasklet_hi_vec).tail = &(t->next);
                __raise_softirq_irqoff(HI_SOFTIRQ);
                local_irq_enable();
        }
}

 

 

 

 

 

 

 

 


 

 

你可能感兴趣的:(中断六)