中斷處理一般不是純軟體來實現的,需要硬體的支援。通過對中斷的學習有助於更深入的瞭解系統的一些底層原理,特別是驅動程式的開發。
主要內容:
- 什麼是中斷
- 中斷類型
- 中斷相關函數
- 中斷處理機制
- 中斷控制方法
- 總結
1. 什麼是中斷
為了提高CPU和外圍硬體(硬碟,鍵盤,滑鼠等等)之間協同工作的效能,引入了中斷的機制。
沒有中斷的話,CPU和外圍裝置之間協同工作可能只有輪詢這個方法:CPU定期檢查硬體狀態,需要處理時就處理,否則就跳過。
當硬體忙碌的時候,CPU很可能會做許多無用功(每次輪詢都是跳過不處理)。
中斷機制是硬體在需要的時候向CPU發出訊號,CPU暫時停止進行中的工作,來處理硬體請求的一種機制。
2. 中斷類型
中斷一般分為非同步中斷(一般由硬體引起)和同步中斷(一般由處理器本身引起)。
非同步中斷:CPU處理中斷的時間過長,所以先將硬體複位,使硬體可以繼續自己的工作,然後在適當時候處理插斷要求中耗時的部分。
舉個例子:網卡的工作原理
- 網卡收到資料包後,向CPU發出中斷訊號,請求處理接收到的資料包
- CPU將收到的資料包拷貝到記憶體後,即通知網卡繼續工作
- 至於資料包拷貝至記憶體後的處理會在適當的時候進行
這樣做避免了處理資料包時間過長導致網卡接收資料包速度變慢。
同步中斷:CPU處理完插斷要求的所有工作後才反饋硬體
舉個例子:系統異常處理(比如運算中的除0操作)
- 應用程式出現異常後,需要核心來處理
- 核心調用相應的異常處理函數來處理異常
- 處理完後終了應用程式或者給出message
同步中斷應該處理能很快完成的一種中斷。
3. 中斷相關函數
實現一個中斷,主要需要知道3個函數:
- 註冊中斷的函數
- 釋放中斷的函數
- 中斷處理常式的聲明
3.1 註冊中斷的函數
位置:<linux/interrupt.h> include/linux/interrupt.h
定義如下:
/* * irg - 表示要分配的中斷號 * handler - 實際的中斷處理常式 * flags - 標誌位,表示此中斷的具有特性 * name - 中斷裝置名稱的ASCII 表示,這些會被/proc/irq和/proc/interrupts檔案使用 * dev - 用於共用中斷線,多個中斷程式共用一個中斷線時(共用一個中斷號),依靠dev來區別各個中斷程式 * 傳回值: * 執行成功:0 * 執行失敗:非0 */int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char* name, void *dev)
3.2 釋放中斷的函數
定義比較簡單:
void free_irq(unsigned int irq, void *dev)
如果不是共用中斷線,則直接刪除irq對應的中斷線。
如果是共用中斷線,則判斷此中斷處理常式是否中斷線上的最後一個中斷處理常式,
是最後一個中斷處理常式 -> 刪除中斷線和中斷處理常式
不是最後一個中斷處理常式 -> 刪除中斷處理常式
3.3 中斷處理常式的聲明
聲明格式如下:
/* * 中斷處理常式的聲明 * @irp - 中斷處理常式(即request_irq()中handler)關聯的中斷號 * @dev - 與 request_irq()中的dev一樣,表示一個裝置的結構體 * 傳回值: * irqreturn_t - 執行成功:IRQ_HANDLED 執行失敗:IRQ_NONE */static irqreturn_t intr_handler(int, irq, void *dev)
4. 中斷處理機制
中斷處理的過程主要涉及3函數:
- do_IRQ 與體繫結構有關,對所接收的中斷進行應答
- handle_IRQ_event 調用中斷線上所有中斷處理
- ret_from_intr 恢複寄存器,將核心恢複到中斷前的狀態
處理流程可以參見書中的圖,如下:
5. 中斷控制方法
常用的中斷控制方法見下表:
函數 |
說明 |
local_irq_disable() |
禁止本地中斷傳遞 |
local_irq_enable() |
啟用本地中斷傳遞 |
local_irq_save() |
儲存本地中斷傳遞的目前狀態,然後禁止本地中斷傳遞 |
local_irq_restore() |
恢複本地中斷傳遞到給定的狀態 |
disable_irq() |
禁止給定中斷線,並確保該函數返回之前在該中斷線上沒有處理常式在運行 |
disable_irq_nosync() |
禁止給定中斷線 |
enable_irq() |
啟用給定中斷線 |
irqs_disabled() |
如果本地中斷傳遞被禁止,則返回非0;否則返回0 |
in_interrupt() |
如果在中斷上下文中,則返回非0;如果在進程上下文中,則返回0 |
in_irq() |
如果當前正在執行中斷處理常式,則返回非0;否則返回0 |
總結
中斷處理對處理時間的要求很高,如果一個中斷要花費較長時間,那麼中斷處理一般分為2部分。
上半部只做一些必要的工作後,立即通知硬體繼續自己的工作。
中斷處理中耗時的部分,也就是下半部的工作,CPU會在適當的時候去完成。