中斷處理一般不是純軟件來實現的,需要硬件的支持。通過對中斷的學習有助于更深入的了解系統的一些底層原理,特別是驅動程序的開發。
主要內容:
- 什么是中斷
- 中斷類型
- 中斷相關函數
- 中斷處理機制
- 中斷控制方法
- 總結
?
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會在適當的時候去完成。