linux 軟中斷

轉+原創

中斷服務程序往往都是在CPU關中斷的條件下執行的,以避免中斷嵌套而使控制複雜
化。但是CPU關中斷的時間不能太長,否則容易丟失中斷信號。爲此,Linux將中斷服務
程序一分爲二,各稱作“Top Half”和“Bottom Half”。前者通常對時間要求較爲嚴
格,必須在中斷請求發生後立即或至少在一定的時間限制內完成。因此爲了保證這種處
理能原子地完成,Top Half通常是在CPU關中斷的條件下執行的。具體地說,Top Half的
範圍包括:從在IDT中登記的中斷入口函數一直到驅動程序註冊在中斷服務隊列中的
ISR。而Bottom Half則是Top Half根據需要來調度執行的,這些操作允許延遲到稍後執
行,它的時間要求並不嚴格,因此它通常是在CPU開中斷的條件下執行的。
但是,Linux的這種Bottom Half(以下簡稱BH)機制有兩個缺點,也即:(1)在任
意一時刻,系統只能有一個CPU可以執行Bottom Half代碼,以防止兩個或多個CPU同時來
執行Bottom Half函數而相互干擾。因此BH代碼的執行是嚴格“串行化”的。(2)BH函
數不允許嵌套。
這兩個缺點在單CPU系統中是無關緊要的,但在SMP系統中卻是非常致命的。因爲BH機
制的嚴格串行化執行顯然沒有充分利用SMP系統的多CPU特點。爲此,Linux2.4內核在BH
機制的基礎上進行了擴展,這就是所謂的“軟中斷請求”(softirq)機制。

Linux的softirq機制是與SMP緊密不可分的。爲此,整個softirq機制的設計與實現中
自始自終都貫徹了一個思想:“誰觸發,誰執行”(Who marks,Who runs),也即觸發
軟中斷的那個CPU負責執行它所觸發的軟中斷,而且每個CPU都由它自己的軟中斷觸發與
控制機制。這個設計思想也使得softirq機制充分利用了SMP系統的性能和特點。 http://www.douban.com/note/245433620/


軟中斷是利用硬件中斷的概念,用軟件方式進行模擬,實現宏觀上的異步執行效果。很多情況下,軟中斷和"信號"有些類似,同時,軟中斷又是和硬中斷相對應的,"硬中斷是外部設備對CPU的中斷","軟中斷通常是硬中斷服務程序對內核的中斷","信號則是由內核(或其他進程)對某個進程的中斷"(《Linux內核源代碼情景分析》第三章)。
軟中斷的一種典型應用就是所謂的"下半部"(bottom half),它的得名來自於將硬件中斷處理分離成"上半部"和"下半部"兩個階段的機制:上半部在屏蔽中斷的上下文中運行,用於完成關鍵性的處理動作;而下半部則相對來說並不是非常緊急的,通常還是比較耗時的,因此由系統自行安排運行時機,不在中斷服務上下文中執行。bottom half的應用也是激勵內核發展出目前的軟中斷機制的原因。
軟中斷是linux系統原“底半處理”的升級,在原有的基礎上發展的新的處理方式,以適應多cpu 、多線程的軟中斷處理。
軟中斷是實現系統API函數調用的手段
函數調用時將返回地址和CPU狀態寄存器內容壓棧,函數執行完畢後出棧返回斷點繼續執行。
軟中斷調用時將返回地址和CPU狀態寄存器內容壓棧,修改特權級,根據中斷號查找中斷向量表,找到ISR中斷服務例程地址,跳轉執行。
綜上,函數調用和軟中斷調用的區別是,軟中斷多了修改特權級和查找中斷向量表的功能,其他部分完全一樣。
一般,系統程序由軟件公司實現且不開源,你無法知道系統API函數的偏移地址,而且你寫的應用程序和軟件公司提供的系統程序是完全分開的,編譯器無法將二者鏈接在一起,同時,系統程序需要核心態特權才能運行,此時用函數調用的辦法是無法調用系統API函數的。解決這個問題的方法是使用軟中斷,當應用程序需要調用API時,就先設置功能號(如AX=0H),然後觸發軟中斷(如INT 80H)。系統程序設置好中斷向量表。這樣,應用程序就可以間接找到系統API了。
有了軟中斷,就可以實現應用程序的動態加載。就像WINDOWS/Linux那樣,應用程序和系統程序分別開發,不在一起編譯連接,應用程序通過軟中斷調用系統提供的功能。

Linux軟中斷原理淺析
 
Linux中的軟中斷機制用於系統中對時間要求最嚴格以及最重要的中斷的下半部進行使用。(中斷分上下部,上部通常對時間要求嚴格)在系統設計過 程中,大家都清楚中斷上下文不能處理太多的事情,需要快速的返回,否則很容易導致中斷事件的丟失,所以這就產生了一個問題:中斷髮生之後的事務處理由誰來 完成?在前後臺程序中,由於只有中斷上下文和一個任務上下文,所以中斷上下文觸發事件,設置標記位,任務上下文循環掃描標記位,執行相應的動作,也就是中 斷髮生之後的事情由任務來完成了,只不過任務上下文采用掃描的方式,實時性不能得到保 證。在Linux系統和Windows系統中,這個不斷循環的任務就是本文所要講述的軟中斷daemon。在Windows中處理耗時的中斷事務稱之爲中 斷延遲處理,在Linux中稱之爲中斷下半部,顯然中斷上半部處理清中斷之類十分清閒的動作,然後在退出中斷服務程序時觸發中斷下半部,完成具體的功能。

硬中斷是由外部事件引起的因此具有隨機性和突發性;軟中斷是執行中斷指令產生的,無面外部施加中斷請求信號,因此中斷的發生不是隨機的而是由程序安排好的。
 
在Linux中,中斷下半部的實現基於軟中斷機制。所以理清楚軟中斷機制的原理,那麼中斷下半部的實現也就非常簡單了。通過上述的描述,大家也應該 清楚爲什麼要定義軟中斷機制了,一句話就是爲了要處理對時間要求苛刻的任務,恰好中斷下半部就有這樣的需求,所以其實現採用了軟中斷機制

  軟中斷是一種推後執行的機制,定時器,網卡的數據的處理是很典型的軟中斷,這個和中斷向 量表裏的中斷是完全不一樣的,以網絡數據的處理爲例,當網卡接到一個數據包後,其中斷處理程序只是把數據複製到緩衝區,然後就告訴網卡,你可以再傳數據給 我了,也就是中斷返回,但在此之前,網卡的中斷處理程序要置一個標誌位,告訴操作系統有事要做,這個事就是軟中斷,但軟中斷只是很多中斷返回時要做的事情 之一,操作系統每次中斷返回時會檢查着個標誌位,看是否有事要做,如果有,就會去處理,象前面提到的網卡,這時候操作系統就回調用軟中斷的處理函數,網卡 的軟中斷程序就是做分析數據包啊,這個數據應該傳給誰啊等這些工作.沒有,就返回了,除了必須的部分
 
構成軟中斷機制的核心元素包括:
 
1、  軟中斷狀態寄存器soft interrupt state(irq_stat)
2、  軟中斷向量表(softirq_vec)
3、  軟中斷守護daemon
  

軟中斷的工作工程模擬了實際的中斷處理過程,當某一軟中斷時間發生後,首先需要設置對應的中斷標記位,觸發中斷事務,然後喚醒守護線程去檢測中斷狀 態寄存器,如果通過查詢發現某一軟中斷事務發生之後,那麼通過軟中斷向量表調用軟中斷服務程序action()。這就是軟中斷的過程,與硬件中斷唯一不同 的地方是從中斷標記到中斷服務程序的映射過程。在CPU的硬件中斷髮生之後,CPU需要將硬件中斷請求通過向量表映射成具體的服務程序,這個過程是硬件自 動完成的,但是軟中斷不是,其需要守護線程去實現這一過程,這也就是軟件模擬的中斷,故稱之爲軟中斷。


 
一個軟中斷不會去搶佔另一個軟中斷,只有硬件中斷纔可以搶佔軟中斷,所以軟中斷能夠保證對時間的嚴格要求。
Linux中軟中斷實現分析
 
在Linux中最多可以註冊32個軟中斷,目前系統用了6個軟中斷,他們爲:定時器處理、SCSI處理、網絡收發處理以及Tasklet機制,這裏的tasklet機制就是用來實現下半部的,
 
描述軟中斷的核心數據結構爲中斷向量表,其定義如下:
struct softirq_action
 
{
 
void (*action)(struct softirq_action *); /* 軟中斷服務程序 */
 
void *data;                                         /* 服務程序輸入參數 */
 
  
};
軟中斷守護daemon是軟中斷機制的實現核心,其實現過程也比較簡單,通過查詢軟中斷狀態irq_stat來判斷事件是否發生,如果發生,那麼映 射到軟中斷向量表,調用執行註冊的action函數就可以了。從這一點分析可以看出,軟中斷的服務程序的執行上下文爲軟中斷daemon。在Linux中 軟中斷daemon線程函數爲do_softirq()。
 
觸發軟中斷事務通過raise_softirq()來實現,該函數就是在中斷關閉的情況下設置軟中斷狀態位,然後判斷如果不在中斷上下文,那麼直接喚醒守護daemon。
 
常用的軟中斷函數列表如下:
1、  Open_softirq,註冊一個軟中斷,將軟中斷服務程序註冊到軟中斷向量表。2、  Raise_softirq,設置軟中斷狀態bitmap,觸發軟中斷事務。
 
Tasklet機制實現分析
Tasklet爲一個軟中斷,考慮到優先級問題,分別佔用了向量表中的0號和5號軟中斷。
 
當tasklet的軟中斷事件發生之後,執行tasklet-action的軟中斷服務程序,該服務程序會掃描一個tasklet的任務列表,執行該任務中的具體服務程序。在這裏舉一個例子加以說明:
 
當用戶讀寫USB設備之後,發生了硬件中斷,硬件中斷服務程序會構建一個tasklet_struct,在該結構中指明瞭完成該中斷任務的具體方法 函數(下半部執行函數),然後將tasklet_struct掛入tasklet的tasklet_struct鏈表中,這一步可以通過 tasklet_schedule函數完成。最後硬件中斷服務程序退出並且CPU開始調度軟中斷daemon,軟中斷daemon會發現tasklet發 生了事件,其會執行tasklet-action,然後tasklet-action會掃描tasklet_struct鏈表,執行具體的USB中斷服務 程序下半部。這就是應用tasklet完成中斷下半部實現的整個過程。
  
Linux中的tasklet實現比較簡單,其又封裝了一個重要數據結構tasklet_struct,使用tasklet主要函數列表如下:
1、  tasklet_init,初始化一個tasklet_struct,當然可以採用靜態初始化的方法,宏爲:DECLARE_TASKLET。
 
2、  tasklet_schedule,調度一個tasklet,將輸入的tasklet_struct添加到tasklet的鏈表中。
 
Linux中的軟中斷機制就是模擬了硬件中斷的過程,其設計思想完全可以在其他嵌入式OS中得以應用。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章