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;
複製代碼
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章