软中断知识

来源:互联网 发布:十堰房产每日成交数据 编辑:程序博客网 时间:2024/06/03 23:39

参考:http://blog.csdn.net/yiyeguzhou100/article/details/49909787
http://blog.csdn.net/adaptiver/article/details/6177646
http://yaoyang.blog.51cto.com/7657153/1261841
在说软中断前,先说一下preempt_count()

thread_info中的成员preempt_count,它是一个32位的字段,分为几个部分,:
0-7位: 抢占计数器, 最大值255
8-15位: 软中断计数器, 最大值255
16-27位: 硬中断计数器, 最大值4096
28位: PREEMPT_ACTIVE标志

因此,在hardirq.h中定义了几个宏:

#define PREEMPT_BITS    8#define SOFTIRQ_BITS    8#define HARDIRQ_BITS    12#define PREEMPT_SHIFT    0#define SOFTIRQ_SHIFT    (PREEMPT_SHIFT + PREEMPT_BITS)#define HARDIRQ_SHIFT    (SOFTIRQ_SHIFT + SOFTIRQ_BITS)#define PREEMPT_OFFSET    (1UL << PREEMPT_SHIFT)#define SOFTIRQ_OFFSET    (1UL << SOFTIRQ_SHIFT)#define HARDIRQ_OFFSET    (1UL << HARDIRQ_SHIFT)

因此, 函数调用add_preempt_count(HARDIRQ_OFFSET)是增加其中硬中断的计数.

in_interrupt()–>irq_count()–>(preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK | NMI_MASK))
其中SOFTIRQ_MASK是软中断计数器所在位的全部为1的数。掩码就是全为1,如PREEMPT_BITS的掩码为11111111。

如:在中断退出时irq_exit有:

void irq_exit(void){        account_system_vtime(current);        trace_hardirq_exit();        sub_preempt_count(IRQ_EXIT_OFFSET);        if (!in_interrupt() && local_softirq_pending())                       检验是否在软中断或者硬中断中,和检验是否有软中断挂起需要执行                invoke_softirq();        rcu_irq_exit();#ifdef CONFIG_NO_HZ        /* Make sure that timer wheel updates are propagated */        if (idle_cpu(smp_processor_id()) && !in_interrupt() && !need_resched())                tick_nohz_stop_sched_tick(0);#endif        preempt_enable_no_resched();}分析__do_softirq函数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));                       软件抢占计数加1,即屏蔽其他的软中断        lockdep_softirq_enter();                                                                 软中断上下文计数加1        cpu = smp_processor_id();restart:        /* Reset the pending bitmask before enabling irqs */        set_softirq_pending(0);                                                                  先把软中断任务清空        local_irq_enable();        h = softirq_vec;        do {                if (pending & 1) {                                              //这是针对每大类,如:TASKLET_SOFTIRQ  HI_SOFTIRQ等                        int prev_count = preempt_count();                        kstat_incr_softirqs_this_cpu(h - softirq_vec);                        trace_softirq_entry(h, softirq_vec);                        h->action(h);                                                           将一个个软中断提取出来并执行其操作函数                        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_qs(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();                                                    软中断上下文计数减1        account_system_vtime(current);        _local_bh_enable();}
原创粉丝点击