中斷與中斷處理 何為中斷? + 一種由設備發向處理器的電信號 + 中斷不與處理器時鐘同步,隨時可以發生,內核隨時可能因為中斷到來而被打斷。 + 每一個中斷都有唯一一個數字標誌,稱之為中斷線(IRQ) + 異常是由軟體產生,與處理器時鐘同步。 中斷處理程式 + 由內核調用來響應中斷 + 運行於中斷上下 ...
中斷與中斷處理
何為中斷?
- 一種由設備發向處理器的電信號
- 中斷不與處理器時鐘同步,隨時可以發生,內核隨時可能因為中斷到來而被打斷。
- 每一個中斷都有唯一一個數字標誌,稱之為中斷線(IRQ)
- 異常是由軟體產生,與處理器時鐘同步。
中斷處理程式
- 由內核調用來響應中斷
- 運行於中斷上下文
- 中斷的執行不可阻塞
- 中斷處理分為兩個部分,中斷處理程式是上半部(top half),還有下半部(bottom halves)
中斷處理程式註冊
- 中斷處理程式是管理硬體驅動程式的組成部分,如果設備使用中斷,其相應的驅動程式就會註冊一個中斷處理程式。
通過request_irq()函數來註冊中斷處理程式
int request_irq( unsigned irq, irq_handler_t handler, unsigned long flags, count char* name, void *dev)
- 第一個參數irq表示要分配的中斷號
- 第二個參數handler表示中斷處理程式指針
- 第三個表示標誌,可以為0、IRQF_DISABLE、IRQF_SAMPLE_RANDOM、IRQF_TIMER、IRQF_SHARED
- IRQF_DISABLE 表示該中斷處理期間,禁用所有其他中斷
- IRQF_SAMPLE_RANDOM 這個設備產生的中斷對內核熵池有貢獻
- IRQF_TIMER 為系統定時器中斷而準備的
- IRQF_SHARED 表示多個中斷處理程式共用中斷線。
- 第四個參數name表示設備的文本表示
第五個參數dev用於共用中斷線,dev提供唯一的標誌信息。
需要註意的是,request_irq( )可能睡眠,因此不能再中斷上下文或者其他不允許阻塞的代碼中調用該函數。
中斷處理程式釋放
卸載驅動程式時,需要用free_irq()註銷相應的中斷處理程式,並釋放中斷線。
void free_irq(unsigned int irq, void *dev);
如果指定的中斷線不是共用的,那麼該函數刪除處理程式的同時將禁用這條中斷線。如果是共用的,只刪除dev對應的中斷處理程式。
編寫中斷處理程式
static irqreturn_t intr_handler(int irq, void * dev);
當一個給定的中斷處理程式正在執行時,相應的中斷線在所有的處理器上都會被屏蔽掉,以防止在同一條中斷線上接受另一個新的中斷。
中斷上下文
- 當執行一個中斷時,內核處於中斷上下文。
- 中斷上下文沒有後備進程,不可以睡眠。
- 中斷上下文有著嚴格的時間限制,因為其打斷了其他代碼(有可能打斷了其他中斷處理程式)。中斷上下文中的 代碼應該迅速簡潔,儘量不要使用迴圈去處理繁重的工作。
中斷控制
Linux內核提供了一組介面用於控制機器上的中斷狀態
禁止和激活中斷
用於禁止、激活當前處理器的本地中斷,local_irq_disable(); local_irqenable();
禁止指定中斷線
void disable_irq(unsigned int irq); //禁止控制器上某一條中斷線,函數只有在當前執行的所有處理程式完成後,才能返回 void disable_irq_nosync(unsigned int irq); //禁止控制器上某一條中斷線,不會等待當前中斷處理程式執行完畢。 void enable_irq(unsigned int irq); //激活控制器上某一條中斷線, void synchronize_irq(unsigned int irq); //等待下一個特定的中斷處理程式退出
在一條中斷線上,每次調用disable_irq_nosync()、disable_irq(),都需要調用一次enable_irq(),只有在enable_irq()完成了最後一次調用後,才完成了中斷線的激活。
這三個函數可以從中斷或進程上下文中調用,而且不會睡眠。