linux核心軟中斷和Tasklet機制

2021-08-30 15:28:07 字數 2759 閱讀 7438

軟中斷

軟中斷的一種典型應用就是所謂的"下半部"(bottom half),它的得名來自於將硬體中斷處理分離成"上半部"和"下半部"兩個階段的機制:上半部在遮蔽中斷的上下文中執行,用於完成關鍵性的處理動作;而下半部則相對來說並不是非常緊急的,通常還是比較耗時的,因此由系統自行安排執行時機,不在中斷服務上下文中執行。bottom half的應用也是激勵核心發展出目前的軟中斷機制的原因。

軟中斷的工作工程模擬了實際的中斷處理過程,當某一軟中斷事件發生後,首先需要設定對應的中斷標記位,觸發中斷事務,然後喚醒守護執行緒去檢測中斷狀態暫存器,如果通過查詢發現有軟中斷事務發生,那麼通過查詢軟中斷向量表呼叫相應的軟中斷服務程式action()。這就是軟中斷的過程,與硬體中斷唯一不同的地方是從中斷標記到中斷服務程式的對映過程。在cpu的硬體中斷發生之後,cpu需要將硬體中斷請求通過向量表對映成具體的服務程式,這個過程是硬體自動完成的,但是軟中斷不是,其需要守護執行緒去實現這一過程,這也就是軟體模擬的中斷,故稱之為軟中斷。

乙個軟中斷不會去搶占另乙個軟中斷,只有硬體中斷才可以搶占軟中斷,所以硬中斷能夠保證對時間的嚴格要求。

tasklet機制

tasklet是linux中斷處理機制中的軟中斷延遲機制。在linux中存在著硬中斷和軟中斷的概念區分。

機制流程:當linux接收到硬體中斷之後,通過tasklet函式來設定軟中斷被執行的優先程度從而導致軟中斷處理函式被優先執行的差異性。

特點:tasklet的優先級別較低,而且中斷處理過程中可以被打斷。但被打斷之後,還能進行自我恢復,斷點續執行。

※ 使用tasklet

1.宣告自己的tasklet

既可以靜態地建立tasklet,也可以動態地建立它。如果靜態地建立乙個tasklet(直接引用),使用中的兩個巨集:

1.   #define declare_tasklet(name, func, data) /

2.structtasklet_struct name = 

3.    

4.   #define declare_tasklet_disabled(name, func, data) /

5.structtasklet_struct name = 

這兩個巨集都能根據給定的名稱靜態地建立乙個tasklet_struct結構。當tasklet被排程以後,給定的函式func會被執行,它的引數由data給出。這兩個巨集的區別在於引用計數器的初始值設定不同。前乙個巨集把建立的tasklet的引用計數器設定為0,該taskelet處於啟用狀態,另一則設為1,所以處於禁止狀態。

還可以通過將乙個間接引用(乙個指標)賦給乙個動態建立的tasklet_struct結構的方式來初始化乙個tasklet:

1.   tasklet_init(t,tasklet_handler,dev);      

2.編寫自己的tasklet處理程式

tasklet處理器程式必須符合規定的函式型別:

void tasklet_handler(unsigned long data)

因為是靠軟中斷實現,所以tasklet不能睡眠。這意味著不能在tasklet中使用訊號量或者其他阻塞函式。tasklet執行時執行響應中斷,如果寫的tasklet和中斷處理程式之間共享了某些資料的話,所以要做好預防工作(比如遮蔽中斷後獲取乙個鎖)。兩個相同的tasklet絕不會同時執行。

3.排程自己的tasklet

通過呼叫tasklet_schedule()函式並傳遞給該函式相應的tasklet_struct的指標,該tasklet就會被排程以便執行 :

1.   declare_tasklet(my_tasklet,my_tasklethandler,dev);

2.    

3.   tasklet_schedule(&my_tasklet);   //把my_tasklet標記為掛起

4.    

在tasklet被排程以後,只要有機會它就會盡可能早地執行。在它還沒有得到執行機會之前,如果有乙個相同的tasklet又被喚醒了,那麼它只會執行一次。而如果此時它已經開始執行了,比如說在另乙個處理器上,那麼這個新的tasklet會被重新排程並再次執行,作為優化,乙個tasklet總是在排程它的處理器上執行,以更好的利用處理器的高度快取。

tasklet_disable()函式用來禁止某個指定的tasklet。如果該tasklet當前正在執行,這個函式會等到它執行完畢再返回。

tasklet_disable_nosync()函式也可以用來禁止指定的tasklet,不過它無需在返回前等待tasklet執行完畢。這樣做往往不太安全,因為我們無法估計該tasklet是否仍在執行。

呼叫tasklet_enable()函式可以啟用乙個tasklet,要啟用declare_tasklet_disabled()建立的tasklet,也要呼叫這個函式。

通過呼叫tasklet_kill()函式從掛起的佇列中去掉乙個tasklet。該函式的引數是乙個指向某個tasklet的tasklet_struct的長指標。在處理乙個經常重新排程它自身的tasklet的時候,從掛起的佇列中移去已排程的tasklet會很有用。這個函式首先等待該tasklet執行完畢,然後再將它移去。由於該函式可能會引起休眠,所以禁止在中斷上下文中使用它。

Linux核心軟中斷執行緒對於通用核心執行緒的啟示

2.6.11版本的核心軟中斷執行緒ksoftirqd 如下,下面框架可以看出對於,吞吐量與處理延遲兩者之間的權衡。軟中斷執行緒處理概括 1 如果沒有活幹 沒有軟中斷等待處理 就 schedule 切出,並從執行佇列裡面刪除 由於任務狀態已經變成task interruptible 2 如果有活兒幹,...

Linux核心實現中斷和中斷處理(一)

核心是怎麼知道應用程式要呼叫系統呼叫的呢?或者說應用程式怎麼通知系統核心自己需要執行乙個系統呼叫,這是通過軟中斷實現的,通過引發乙個異常來促使系統切換到核心態去執行異常處理程式 ps 什麼時候會從使用者態切換到核心態呢?1.中斷 2.陷阱 3.系統呼叫 中斷分為兩種,硬中斷和軟中斷 在許多處理器體系...

Linux核心 之 中斷

中斷處理函式所作的第一件事情是什麼?答案是遮蔽中斷,所以要遮蔽中斷,是因為新的中斷會再次呼叫中斷處理函式,導致原來中斷處理現場的破壞。因為中斷,它是把原來的上下文都存起來,如果是多級中斷的話,它需要存多級的上下文,除非linux能存多級上下文,感覺是能多存的。如果只能存一級,那必然是要遮蔽中斷,不然...