Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2000317
  • 博文数量: 369
  • 博客积分: 10093
  • 博客等级: 上将
  • 技术积分: 4271
  • 用 户 组: 普通用户
  • 注册时间: 2005-03-21 00:59
文章分类

全部博文(369)

文章存档

2013年(1)

2011年(2)

2010年(10)

2009年(16)

2008年(33)

2007年(146)

2006年(160)

2005年(1)

分类: LINUX

2006-08-15 10:48:29

File:kernel/softirq.c
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();

阅读(3228) | 评论(1) | 转发(0) |
0

上一篇:NONE

下一篇:Waiting Bar

给主人留下些什么吧!~~

chinaunix网友2008-08-20 10:49:09

沙发~~!!