softirq
軟中斷支持SMP,同一個 softirq 可以在不同的CPU上同時運行,softirq 必須是可重入的。
軟中斷是在編譯期間靜態分配的,它不像 tasklet 那樣能被動態的註冊或去除。
kernel/softirq.c中定義了一個包含 32 個 softirq_action結構體的數組。每個被註冊的軟中斷都佔據該數組的一項。因此最多可能有32個軟中斷。
2.6版本的內核中定義了六個軟中斷:HI_SOFTIRQ、TIMER_SOFTIRQ、NET_TX_SOFTIRQ、NET_RX_SOFTIRQ、SCSI_SOFTIRQ、TASKLET_SOFTIRQ。
軟中斷的特性:
1).一個軟中斷不會搶佔另外一個軟中斷。
2).唯一可以搶佔軟中斷的是中斷處理程序。
3).其他軟中斷(包括相同類型的)可以在其他的處理其上同時執行。
4).一個註冊的軟中斷必須在被標記後才能執行。
5).軟中斷不可以自己休眠(即調用可阻塞的函數或sleep等)。
6).索引號小的軟中斷在索引號大的軟中斷之前執行。
tasklet
引入tasklet,最主要的是考慮支持SMP,提高SMP多個cpu的利用率;兩個相同的tasklet決不會同時執行。
tasklet可以理解爲softirq的派生,所以它的調度時機和軟中斷一樣。對於內核中需要延遲執行的多數任務都可以用tasklet來完成,由於同類tasklet本身已經進行了同步保護,所以使用tasklet比軟中斷要簡單的多,而且效率也不錯。tasklet把任務延遲到安全時間執行的一種方式,在中斷期間運行,即使被調度多次,tasklet也只運行一次,不過tasklet可以在SMP系統上和其他不同的tasklet並行運行。在SMP系統上,tasklet還被確保在第一個調度它的CPU上運行,因爲這樣可以提供更好的高速緩存行爲,從而提高性能。
tasklet的特性:.不允許兩個兩個相同類型的tasklet同時執行,即使在不同的處理器上。
work queue
如果推後執行的任務需要睡眠,那麼就選擇工作隊列。另外,如果需要用一個可以重新調度的實體來執行你的下半部處理,也應該使用工作隊列。它是唯一能在進程上下文運行的下半部實現的機制,也只有它纔可以睡眠。這意味着在需要獲得大量的內存時、在需要獲取信號量時,在需要執行阻塞式的I/O操作時,它都會非常有用。
work queue造成的開銷最大,因爲它要涉及到內核線程甚至是上下文切換。這並不是說work queue的低效,但每秒鐘有數千次中斷,就像網絡子系統時常經歷的那樣,那麼採用其他的機制可能更合適一些。 儘管如此,針對大部分情況工作隊列都能提供足夠的支持。
工作隊列特性:
1).工作隊列會在進程上下文中執行!
2).可以阻塞。(前兩種機制是不可以阻塞的)
3).可以被重新調度。(前兩種只可以被中斷處理程序打斷)
4).使用工作隊列的兩種形式:
1>缺省工作者線程(works threads)
2>自建的工作者線程
5).在工作隊列和內核其他部分之間使用鎖機制就像在其他的進程上下文一樣。
6).默認允許響應中斷。
7).默認不持有任何鎖。
4、softirq和tasklet共同點
軟中斷和tasklet都是運行在中斷上下文中,它們與任一進程無關,沒有支持的進程完成重新調度。所以軟中斷和tasklet不能睡眠、不能阻塞,它們的代碼中不能含有導致睡眠的動作,如減少信號量、從用戶空間拷貝數據或手工分配內存等。也正是由於它們運行在中斷上下文中,所以它們在同一個CPU上的執行是串行的,這樣就不利於實時多媒體任務的優先處理。
Bottom Half 機制比較表
Bottom Half | 執行環境 | 序列執行 |
---|---|---|
Softirq | 中斷環境 | 無 |
Tasklet | 中斷環境 | 同類型不同同時執行 |
Work queues | 程序環境 | 無 |
簡單地說,一般的驅動程序的編寫者需要做兩個選擇。 首先,你是不是需要一個可調度的實體來執行需要推後完成的工作――從根本上來說,有休眠的需要嗎?要是有,工作隊列就是你的惟一選擇。 否則最好用tasklet。要是必須專注於性能的提高,那麼就考慮softirq。
Bottom Halves 間的同步鎖定
Tasklets 的一大優點就是:
在系統的其他處理上,相同的 tasklets 也不能同時執行。所以後不用擔心相同 tasklet 的並行問題。但是不同的 tasklets 間卻有可能共享資料,就必須引入適當的同步鎖定才行。
softirqs 完全沒有序列執行的限制,相同的 softirq 可以同時執行,所有共享的資料都需要適當的保護。
暫停 Buttom Halves 運作
單是暫停 bottom halves 運作,還不足以提供資料保護。通常,還必須加上抓取同步鎖的動作,才能確保資料無誤。
驅動程式需要同時執行這兩種動作。
要暫停所有 bottom halves 的運作。
函式 | 說明 |
---|---|
void local_bh_disable() | 在當前處理器上禁用 softirq 與 tasklet 處理 |
void local_bh_enable() | 在當前處理器上啟用 softirq 與 tasklet 處理 |
這兩個函式允許巢狀呼叫
只有在最後一個對應的 local_bh_enable() 呼叫可以打開先前關閉的後段處理。
這些函式藉操作一個 per-task 計數值 preempt_count 達成這個功能。當計數值變成零時,後段處理才可以進行。
因為執行 local_bh_enable() 前 bottom halves 處理暫停狀態,所以呼叫後也會順便檢查,並執行尚在等待中的推遲作業。
注意:
這類呼叫不會關閉 work queues 的執行。因為 work queues 執行於程序環境,不會引起非同步執行問題,所以不用關閉它。因為 softirqs 與 tasklets 都不時的啟動 (如中斷處理程式返回時),核心必須能適時暫停這些機制。
No comments:
Post a Comment