作者: 樊穎飛
定時器在內核的定義:
struct timer_list { /* * All fields that change during normal runtime grouped to the * same cacheline */ struct list_head entry; //定時器的鏈表 unsigned long expires;//以節拍為單位的定時時間,表示為定時器觸發的到期時間 struct tvec_base *base; void (*function)(unsigned long); //該指針指向定時器處理函數,函數參數為長整形 unsigned long data; //處理函數的參數值 int slack; #ifdef CONFIG_TIMER_STATS void *start_site; char start_comm[16]; int start_pid; #endif #ifdef CONFIG_LOCKDEP struct lockdep_map lockdep_map; #endif };
使用定時器的步驟:
1) 定義定時器:
struct timer_list my_timer
2)初始化定時器:
初始化定時器的到期節拍數
my_timer.expires = jiffies +delay ;該設置讓定時器的觸發時間設置為 激活定時器后的delay個節拍點
my_timer.function = 處理函數的名稱 該設置設置定時器觸發時處理的函數
my_timer.data 初始化處理函數的參數值,若處理函數沒有參數則可簡單設置為0或任意其他數值
3)激活定時器:即內核會開始定時,直到my_timer.expires
使用函數add_timer 即 add_timer(&my_timer);
內核原型為:
void add_timer(struct timer_list *timer) { BUG_ON(timer_pending(timer)); mod_timer(timer, timer->expires); //該函數設置定時器timer的定時時間為timer->expires; }
4)刪除定時器:如果需要在定時器到期之前停止定時器,則可以使用該函數,若是定時器已經過期則不需調用該函數,因為它們會自動刪除
del_timer(&my_timer);
定時器的簡單實例:該例子的功能是首先初始化一個定時器,當定時器時間到后觸發定時器出倆函數的執行,該函數又重新設置了該定時器的時間,即該定時器又在下一次定時時間的到來繼續處理函數,一直循環,知道最后在該模塊卸載時進行刪除定時器,結束該定時器
代碼中 HZ為內核每一秒的節拍數,是通過宏進行定義的,通過該程序的打印結果可以得到,本人電腦的節拍數測試結果為250
#include< linux/module.h > #include< linux/init.h > #include< linux/sched.h > #include < linux/timer.h > #include < linux/kernel.h > struct timer_list stimer; //定義定時器 static void time_handler(unsigned long data){ //定時器處理函數 mod_timer(&stimer, jiffies + HZ); printk(“current jiffies is %ld\n”, jiffies); } static int __init timer_init(void){ //定時器初始化過程 printk(“My module worked!\n”); init_timer(&stimer); stimer.data = 0; stimer.expires = jiffies + HZ; //設置到期時間 stimer.function = time_handler; add_timer(&stimer); return 0; } static void __exit timer_exit(void){ printk(“Unloading my module.\n”); del_timer(&stimer);//刪除定時器 return; } module_init(timer_init);//加載模塊 module_exit(timer_exit);//卸載模塊 MODULE_AUTHOR(“fyf”); MODULE_LICENSE(“GPL”);
加載/ 卸載該程序后通過命令dmesg可以看到
[ 6225.522208] My module worked!
[ 6226.520014] current jiffies is 1481630
[ 6227.520014] current jiffies is 1481880
[ 6228.520013] current jiffies is 1482130
[ 6229.520011] current jiffies is 1482380
[ 6229.770335] Unloading my module.
即每2次的jiffies之差為250
定時器的應用:以下是一個簡單的延遲當前進程執行的程序,延遲是通過定時器來實現的;
#include< linux/module.h > #include< linux/init.h > #include< linux/sched.h > #include < linux/timer.h > #include < linux/kernel.h > struct timer_list stimer; //定義定時器 int timeout = 10 * HZ; static void time_handler(unsigned long data){ //定時器處理函數,執行該函數獲取掛起進程的pid,喚醒該進程 struct task_struct *p = (struct task_struct *)data;//參數為掛起進程pid wake_up_process(p);//喚醒進程 printk(“current jiffies is %ld\n”, jiffies); //打印當前jiffies } static int __init timer_init(void){ //定時器初始化過程 printk(“My module worked!\n”); init_timer(&stimer); stimer.data = (unsigned long)current; //將當前進程的pid作為參數傳遞 stimer.expires = jiffies + timeout; //設置到期時間 stimer.function = time_handler; add_timer(&stimer); printk(“current jiffies is %ld\n”, jiffies); set_current_state(TASK_INTERRUPTIBLE); schedule(); //掛起該進程 del_timer(&stimer); //刪除定時器 return 0; } static void __exit timer_exit(void){ printk(“Unloading my module.\n”); return; } module_init(timer_init);//加載模塊 module_exit(timer_exit);//卸載模塊 MODULE_AUTHOR(“fyf”); MODULE_LICENSE(“GPL”);
運行結果:
[ 9850.099121] My module worked!
[ 9850.099127] current jiffies is 2387524
[ 9860.128017] current jiffies is 2390032
[ 9869.135805] Unloading my module.
打印結果與定時時間2500有一點差距,是因為打印時第一次的jiffies實在add_timer之后打印的,故不是定時器激發時的jiffies,第二次同理,所以結果不是確定的,但都於2500相差不多