###### tags: `Linux kernel` # LKMPG tasklet and workqueue example 拜讀Jserv改寫的The Linux Kernel Module Programming Guide,在跑example的時候遇到一些問題: DECLARE_TASKLET(mytask, tasklet_fn, 0L) void tasklet_fn(unsigned long data) 須改成以下的定義: DECLARE_TASKLET(mytask, tasklet_fn) void tasklet_fn(struct tasklet_struct * ptasklet) 定義的問題還好,改一下就行了,奇怪的是跑出來的結果有些不同: ``` static void tasklet_fn(struct tasklet_struct * ptasklet){ pr_info("Example tasklet starts\n"); mdelay(5000); pr_info("Example tasklet ends\n"); } DECLARE_TASKLET(mytask, tasklet_fn); static int example_tasklet_init(void) { pr_info("tasklet example init\n"); tasklet_schedule(&mytask); mdelay(200); pr_info("Example tasklet init continues...\n"); return 0; } ``` 照書上的說法,The tasklet_fn function runs for a few seconds and **"in the mean time"** execution of the example_tasklet_init function continues to the exit point,順序應該是 tasklet example init Example tasklet starts Example tasklet init continues... Example tasklet ends 但我的結果卻是 tasklet example init Example tasklet starts Example tasklet ends Example tasklet init continues... 相當於一排進tasklet,後面就跟著跑tasklet了,和書上寫的不大一樣。有另一個workqueue的範例,我也把他改寫成和tasklet做的事情一樣: ``` static void work_handler(struct work_struct *data) { pr_info("work handler function start.\n"); mdelay(5000); pr_info("work handler function end.\n"); } int init_module() { queue = alloc_workqueue("HELLOWORLD", WQ_UNBOUND, 1); INIT_WORK(&work, work_handler); pr_info("Ready to schedule_work...\n"); schedule_work(&work); mdelay(200); pr_info("Schedule work done.\n"); return 0; } ``` 這個結果就合理許多: Ready to schedule_work... Schedule work done. work handler function start. work handler function end. 經過多次嘗試,發現tasklet範例的問題在於init module中的mdelay(),若是拿掉的話順序就會跟書上寫的一樣了。所以我推斷應該是mdelay()導致schedule out跑去做tasklet function。以下是一些心得: 1. 本來tasklet用法就不應該放sleep,這裡只是示範用途 2. tasklet insmod的時候回到prompt要等待5秒鐘才回來,也間接坐實了tasklet只在這個CPU上執行的說法(相反的同樣的作法用workqueue不用等待) 3. init module中sleep會導致schedule out,跑去做tasklet function,但是對workqueue來說,卻不會跑去做workqueue function,我猜應該是workqueue跑在process裡面,而非tasklet跑在kernel裡面,所以在workqueue case,scheduler就讓init module繼續跑到完。