1. 程式人生 > >linux之延時及核心定時器的使用

linux之延時及核心定時器的使用

想要在核心中的實行短的延時我們可以看這兩個標頭檔案Linux-3.0.1\include\linux下的delay.hlinux-3.0.1\arch\arm\include\asm下的delay.h裡面包含了這樣幾句延時的語句

void ndelay(unsigned long nsecs); //納秒級的延時

void udelay(unsigned long usecs); //微妙級的延時

void mdelay(unsigned long msecs); //毫秒級的延時

用這三個函式我們要重點知道他們是忙等待函式,因此在延時的同時其它程式是無法執行的,如果涉及到毫秒級以上的延時我個人不推薦使用mdelay

因為對於處理器來說毫秒是一個很長的時間,在這之中它可以做很多的事情,因此我們可以使用一下的函式來替換這個函式:

void msleep(unsigned int millsecs); //毫秒級睡眠

unsigned long msleep_interruptible(unsigned int millsecs); //毫秒級帶有中斷喚醒的延時(通常返回值為0,但是如果提前被喚醒則返回剩餘毫秒數)

void ssleep(unsigned int seconds)  //秒級的延時

個人認為這些延時過程當中系統在進行任務的排程,當延時時間到達時,核心在直接排程這個程序。 

核心定時器是基於滴答時鐘實現定時,如果我們需要在將來的某一個時刻讓核心排程執行某段程式,同時在這個時刻到來之前不會阻塞當前程序。

核心定時器的使用只有3個步驟

1.定義定時器結構體

struct timer_list {

struct list_head entry; //定時器列表

unsigned long expires; //定時器到期時間

struct tvec_base *base;

void (*function)(unsigned long); //定時器中斷處理函式

unsigned long data; //作為引數可以傳入定時器中斷處理函式

};

2.給定時器結構體賦定時時間、定時中斷處理函式、傳參設定。

在這裡我講一下定時的數值該怎麼來確定,因為核心定時器是基於jiffies,所以設定的時間要在jiffies

之上加上我們的定時值,比如定時2秒則:2*HZ,看到這個HZ可能會蒙,其實很好理解,在linux-3.0.1\arch\arm\include\asm下的param.h標頭檔案中已經給出,就是每秒中jiffies這個計數器會計多少值。

3.啟用定時器add_timer;

對於上面的第2步,涉及到靜態定義和動態定義兩種方法

靜態定義struct timer_list TIMER_INITIALIZER(_function, _expires, _data);

直接把中斷函式,到期時間,傳入引數寫上即可。

動態定義,就是我們一般的對結構體賦值,非常簡單。不過在賦值之前我們先必須初始化timer_list這個結構體,init_timer(&結構體名);

完成以上步驟之後我們就可以呼叫add_timer函式來啟用定時器開始定時。

當我們啟用定時器後,它只會執行一次處理函式,然後將定時器從核心中移除。但我們平時往往需要重複執行,所以核心給我嗎提供了int mod_timer(struct timer_list *timer, unsigned long expires)

在不用定時器的時候我們需要int del_timer(struct timer_list *timer)需要刪除定時器。

最後講一下核心是如何來管理定時器的,當我們啟動一個定時器的時候,定時器並不是右我們當前載入的模組來管理,而是由核心的swapper程序來接管了這個定時器,當定時器時間一到。核心將呼叫swapper程序執行函式。