內(nèi)核定時(shí)器

定時(shí)器的使用

1、定義定時(shí)器結(jié)構(gòu)體timer_list。

2、設(shè)置超時(shí)時(shí)間,定義定時(shí)器處理函數(shù)和傳參。

3、激活定時(shí)器。

1、定義并初始化定時(shí)器結(jié)構(gòu)體timer_list。

/*include/linux/timer.h*/
struct timer_list {
struct list_head entry;
unsigned long expires; //設(shè)置在執(zhí)行定時(shí)器處理函數(shù)的時(shí)間
void (*function)(unsigned long); //定時(shí)器處理函數(shù)
unsigned long data; //處理函數(shù)的傳參
...
靜態(tài)定義并初始化:

初始化結(jié)構(gòu)體的同時(shí)給指定測成員賦值
動態(tài)初始化

struct timer_list TIMER_INITIALIZER(_function, _expires, _data);
動態(tài)初始化:
/*定義一個(gè)名為my_timer的timer_list數(shù)據(jù)結(jié)構(gòu)*/
struct timer_list my_timer;
/*初始化my_timer的部分內(nèi)部成員*/
init_timer(&my_timer);

2、設(shè)置超時(shí)時(shí)間,定義定時(shí)器處理函數(shù)和傳參。

這一步驟是要填充timer_list的三個(gè)成員:expires、function和data。

void timer_func(unsigned long data) //2.定義定時(shí)器處理函數(shù)
{
printk("time out![%d] [%s]\n", (int)data, current->comm);
}
然后給timer_list的三個(gè)成員賦值:

my_timer.expires = jiffies + 5*HZ; //2.設(shè)定定時(shí)器處理函數(shù)觸發(fā)時(shí)間為5秒
my_timer.function = timer_func; //2.給結(jié)構(gòu)體指定定時(shí)器處理函數(shù)
my_timer.data = (unsigned long)99; //2.設(shè)定定時(shí)器處理函數(shù)的傳參

當(dāng)前時(shí)間(jiffies)的后5秒(5*HZ)

3、激活定時(shí)器。

add_timer(&my_timer); //3.激活定時(shí)器

int mod_timer(struct timer_list *timer, unsigned long expires)
//這是改變定時(shí)器超時(shí)時(shí)間的函數(shù),如果在指定的定時(shí)器(timer)沒超時(shí)前調(diào)用,超時(shí)時(shí)間會更新為新的新的超時(shí)時(shí)間(expires)。如果在定時(shí)器超時(shí)后調(diào)用,那就相當(dāng)于重新指定超時(shí)時(shí)間并再次激活定時(shí)器。
irqreturn_t irq_handler(int irqno, void *dev_id)
15 {
16 printk("irq\n");
17 /*0.5秒觸發(fā)一次定時(shí)器處理函數(shù),則只有最后一次抖動的中斷會觸發(fā)timer_func*/
18 mod_timer(&my_timer, jiffies + 100); //0.5*200 = 100
19 return IRQ_HANDLED; //表示中斷在處理,IRQ_NONE表示中斷沒處理
20 }

每次進(jìn)入中斷,都會刷新定時(shí)器的值。當(dāng)按下按鍵時(shí),由于抖動的關(guān)系,會出現(xiàn)多次的中斷,但只有最后的一次中斷才會觸發(fā)一次定時(shí)器處理函數(shù)。

jiffies 回繞

全局變量#### jiffies 用來記錄自啟動以來產(chǎn)生的節(jié)拍的總數(shù)。系統(tǒng)啟動時(shí)會將該變量初始化為0,此后,每當(dāng)時(shí)鐘中斷產(chǎn)生時(shí)就會增加該變量的值。 jiffies和另外一個(gè)變量息息相關(guān):HZ。HZ是每秒系統(tǒng)產(chǎn)生的時(shí)鐘中斷次數(shù),所以jiffies每秒增加的值也就是HZ.
在2.6內(nèi)核中被定義為1000
extern unsigned long volatile jiffies;
如果HZ為1000,那么回繞時(shí)間將只有50天左 右。如果發(fā)生了回繞現(xiàn)象,對內(nèi)核中直接利用jiffies來比較時(shí)間的代碼將產(chǎn)生很不利的影響,

內(nèi)核也專門針對這種情況提供了四個(gè)宏來幫助比較jiffies計(jì)數(shù):

  #define time_after(unknown,known) ((long)(known) - (long)(unknown)<0)
  #define time_before(unkonwn,known) ((long)(unknown) - (long)(known)<0)
  #define time_after_eq(unknown,known) ((long)(unknown) - (long)(known)>=0)
  #define time_before_eq(unknown,known) ((long)(known) -(long)(unknown)>=0)
原碼

原碼采 用一個(gè)最高位作為符號位,其余位是數(shù)據(jù)大小的二進(jìn)制表示。
正數(shù)的補(bǔ)碼即為原碼,負(fù)數(shù)的補(bǔ)碼為原碼除符號位外其他各位取反再加1

unsigned long timeout = jiffies + HZ/2; /* timeout in 0.5s */  
  
/* do some work ... */  
do_somework();  
  
/* then see whether we took too long */  
if (time_before(jiffies, timeout)) {  
/* we did not time out, call no_timeout_handler() ... */  
no_timeout_handler();  
  
} else {  
/* we timed out, call timeout_handler() ... */  
timeout_handler();  
}  
time_after等比較時(shí)間先后的宏背后的原理

上述time_after等比較時(shí)間先/后的宏為什么能夠解決jiffies溢出造成的錯(cuò)誤情況呢?
我們?nèi)匀灰?位無符號整型(unsigned char)為例來加以說明。仿照上面的time_after宏,我們可以給出簡化的8位無符號整型對應(yīng)的after宏:

define uc_after(a, b) ((char)(b) - (char)(a) < 0)

設(shè)a和b的數(shù)據(jù)類型為unsigned char,b為臨近8位無符號整型最大值附近的一個(gè)固定值254,下面給出隨著a(設(shè)其初始值為254)變化而得到的計(jì)算值:

a b (char)(b) - (char)(a)
254 254 0
255 - 1
0 - 2
1 - 3
...
124 -126
125 -127
126 -128
127 127
128 126
...
252 2
253 1

從上面的計(jì)算可以看出,設(shè)定b不變,隨著a(設(shè)其初始值為254)不斷增長1,a的取值變化為:
254, 255,一次產(chǎn)生溢出
0, 1, ..., 124, 125, 126, 127, 126, ..., 253, 254, 255, (二次產(chǎn)生溢出)
0, 1, ...
...

而(char)(b) - (char)(a)的變化為:
0, -1,
-2, -3, ..., -126, -127, -128, 127, 126, ..., 1, 0, -1,
-2, -3, ...
...

從上面的詳細(xì)過程可以看出,當(dāng)a取值為254,255, 接著在(一次產(chǎn)生溢出)之后變?yōu)?,然后增長到127之前,uc_after(a,b)的結(jié)果都顯示a是在b之后,這也與我們的預(yù)期相符。但在a取值為 127之后,uc_after(a,b)的結(jié)果卻顯示a是在b之前。

從上面的運(yùn)算過程可以得出以下結(jié)論:
使用uc_after(a,b)宏來計(jì)算兩個(gè)8位無符號整型a和b之間的大?。ɑ蛳?后,before/after),那么a和b的取值應(yīng)當(dāng)滿足以下限定條件:

兩個(gè)值之間相差從邏輯值來講應(yīng)小于有符號整型的最大值。

比如: 對于8位無符號整型,兩個(gè)值之間相差從邏輯值來講應(yīng)小于128。

對于32位無符號整型,兩個(gè)值之間相差從邏輯值來講應(yīng)小于2147483647。

對于HZ=100,那么兩個(gè)時(shí)間值之間相差不應(yīng)當(dāng)超過2147483647/100秒 = 0.69年 = 248.5天。對于HZ=60,那么兩個(gè)時(shí)間值之間相差不應(yīng)當(dāng)超過2147483647/60秒 = 1.135年。

在實(shí)際代碼應(yīng)用中,需要比較先/后的兩個(gè)時(shí)間值之間一般都相差很小,范圍大致在1秒~1天左右,所以以上time_after等比較時(shí)間先 /后的宏完全可以放心地用于實(shí)際的代碼中。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1、綜述 基于硬件工程師的提出的一個(gè)測試需求:每隔5秒鐘拉高PA的使能腳,間隔5秒鐘再拉低PA使能腳(這里的PA ...
    擼碼的日子閱讀 15,456評論 0 10
  • 主要內(nèi)容:Linux-定時(shí)器 知識點(diǎn): 1.Linux定時(shí)器基礎(chǔ)知識 1.1 定時(shí)器的使用范圍(延后執(zhí)行某個(gè)操作,...
    嵌入式工作閱讀 1,477評論 0 0
  • 內(nèi)核定時(shí)器可用來在未來的某個(gè)時(shí)間點(diǎn)(基于時(shí)鐘滴答)調(diào)度執(zhí)行的某個(gè)函數(shù)。 當(dāng)定時(shí)器運(yùn)行時(shí),調(diào)度定時(shí)器的進(jìn)程可能正在休...
    rlkbk閱讀 403評論 0 0
  • 專業(yè)考題類型管理運(yùn)行工作負(fù)責(zé)人一般作業(yè)考題內(nèi)容選項(xiàng)A選項(xiàng)B選項(xiàng)C選項(xiàng)D選項(xiàng)E選項(xiàng)F正確答案 變電單選GYSZ本規(guī)程...
    小白兔去釣魚閱讀 10,564評論 0 13
  • 今天老公去辦了一件事,他自己成為了戶主,真是值得開心的事情。 伴隨著開學(xué),今天又做了一件不應(yīng)該的事,不該因?yàn)橐稽c(diǎn)小...
    格格巫的小房子閱讀 141評論 0 0

友情鏈接更多精彩內(nèi)容