- 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);
-
}