軟中斷

軟中斷

軟中斷是利用硬體中斷的概念,用軟體方式進行模擬,實現宏觀上的非同步執行效果。很多情況下,軟中斷和"信號"有些類似,同時,軟中斷又是和硬中斷相對應的,"硬中斷是外部設備對CPU的中斷","軟中斷通常是硬中斷服務程序對內核的中斷","信號則是由內核(或其他進程)對某個進程的中斷"(《Linux內核源代碼情景分析》第三章)。

概念


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

原因


一般來說,軟中斷是由內核機制的觸發事件引起的(例如進程運行超時),但是不可忽視有大量的軟中斷也是由於和硬體有關的中斷引起的,例如當印表機埠產生一個硬體中斷時,會通知和硬體相關的硬中斷,硬中斷就會產生一個軟中斷並送到操作系統內核里,這樣內核就會根據這個軟中斷喚醒睡眠在印表機任務隊列中的處理進程。

代碼的執行


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

機制實現原理


軟中斷機制的實現原理如圖所示:
軟中斷
軟中斷

核心元素


構成軟中斷機制的核心元素包括:
1、軟中斷狀態寄存器soft interrupt state(irq_stat)
2、軟中斷向量表(softirq_vec)
3、軟中斷守護daemon
軟中斷的工作工程模擬了實際的中斷處理過程,當某一軟中斷事件發生后,首先需要設置對應的中斷標記位,觸發中斷事務,然後喚醒守護線程去檢測中斷狀態寄存器,如果通過查詢發現有軟中斷事務發生,那麼通過查詢軟中斷向量表調用相應的軟中斷服務程序action()。這就是軟中斷的過程,與硬體中斷唯一不同的地方是從中斷標記到中斷服務程序的映射過程。在CPU的硬體中斷髮生之後,CPU需要將硬體中斷請求通過向量表映射成具體的服務程序,這個過程是硬體自動完成的,但是軟中斷不是,其需要守護線程去實現這一過程,這也就是軟體模擬的中斷,故稱之為軟中斷。
一個軟中斷不會去搶佔另一個軟中斷,只有硬體中斷才可以搶佔軟中斷,所以軟中斷能夠保證對時間的嚴格要求。