- asmlinkage void __do_softirq(void)
- {
- struct softirq_action *h;
- __u32 pending;
- int max_restart = MAX_SOFTIRQ_RESTART;
- int cpu;
/* 取得软中断的pending状态 */
- pending = local_softirq_pending();
- account_system_vtime(current);
/* disable BH */
- __local_bh_disable((unsigned long)__builtin_return_address(0),
- SOFTIRQ_OFFSET);
- lockdep_softirq_enter();
- cpu = smp_processor_id();
- restart:
- /* Reset the pending bitmask before enabling irqs */
- /*
- 将pending的软中断标志清零。
- 做这个操作时需要在关中断的情况下,因为中断会设置这个标志
- */
- set_softirq_pending(0);
/* enable中断 */
- local_irq_enable();
- h = softirq_vec;
/* 按位检测,处理所有的pending的软中断 */
- do {
- if (pending & 1) {
- unsigned int vec_nr = h - softirq_vec;
- int prev_count = preempt_count();
- kstat_incr_softirqs_this_cpu(vec_nr);
- trace_softirq_entry(vec_nr);
- /* 调用对应的软中断处理函数 */
- h->action(h);
- trace_softirq_exit(vec_nr);
- if (unlikely(prev_count != preempt_count())) {
- printk(KERN_ERR "huh, entered softirq %u %s %p"
- "with preempt_count %08x,"
- " exited with %08x?\n", vec_nr,
- softirq_to_name[vec_nr], h->action,
- prev_count, preempt_count());
- preempt_count() = prev_count;
- }
- rcu_bh_qs(cpu);
- }
- h++;
- pending >>= 1;
- } while (pending);
/* 再关中断 */
- local_irq_disable();
/* 再检查pending的软中断,因为在之前的处理软中断的过程中,很可能发生了新的中断,并设置了新的软中断标志位,所以需要再次检查 */
- pending = local_softirq_pending();
- /*
- 如果有了新的pending并且没有超过最多的循环限制,那么就继续处理软中断。
- 之所以要加一个最多的循环处理限制,因为在网络负载比较大的环境,网卡会产生很多软中断。如果没有循环,那么kernel就把大部分时间集中在软中断处理上,而无法处理其他工作。
- */
- if (pending && --max_restart)
- goto restart;
/* 还有软中断剩下没有处理,那么就唤醒softirqd去处理剩下的软中断 */
- if (pending)
- wakeup_softirqd();
- lockdep_softirq_exit();
- account_system_vtime(current);
- /* enable BH*/
- __local_bh_enable(SOFTIRQ_OFFSET);
- }