Linux內核的設計與實現 讀書筆記(7)中斷處理

主要內容:

  • 什麼是中斷
  • 中斷類型
  • 中斷相關函數
  • 中斷處理機制
  • 中斷控制方法
  • 總結

 

1. 什麼是中斷

爲了提高CPU和外圍硬件(硬盤,鍵盤,鼠標等等)之間協同工作的性能,引入了中斷的機制。

沒有中斷的話,CPU和外圍設備之間協同工作可能只有輪詢這個方法:CPU定期檢查硬件狀態,需要處理時就處理,否則就跳過。

當硬件忙碌的時候,CPU很可能會做許多無用功(每次輪詢都是跳過不處理)。

 

中斷機制是硬件在需要的時候向CPU發出信號,CPU暫時停止正在進行的工作,來處理硬件請求的一種機制。

 

2. 中斷類型

中斷一般分爲異步中斷(一般由硬件引起)和同步中斷(一般由處理器本身引起)。

異步中斷:CPU處理中斷的時間過長,所以先將硬件復位,使硬件可以繼續自己的工作,然後在適當時候處理中斷請求中耗時的部分。

舉個例子:網卡的工作原理

  1.     網卡收到數據包後,向CPU發出中斷信號,請求處理接收到的數據包
  2.     CPU將收到的數據包拷貝到內存後,即通知網卡繼續工作
  3.     至於數據包拷貝至內存後的處理會在適當的時候進行

 

這樣做避免了處理數據包時間過長導致網卡接收數據包速度變慢。

 

同步中斷:CPU處理完中斷請求的所有工作後才反饋硬件

舉個例子:系統異常處理(比如運算中的除0操作)

  1.     應用程序出現異常後,需要內核來處理
  2.     內核調用相應的異常處理函數來處理異常
  3.     處理完後終了應用程序或者給出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 恢復寄存器,將內核恢復到中斷前的狀態

 

處理流程可以參見書中的圖,如下:

interrupt

 

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會在適當的時候去完成。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章