1.異常處理
Linux利用異常來達到兩個截然不同的目的:
· 給進程發送一個信號以通報一個反常情況
· 管理硬件資源
對於第一種情況,例如,如果進程執行了一個被0除的操作,CPU則會產生一個“除法錯誤”異常,並由相應的異常處理程序向當前進程發送一個SIGFPE信號。當前進程接收到這個信號後,就要采取若干必要的步驟,或者從錯誤中恢復,或者終止執行(如果這個信號沒有相應的信號處理程序)。
對於第二種情況,內核使用兩種異常來有效地管理硬件資源,相應的處理程序也就更復雜。在這種情況下,異常並不表示一種錯誤情況:
· 用“設備不可用”異常來推遲裝載浮點寄存器。
· 用“缺頁”異常推遲把新頁框分配給進程。
內核對異常處理程序的調用有一個標准的結構,它由以下三部分組成:
· 在內核棧中保存大多數寄存器的內容(由匯編語言實現)
· 調用C編寫的異常處理函數
· 通過ret_from_exception()函數從異常退出。
關於內核對異常的具體處理在此不進行詳細介紹,在第六章內存管理中我們將涉及到“缺頁”異常處理程序,本節的重點放在中斷處理。
2.中斷處理
當一個中斷發生時,並不是所有的操作都具有相同的急迫性。事實上,把所有的操作都放進中斷處理程序本身並不合適。需要時間長的、非重要的操作應該推後,因為當一個中斷處理程序正在運行時,相應的IRQ中斷線上再發出的信號就會被忽略。更重要的是,中斷處理程序是代表進程執行的,它所代表的進程必需總處於TASK_RUNNING狀態,否則,就可能出現系統僵死情形。因此,中斷處理程序不能執行任何阻塞過程,如I/O設備操作。因此,Linux把一個中斷要執行的操作分為下面的三類:
(1)緊急的(Critical)
這樣的操作諸如:中斷到來時中斷控制器做出應答,對中斷控制器或設備控制器重新編程,或者對設備和處理器同時訪問的數據結構進行修改。這些操作都是緊急的,應該被很快地執行,也就是說,緊急操作應該在一個中斷處理程序內立即執行,而且是在禁用中斷的狀態下。
(2)非緊急的(Noncritical)
這樣的操作如修改那些只有處理器才會訪問的數據結構(例如,按下一個鍵後,讀掃描碼)。這些操作也要很快地完成,因此,它們由中斷處理程序立即執行,但在啟用中斷的狀態下。
(3)非緊急可延遲的(Noncritical deferrable)
這樣的操作如,把一個緩沖區的內容拷貝到一些進程的地址空間(例如,把鍵盤行緩沖區的內容發送到終端處理程序的進程)。這些操作可能被延遲較長的時間間隔而不影響內核操作:有興趣的進程會等待需要的數據。非緊急可延遲的操作由一些被稱為“下半部分”(bottom halves)的函數來執行。我們將在後面討論“下半部分”。
所有的中斷處理程序都執行四個基本的操作:
· 在內核棧中保存IRQ的值和寄存器的內容。
· 給與IRQ中斷線相連的中斷控制器發送一個應答,這將允許在這條中斷線上進一步發出中斷請求。
· 執行共享這個IRQ的所有設備的中斷服務例程(ISR)。
· 跳到ret_from_intr( )的地址後終止。