中斷下半部的三種機制

FreeeLinux發表於2017-01-09


之前提到過,之所以中斷會分成上下兩部分,Linux 的上半部就是中斷處理程式,下半部採用三種機制來實現,這樣分兩部執行的策略有利於縮短響應硬體的時限。

中斷下半部的處理


對於一箇中斷,如何劃分出上下兩部分呢?哪些處理放在上半步,哪些放在下半部?
這裡有一些經驗可供借鑑:

  1. 如果一個任務對時間十分敏感,將其放在上半部。
  2. 如果一個任務和硬體有關,將其放在上半部。
  3. 如果一個任務要保證不被其他中斷打斷,將其放在上半部。
  4. 其他所有任務,考慮放在下半部。

實現下半部中斷的三種機制


目前使用下面三種方法:

  1. 軟中斷
  2. tasklet
  3. 工作佇列

軟中斷

軟中斷是一組靜態定義的下半部介面,有 32 個,可以在所有處理器上同時執行,型別相同也可以;在編譯時靜態註冊。

軟中斷的流程如下:

Created with Raphaël 2.1.0註冊軟中斷 open_softirq觸發軟中斷 raise_softirq執行軟中斷 do_softirq是否還有未執行的中斷函式執行相應的軟中斷結束本次中斷yesno

軟中斷執行函式如下:

asmlinkage void do_softirq(void)
{
    __u32 pending;
    unsigned long flags;

    /* 判斷是否在中斷處理中,如果正在中斷處理,就直接返回 */
    if (in_interrupt())
        return;

    /* 儲存當前暫存器的值 */
    local_irq_save(flags);

    /* 取得當前已註冊軟中斷的點陣圖 */
    pending = local_softirq_pending();

    /* 迴圈處理所有已註冊的軟中斷 */
    if (pending)
        __do_softirq();

    /* 恢復暫存器的值到中斷處理前 */
    local_irq_restore(flags);
}

程式碼之中第一次就判斷是否在中斷處理中,如果在立刻退出函式。這說明了什麼?說明了如果有其他軟中斷觸發,執行到此處由於先前的軟中斷已經在處理,則其他軟中斷會返回。所以,軟中斷不能被另外一個軟中斷搶佔唯一可以搶佔軟中斷的是中斷處理程式,所以軟中斷允許響應中斷。雖然不能在本處理器上搶佔,但是其他的軟中斷甚至同型別可以再其他處理器上同時執行。由於這點,所以對臨界區需要加鎖保護。

軟中斷留給對時間要求最嚴格的下半部使用。目前只有網路,核心定時器和 tasklet 建立在軟中斷上。

Tasklet


注意,這第二種機制是基於軟中斷實現的,靈活性強,動態建立的下半部實現機制。兩個不同型別的 tasklet 可以在不同處理器上執行,但相同的不可以,可以通過程式碼動態註冊。

在 SMP 上,呼叫 tasklet 是會檢測 TASKLET_STATE_SCHED 標誌,如果同型別在執行,就退出函式。

tasklet 由於是基於軟中斷實現的,所以也允許響應中斷。但不能睡眠(我認為不能睡眠原因是它們內部有 spin lock)。

工作佇列


將下半部功能交由核心執行緒執行,有著執行緒上下文環境,可以睡眠。
提供介面把需要推後執行的任務排列到佇列裡,提供預設的工作者執行緒處理排到佇列裡的下半部工作。

工作佇列實際上是一個連結串列,工作執行緒作為死迴圈,連結串列空時休眠,不空是執行每一個工作。

各種機制的比較

下半部 上下文 順序執行保障
軟中斷 中斷 隨意,同型別都可以在不同處理器同時執行
tasklet 中斷 同型別不能同時執行
工作佇列 程式 不保障,可能被排程和搶佔


選擇:
- 工作佇列:適用於任務推後到程式上下文完成,可以休眠
- tasklet:任務介面簡單,支援中斷響應,但有同種型別不能同時執行的限制
- 軟中斷:提供的執行順序保障最少,支援中斷響應,由於同型別軟中斷在其他處理器可同時執行,所以要採取措施保護共享資料。

相關文章