Linux的tasklet函數詳解

tasklet主要用在中斷函數中。它對於中斷處理特別有用,由於硬件中斷必須儘快處理, 但大部分的數據管理可以延後到以後安全的時間執行。所以可以使用tasklet。

tasklet的使用比較簡單,只需要定義tasklet及其處理函數並將兩者關聯即可,在定義時可以採用兩種形式。

例子:
        struct tasklet_struct my_tasklet;

        Void my_tasklet_func(unsigned long);
        第一種:

        DECLARE_TASKLET(my_tasklet,my_tasklet_func,data)

        代碼DECLARE_TASKLET實現了定義名稱爲my_tasklet的tasklet並將其與my_tasklet_func這個函數綁定,而傳入這個函數的參數爲data。
 
        第二種:
        tasklet_init(&my_tasklet, my_tasklet_func, data);

        需要調度tasklet的時候引用一個tasklet_schedule()函數就能使系統在適當的時候進行調度,如下所示

        tasklet_schedule(&my_tasklet)

tasklet以一個數據結構形式存在,使用前必須被初始化。初始化能夠通過調用一個特定函數或者通過使用某些宏定義聲明結構:

#include <linux/interrupt.h>
struct tasklet_struct {
    struct tasklet_struct *next;
    unsigned long state;
    atomic_t count;
    void (*func)(unsigned long);
    unsigned long data;
};
void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data);
#define DECLARE_TASKLET(name, func, data) \ struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }
#define DECLARE_TASKLET_DISABLED(name, func, data) \ struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(1), func, data }
1) void tasklet_disable(struct tasklet_struct *t);
函數暫時禁止給定的 tasklet被 tasklet_schedule 調度,直到這個 tasklet 再次被enable;若這個 tasklet 當前在運行, 這個函數忙等待直到這個tasklet退出。
2) void tasklet_disable_nosync(struct tasklet_struct *t);
和tasklet_disable類似,但是tasklet可能仍然運行在另一個 CPU。
3) void tasklet_enable(struct tasklet_struct *t);
使能一個之前被disable的 tasklet。若這個 tasklet 已經被調度, 它會很快運行。 tasklet_enable和tasklet_disable必須匹配調用, 因爲內核跟蹤每個 tasklet 的"禁止次數"4) void tasklet_schedule(struct tasklet_struct *t);
調度 tasklet 執行,如果tasklet在運行中被調度, 它在完成後會再次運行; 這保證了在其他事件被處理當中發生的事件受到應有的注意. 這個做法也允許一個 tasklet 重新調度它自己。
5) void tasklet_hi_schedule(struct tasklet_struct *t);
和tasklet_schedule類似,只是在更高優先級執行。當軟中斷處理運行時, 它處理高優先級 tasklet。在其他軟中斷之前,只有具有低響應週期要求的驅動才應使用這個函數, 可避免其他軟件中斷處理引入的附加週期。
6) void tasklet_kill(struct tasklet_struct *t);
確保了 tasklet 不會被再次調度來運行,通常當一個設備正被關閉或者模塊卸載時被調用。如果 tasklet正在運行, 這個函數等待直到它執行完畢。若 tasklet 重新調度它自己,則必須阻止在調用 tasklet_kill前它重新調度它自己,如同使用 del_timer_sync。

tasklet驅動調用模板:

void xxx_do_tasklet(unsigned long);

DECLARE_TASKLET(xxx_tasklet,xxx_do_tasklet,0);

void xxx_do_tasklet(unsigned long)
{
      ……
}

irqreturn_t xxx_interrupt(int irq,void *dev_id,struct pt_regs *regs)
{
      ……
      tasklet_schedule(&xxx_tasklet);
      ……
}
int _init xxx_init(void)
{
      ……
   result=request_irq(xxx_irq,xxx_interrupt,SA_INTERRUPT,”xxx”,NULL)
      ……
}
void _exit xxx_exit(void)
{
      ……
      free_irq(xxx_irq,xxx_irq_interrupt);
      ……
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章