Linux下半部——谁先运行

链接:http://bbs.chinaunix.net/thread-4125504-1-1.html

原问:

看博客有写到:一个软中断不会去抢占另一个软中断。
      个人理解如下:《Linux内核设计与实现》中提到,如果软中断存在共享数据,那么需要进行加锁保护,因为同类型的软中断可以同时在不同的CPU下运行。所以,一个软中断不会去抢占另一个软中断,这句话的是在一个CPU上吧?
       以下内容为个人猜想,不对的地方还请指正。假设硬件中断频繁发生,那么就会挤压了多个下半部(tasklet)在等待处理,这些tasklet应该是以队列的形式存放起来的。空闲的CPU从队列中取出一个tasklet进行处理,所以所有CPU都在处理软中断。 假设在一个CPU上,正在运行软中断A,此时来了一个中断,该中断处理也分为硬中断B和软中断B,硬中断B肯定可以抢占CPU运行。  那么接下来,执行软中断A还是软中断B呢?  是软中断A运行完以后,立即运行B,还是会放入队列当中啊?

6楼回复:

如果你这里的软中断时指softirq的话,那么:

查看了一下代码,流程应该是这样:
1. 当某CPU正在run softirq A,这时来了一个硬件中断,硬件中断打断软件中断;
2. 硬件中断在上半部raise了软中断B的pending标志;
3. 硬件中断运行完毕,call  irq_exit :
  1. void irq_exit(void)
  2. {
  3.         account_system_vtime(current);
  4.         trace_hardirq_exit();
  5.         sub_preempt_count(IRQ_EXIT_OFFSET);
  6.         if (!in_interrupt() && local_softirq_pending())
  7.                 invoke_softirq();

  8.         rcu_irq_exit();
  9. #ifdef CONFIG_NO_HZ
  10.         /* Make sure that timer wheel updates are propagated */
  11.         if (idle_cpu(smp_processor_id()) && !in_interrupt() && !need_resched())
  12.                 tick_nohz_stop_sched_tick(0);
  13. #endif
  14.         preempt_enable_no_resched();
  15. }
复制代码
4. 注意这里的代码:
        if (!in_interrupt() && local_softirq_pending())
                invoke_softirq();
是说如果现在的环境本身就是在中断中(软中断也是在中断环境中),那么!in_interrupt()就会返回false,那么就不会运行invoke_softirq()

5. 硬件中断继续返回到被打断的地方(即先前的softirq A的处理中),kernel继续运行softirq A。
请注意在step 2中kernel已经raise了softirq B的pending位,所以在函数__do_softirq中,会重新check到softirq B的bit,从而运行softirq B的action
  1. restart:
  2.         /* Reset the pending bitmask before enabling irqs */
  3.         set_softirq_pending(0);

  4.         local_irq_enable();

  5.         h = softirq_vec;

  6.         do {
  7.                 if (pending & 1) {
  8.                         int prev_count = preempt_count();
  9.                         kstat_incr_softirqs_this_cpu(h - softirq_vec);

  10.                         trace_softirq_entry(h, softirq_vec);
  11.                         h->action(h);
  12.                         trace_softirq_exit(h, softirq_vec);
  13.                         if (unlikely(prev_count != preempt_count())) {
  14.                                 printk(KERN_ERR "huh, entered softirq %td %s %p"
  15.                                        "with preempt_count %08x,"
  16.                                        " exited with %08x?\n", h - softirq_vec,
  17.                                        softirq_to_name[h - softirq_vec],
  18.                                        h->action, prev_count, preempt_count());
  19.                                 preempt_count() = prev_count;
  20.                         }

  21.                         rcu_bh_qs(cpu);
  22.                 }
  23.                 h++;
  24.                 pending >>= 1;
  25.         } while (pending);

  26.         local_irq_disable();

  27.         pending = local_softirq_pending();
  28.         if (pending && --max_restart)
  29.                 goto restart;
复制代码
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章