更新時間:2020-12-17 17:53:38 來源:動力節(jié)點 瀏覽1513次
Linux內核定時器是內核用來控制在未來某個時間點(基于jiffies)調度執(zhí)行某個函數(shù)的一種機制,其實現(xiàn)位于 <Linux/timer.h> 和 kernel/timer.c 文件中。無論是從單片機還是到后面的多任務系統(tǒng),還是RTOS到Linux,都需要用到定時器。
首先我們要知道被調度的函數(shù)肯定是異步執(zhí)行的,它類似于一種“軟件中斷”,而且是處于非進程的上下文中,所以調度函數(shù)必須遵守以下規(guī)則:
1) 沒有 current 指針、不允許訪問用戶空間。因為沒有進程上下文,相關代碼和被中斷的進程沒有任何聯(lián)系。
2) 不能執(zhí)行休眠(或可能引起休眠的函數(shù))和調度。
3) 任何被訪問的數(shù)據(jù)結構都應該針對并發(fā)訪問進行保護,以防止競爭條件。
而內核定時器的調度函數(shù)運行過一次后就不會再被運行了(相當于自動注銷),但可以通過在被調度的函數(shù)中重新調度自己來周期運行。
在SMP系統(tǒng)中,調度函數(shù)總是在注冊它的同一CPU上運行,以盡可能獲得緩存的局域性。
1.Linux內核定時器的數(shù)據(jù)結構:
struct timer_list {
struct list_head entry;
unsigned long expires;
void (*function)(unsigned long);
unsigned long data;
struct tvec_base *base;
/* ... */
};
其中 expires 字段表示期望定時器執(zhí)行的 jiffies 值,到達該 jiffies 值時,將調用 function 函數(shù),并傳遞 data 作為參數(shù)。當一個定時器被注冊到內核之后,entry 字段用來連接該定時器到一個內核鏈表中。base 字段是內核內部實現(xiàn)所用的。
2.jiffies
全局變量jiffies用來記錄自系統(tǒng)啟動以來產(chǎn)生的節(jié)拍的總數(shù)。啟動時,內核將該變量初始化為0,此后,每次時鐘中斷處理程序都會增加該變量的值。一秒內時鐘中斷的次數(shù)等于Hz,所以jiffies一秒內增加的值也就是Hz。
HZ:這個可以認為是一個頻率,一秒內系統(tǒng)時鐘中斷的次數(shù)
Jiffies/HZ:我想知道從系統(tǒng)開機到現(xiàn)在系統(tǒng)運行了多少秒,可以這樣計算 jiffies類型為無符號長整型(unsigned long)
當jiffies的值超過它的最大存放范圍后就會發(fā)生溢出。對于32位無符號長整型,最大取值為(2^32)-1,即429496795。如果節(jié)拍計數(shù)達到了最大值后還要繼續(xù)增加,它的值就會回繞到0。
3.使用定時器步驟
struct timer_list my_timer_list;//定義一個定時器,可以把它放在你的設備結構中init_timer(&my_timer_list);//初始化一個定時器
my_timer_list.expire=jiffies+HZ;//定時器1s后運行服務程序my_timer_list.function=timer_function;//定時器服務函數(shù)add_timer(&my_timer_list);//添加定時器
void timer_function(unsigned long);//寫定時器服務函數(shù)del_timer(&my_timer_list);//當定時器不再需要時刪除定時器del_timer_sync(&my_timer_list);//基本和del_timer一樣,比較適合在多核處理器使用,一般推薦使用del_timer_sync
4.實例分析#include
#include
#include
#include /*timer*/
#include /*jiffies*/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Qifa");
MODULE_DESCRIPTION("Timer Module");
MODULE_ALIAS("timer module");
struct timer_list timer;
void timer_function(int para)
{
static int i = 0;
printk("#########%d########Timer Expired and para is %d !!\n",i++,para);
printk("jiffies:%lu jiffies/Hz: %lu HZ:%d\n",jiffies,(jiffies/HZ),HZ);
mod_timer(&timer,jiffies+(2*HZ));
}
int timer_init(void)
{
init_timer(&timer);
timer.data = 5;
timer.expires = jiffies + (1 * HZ);
timer.function = timer_function;
add_timer(&timer);
return 0;
}
void timer_exit(void)
{
del_timer( &timer );
}
module_init(timer_init);
module_exit(timer_exit);
使用定時器的目的無外乎是為了周期性的執(zhí)行某一任務,或者是到了一個指定時間去執(zhí)行某一個任務。只要掌握了這一關鍵點,就能更好地理解定時器的工作機制,Linux內核定時器也是如此。在本站的Linux教程里還有關于Linux中其他類型的定時器的介紹,感興趣的小伙伴可以深入學習一下。