1. 程式人生 > >中斷底半部機制之工作佇列詳解

中斷底半部機制之工作佇列詳解

工作佇列的使用方法和tasklet 非常相似,下面的程式碼用於定義一個工作佇列和一個底半部執行函式。

struct work_struct my_wq; /*定義一個工作佇列*/

void my_wq_func(unsigned long); /*定義一個處理函式*/

通過INIT_WORK()可以初始化這個工作佇列並將工作佇列與處理函式繫結,這兩種方式最後產生的效果是一樣的,為了方便建議使用INIT_WORK(),實際中大多數也是這個函式。如下所示:

INIT_WORK(&my_wq, (void (*)(void *)) my_wq_func, NULL);

/*初始化工作佇列並將其與處理函式繫結*/

tasklet_schedule()對應的用於排程工作佇列執行的函式為schedule_work(),如:

schedule_work(&my_wq);/*排程工作佇列執行*/

使用 工作佇列作為底半部處理中斷的裝置驅動程式模板如下所示(僅包含與中斷相關的部分)。

/*定義工作佇列和關聯函式*/
struct work_struct xxx_wq;
void xxx_do_work(unsigned long);

/*中斷處理底半部*/
void xxx_do_work(unsigned long)
{
...
}

/*中斷處理頂半部*/
irqreturn_t xxx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
    ...
    schedule_work(&xxx_wq);
    ...
}

/*裝置驅動模組載入函式*/
int xxx_init(void)
{
    ...
    /*申請中斷*/
    result = request_irq(xxx_irq, xxx_interrupt,
    SA_INTERRUPT, "xxx", NULL);
    ...
    /*初始化工作佇列*/
    INIT_WORK(&xxx_wq, (void (*)(void *)) xxx_do_work, NULL);
    ...
}

/*裝置驅動模組解除安裝函式*/
void xxx_exit(void)
{
    ...
    /*釋放中斷*/
    free_irq(xxx_irq, xxx_interrupt);
    ...
}

上述程式在設計驅動模組載入函式中增加了初始化工作佇列的程式碼(第28 行)。

儘管 Linux 專家們多建議在裝置第一次開啟時才申請裝置的中斷並在最後一次關閉時釋放中斷以儘量減少中斷被這個裝置佔用的時間,但是,大多數情況下,為求省事,大多數驅動工程師還是將中斷申請和釋放的工作放在了裝置驅動的模組載入和解除安裝函式中。