在延遲中斷處理機制上,workqueue是另一個可以使用的方式,workqueue是執行在低優先級別上,因此,可以讓Context Switch繼續執行,意味著使用者可以在workqueue裡面呼叫sleep()相關的函式,這也是跟softirq、tasklet最大的差別,因此,workqueue是相當適合應用在耗時處理的場合
使用步驟:
1. alloc_workqueue() 2. INIT_WORK() 3. queue_work() 4. destroy_workqueue()
main.c
#include <linux/init.h> #include <linux/device.h> #include <linux/module.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/mm.h> #include <linux/gpio.h> #include <linux/interrupt.h> MODULE_LICENSE("GPL"); MODULE_AUTHOR("Steward Fu"); MODULE_DESCRIPTION("Linux Driver"); #define BUTTON 27 struct work_struct mywork = {0}; struct workqueue_struct *myworkqueue = NULL; static void workqueue_handler(struct work_struct *work) { printk("%s\n", __func__); } static irqreturn_t irq_handler(int irq, void *arg) { queue_work(myworkqueue, &mywork); return IRQ_HANDLED; } int ldd_init(void) { myworkqueue = alloc_workqueue("myworkqueue", 0, 0); INIT_WORK(&mywork, workqueue_handler); request_irq(gpio_to_irq(BUTTON), irq_handler, IRQF_TRIGGER_RISING, "gpio_irq", NULL); return 0; } void ldd_exit(void) { free_irq(gpio_to_irq(BUTTON), NULL); destroy_workqueue(myworkqueue); } module_init(ldd_init); module_exit(ldd_exit);
ldd_init: 設定GPIO中斷以及workqueue延遲處理副程式
irq_handler: 安排一個workqueue延遲處理
workqueue_handler: 列印字串
ldd_exit: 釋放中斷資源以及刪除workqueue
完成
# workqueue_handler