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