tasklet機制

在編寫設備驅動時, tasklet 機制是一種比較常見的機制,通常用於減少中斷處理的時間,將本應該是在中斷服務程序中完成的任務轉化成軟中斷完成。

爲了最大程度的避免中斷處理時間過長而導致中斷丟失,有時候我們需要把一些在中斷處理中不是非常緊急的任務放在後面執行,而讓中斷處理程序儘快返回。在老版本的 linux 中通常將中斷處理分爲 top half handler 、 bottom half handler 。利用 top half handler 處理中斷必須處理的任務,而 bottom half handler 處理不是太緊急的任務。

但是 linux2.6 以後的 linux 採取了另外一種機制,就是軟中斷來代替 bottom half handler 的處理。而 tasklet 機制正是利用軟中斷來完成對驅動 bottom half 的處理。 Linux2.6 中軟中斷通常只有固定的幾種: HI_SOFTIRQ( 高優先級的 tasklet ,一種特殊的 tasklet) 、 TIMER_SOFTIRQ (定時器)、 NET_TX_SOFTIRQ (網口發送)、 NET_RX_SOFTIRQ (網口接收) 、 BLOCK_SOFTIRQ (塊設備)、 TASKLET_SOFTIRQ (普通 tasklet )。當然也可以通過直接修改內核自己加入自己的軟中斷,但是一般來說這是不合理的,軟中斷的優先級比較高,如果不是在內核處理頻繁的任務不建議使用。通常驅動用戶使用 tasklet 足夠了。

軟中斷和 tasklet 的關係如下圖:


上圖可以看出, ksoftirqd 是一個後臺運行的內核線程,它會週期的遍歷軟中斷的向量列表,如果發現哪個軟中斷向量被掛起了( pend ),就執行對應的處理函數,對於 tasklet 來說,此處理函數就是 tasklet_action ,這個處理函數在系統啓動時初始化軟中斷的就掛接了。

Tasklet_action 函數,遍歷一個全局的 tasklet_vec 鏈表(此鏈表對於 SMP 系統是每個 CPU 都有一個),此鏈表中的元素爲 tasklet_struct 。此結構如下 :

struct tasklet_struct

{

       struct tasklet_struct *next;

       unsigned long state;

       atomic_t count;

       void (*func)(unsigned long);

       unsigned long data;

};

每個結構一個函數指針,指向你自己定義的函數。當我們要使用 tasklet ,首先新定義一個 tasklet_struct 結構,並初始化好要執行函數指針,然後將它掛接到 task_vec 鏈表中,併發一個軟中斷就可以等着被執行了。

原理大概如此,對於 linux 驅動的作者其實不需要關心這些,關鍵是我們如何去使用 tasklet 這種機制。

Linux 中提供瞭如下接口:

DECLARE_TASKLET(name,function,data) :此接口初始化一個 tasklet ;其中 name 是 tasklet 的名字, function 是執行 tasklet 的函數; data 是 unsigned long 類型的 function 參數。

static inline void tasklet_schedule(struct tasklet_struct *t) :此接口將定義後的 tasklet 掛接到 cpu 的 tasklet_vec 鏈表,具體是哪個 cpu 的 tasklet_vec 鏈表,是根據當前線程是運行在哪個 cpu 來決定的。此函數不僅會掛接 tasklet ,而且會起一個軟 tasklet 的軟中斷 , 既把 tasklet 對應的中斷向量掛起 (pend) 。

兩個工作完成後,基本上可以了, tasklet 機制並不複雜,很容易的使程序儘快的響應中斷,避免造成中斷丟失。


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