工作隊列
[概述]
工作隊列是一種將工作推後執行的的形式,工作隊列可以把工作推後,交由一個核心線程去執行,佔有進程內容相關的所有優勢,允許重新調度和睡眠。
[工作隊列的實現]
工作隊列子系統是一個用於建立核心線程的介面,通過它建立的進程負責執行由核心其他部分排到隊列裡的任務。它建立的這些核心線程稱作工作者線程(worker thread)。工作隊列子系統提供了一個預設的工作者線程來處理推後的工作,所以我們大多數情況下,沒必要自己去建立工作者線程,使用預設的就OK。
Linux kernel development 3 上對工作隊列的實現原理講的很清楚了,這裡就不再詳述。具體來看一個執行個體
[執行個體]
static struct input_dev *button_dev;static struct work_struct button_wq;
在做實際的驅動開發的時候,不推薦使用全域變數,因為全域變數是造成競爭條件的主要原因。
[中斷處理常式]
static irqreturn_t button_interrupt(intirq, void *p){ schedule_work(&button_wq); returnIRQ_RETVAL(IRQ_HANDLED);}
schedule_work(&work)函數用來調度work,把work提交給預設的events工作者線程(插入工作任務鏈表中)。work馬上會被調度,一旦其所在的處理器上的工作者線程被喚醒,喚醒的工作者隊列會遍曆整個工作任務鏈表,如果有工作,它就會被執行,否則繼續睡眠。
Schedule_work_delay(&work, delay) 和schedule_work函數的作用相同,唯一區別就是延遲delay時間後才會執行。
[工作隊列處理函數]
void work_handler(struct work_struct *data){ /*get pin value <down 0, up 1> */ intval = s3c2410_gpio_getpin(S3C2410_GPG(0)); input_report_key(button_dev,KEY_1, val); input_sync(button_dev);}
完成按鍵資訊的擷取和上報工作。
[模組初始化函數]
static int __init button_init(void){ interr; if(request_irq(BUTTON_IRQ, button_interrupt, IRQ_TYPE_EDGE_BOTH,DEV_NAME, NULL)) { printk(KERN_ERR"cannotallocate irq"); return- EBUSY; } …… INIT_WORK(&button_wq,work_handler); printk("initialized\n"); return0;}
初始化函數主要完成了兩個工作:
1、 申請中斷
2、 建立一個推後的工作button_wq,有兩種方法:
動態建立:
INIT_WORK(struct work_struct work, void (*func)(void *)), 在新核心裡,INIT_WORK已經發生了變化,少了第三個參數。可以參考http://hi.baidu.com/amokefei/blog/item/db998b2e1885a134d52af13e.html
靜態建立:
DECLARE_WORK(name,func) 建立一個名為name,處理函數為func的work_struct結構體。
不管是動態還是靜態,都是填充work struct 結構體。
有興趣可以去看核心裡gpio_keys.c的實現代碼,一個典型的work queue的實現例子。