分类: LINUX
2006-08-15 10:48:29
165 void irq_exit(void) 166 { 167 account_system_vtime(current); 168 sub_preempt_count(IRQ_EXIT_OFFSET); 169 if (!in_interrupt() && local_softirq_pending()) 170 invoke_softirq(); 如果系统从硬中断回到进程上下文,且当前CPU有未决的软中断,则调用软中断。 171 preempt_enable_no_resched(); 172 } |
117 asmlinkage void do_softirq(void) 118 { 119 __u32 pending; 120 unsigned long flags; 121 122 if (in_interrupt()) 123 return; 检查是否是在中断上下文调用的do_softirq,如果是,则直接退出 124 125 local_irq_save(flags); 关闭当前CPU的中断,这也暗示了,在SMP系统上SoftIRQ可以并发的这个事实。 126 127 pending = local_softirq_pending(); 128 129 if (pending) 130 __do_softirq(); 如果当前CPU上有未决中断,调用__do_softirq() 注意:此时是在关闭了当前CPU的中断前提下进行的 131 132 local_irq_restore(flags); 打开当前CPU的中断 惯例:对任务环境的维护代码,必须放在一个函数中,而不能由子函数代劳,且子函数必须在退出之前,将任务环境恢复到进入此函数之前的状态。 133 } |
64 /* 65 * We restart softirq processing MAX_SOFTIRQ_RESTART times, 66 * and we fall back to softirqd after that. 67 * 68 * This number has been established via experimentation. 69 * The two things to balance is latency against fairness - 70 * we want to handle softirqs as soon as possible, but they 71 * should not be able to lock up the box. 72 */ 73 #define MAX_SOFTIRQ_RESTART 10 74 75 asmlinkage void __do_softirq(void) 76 { 77 struct softirq_action *h; 78 __u32 pending; 79 int max_restart = MAX_SOFTIRQ_RESTART; 80 int cpu; 81 82 pending = local_softirq_pending(); 83 84 local_bh_disable(); 关闭当前CPU的软中断,虽然它这里名在为local_bh_disable(),可实际上叫做local_softirq_disable()可能更加贴切一点,叫前者可能只是因为历史的原因。主要目的是为了防止从硬中断返回后再次进入软中断处理例程,而引起冲突。 85 cpu = smp_processor_id(); 获得当前处理器的id,因为softIRQ是可以在多个cpu上并发的,为了避免锁的使用,用的是perCPU变量,就是为每个CPU分配一个这个CPU私有的数据。 86 restart: 87 /* Reset the pending bitmask before enabling irqs */ 88 set_softirq_pending(0); 因为我们已经决定处理所有的未决软中断,并且在82行已经取得了未决软中断的掩码,所以此处我们可以安全的将当前软中断的掩码归零 89 90 local_irq_enable(); 一些可能和硬中断竞争的操作都做完了,即时的打开硬件中断。这也反映了SoftIRQ的优越性,他是在开中断的条件下运行的。 91 92 h = softirq_vec; 93 94 do { 95 if (pending & 1) { 96 h->action(h); 97 rcu_bh_qsctr_inc(cpu); 98 } 99 h++; 100 pending >>= 1; 101 } while (pending); 按照软中断的优先级顺序执行软中断服务程序。 102 103 local_irq_disable(); 再次进入临界区,主要是这个local_softirq_pending() 104 105 pending = local_softirq_pending(); 106 if (pending && --max_restart) 107 goto restart; 如果在软中断处理期间,又有软中断光临,且没有达到最大软中断重启次数,则重启软中断,将软中断重启次数加一,这里表现为max_restart 减一 108 109 if (pending) 110 wakeup_softirqd(); 如果已经达到了软中断最大重启次数,起用软中断服务后台进程,至于为什么要如此,看前面64行的英文注释,不要告诉我看不懂英文哦~_~ 111 112 __local_bh_enable(); 恢复任务环境。打开软中断。 113 } |
351 static int ksoftirqd(void * __bind_cpu) 352 { 353 set_user_nice(current, 19); 354 current->flags |= PF_NOFREEZE; 355 356 set_current_state(TASK_INTERRUPTIBLE); 357 358 while (!kthread_should_stop()) { 359 preempt_disable(); 360 if (!local_softirq_pending()) { 361 preempt_enable_no_resched(); 362 schedule(); 363 preempt_disable(); 364 } 365 366 __set_current_state(TASK_RUNNING); 367 368 while (local_softirq_pending()) { 369 /* Preempt disable stops cpu going offline. 370 If already offline, we'll be on wrong CPU: 371 don't process */ 372 if (cpu_is_offline((long)__bind_cpu)) 373 goto wait_to_die; 374 do_softirq(); 375 preempt_enable_no_resched(); 376 cond_resched(); 377 preempt_disable(); 378 } 379 preempt_enable(); 380 set_current_state(TASK_INTERRUPTIBLE); 381 } 382 __set_current_state(TASK_RUNNING); 383 return 0; 384 385 wait_to_die: 386 preempt_enable(); 387 /* Wait for kthread_stop */ 388 set_current_state(TASK_INTERRUPTIBLE); 389 while (!kthread_should_stop()) { 390 schedule(); 391 set_current_state(TASK_INTERRUPTIBLE); 392 } 393 __set_current_state(TASK_RUNNING); 394 return 0; 395 } 整个函数的功能比较简单,就是在进程中模拟软中断环境,处理软中断。不过需要特别小心,还好do_softirq都帮我们做了。 |
1 149 kernel/softirq.c < do_softirq(); 2 159 kernel/softirq.c < #define invoke_softirq() do_softirq() 3 374 kernel/softirq.c < do_softirq(); 4 1512 net/core/dev.c < do_softirq(); 5 1860 net/core/pktgen.c < do_softirq(); 6 3039 net/core/pktgen.c < do_softirq(); |