日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux 2.6 内核定时器

發布時間:2025/6/17 linux 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux 2.6 内核定时器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、定義:

/include/linux/timer.h

?

struct timer_list {

struct list_head entry;

unsigned long expires;

void (*function)(unsigned long);

unsigned long data;

struct tvec_t_base_s *base;

#ifdef CONFIG_TIMER_STATS

void *start_site;

char start_comm[16];

int start_pid;

#endif

};

二、作用:

一個timer_list結構體的實例對應一個定時器,在linux設備驅動編程中,可以使用timer_list和基于它的一些操作(函數)來完成定時出發工作或者完成某周期性的事物。

三、個字段詳解:

1struct list_head entry;

定時器鏈表,用于存放軟定時器,該鏈表根據定時器expirex字段的值將它們分組存放。

2unsigned long expires;

定時器的到期時間,到達expires時間后,定時器將調用其成員函數function,其中將data字段作為function的參數。該字段表示的時間是以時間節拍為單位。例如如果你想定時一秒,則expires=jiffies+HZ*1。關于jiffies的詳解見:http://blog.chinaunix.net/u2/73528/showart_1130865.html

3void (*function)(unsigned long);

定時器處理函數,也就是說到達expires時間時,function函數將被調用執行。起參數來自定時器的data字段。

4unsigned long data;

在調用function函數時,該字段作為其參數被使用。

四、操作:

1、定義及初始化:

(1)

struct timer_list timer;

void init_timer(struct timer_list *timer);

init_timer()函數被定義在kernel/timer.c中,實際上是將timerentrynext指針置為NULL,base字段賦值。

(2)

struct timer_list timer;

timer=TIMER_INITIALIZER(function,expires,data);

采用這種初始化方式,必須首先先寫好定時器處理函數function. TIMER_INITIALIZER宏的定義如下:

?

#define TIMER_INITIALIZER(_function, _expires, _data) { /

.function = (_function), /

.expires = (_expires), /

.data = (_data), /

.base = &boot_tvec_bases, /

}

其中boot_tcec_bases是在kernel/timer中定義的一個全局的tvec_t_base_s類型的變量。

(3)

DEFINE_TIMER(timer,function,expires,data);

定義并初始化定時器timer,相當于(2).其中DEFINE_TIMER宏的定義為:

?

#define DEFINE_TIMER(_name, _function, _expires, _data) /

struct timer_list _name = /

TIMER_INITIALIZER(_function, _expires, _data

)

(4)

struct timer_list timer;

setup_timer(&timer);

等同于定義方式(2)(3),不過對base字段的賦值是調用了init_timer()函數。setup_timer()原型為:

?

static inline void setup_timer(struct timer_list * timer,

void (*function)(unsigned long),

unsigned long data)

{

timer->function = function;

timer->data = data;

init_timer(timer);

}

?

2、注冊定時器:

在定義并初始化了定時器之后,就要調用add_timer()函數來將該定時器注冊到內核中,這樣定時器才會工作。在注冊之后,定時器就開始計時,在到達時間expires時,執行回調函數function(->data)add_timer()函數的原型為:

?

static inline void add_timer(struct timer_list *timer)

{

BUG_ON(timer_pending(timer));

__mod_timer(timer, timer->expires);

}

?

3、刪除定時器:

int del_timer(struct timer_list *timer);

從內核中刪除已經注冊的定時器timer。如果該定時器是活動的,則返回1,否則返回0

?

int del_timer(struct timer_list *timer)

{

tvec_base_t *base;

unsigned long flags;

int ret = 0;

?

timer_stats_timer_clear_start_info(timer);

if (timer_pending(timer)) {

base = lock_timer_base(timer, &flags);

if (timer_pending(timer)) {

detach_timer(timer, 1);

ret = 1;

}

spin_unlock_irqrestore(&base->lock, flags);

}

?

return ret;

}

?

4、修改定時器的定時時間:

?

int mod_timer(struct timer_list *timer, unsigned long expires)

{

BUG_ON(!timer->function);

?

timer_stats_timer_set_start_info(timer);

/*

* This is a common optimization triggered by the

* networking code - if the timer is re-modified

* to be the same thing then just return:

*/

if (timer->expires == expires && timer_pending(timer))

return 1;

?

return __mod_timer(timer, expires);

}

?

從代碼可以看出,如果所給的要修改的時間等于定時器原來的時間并且定時器現在正處于活動狀態,則不修改,返回1,否則修改定時器時間,返回0mod_timer()是一個非有效的更新處于活動狀態的定時器的時間的方法,如果定時器處于非活動狀態,則會激活定時器。在功能上,mod_timer()等價于:

del_timer(timer);

timer->expires=expires;

add_timer(timer);

?

五、內核延時函數:

1、短延時:

ndelay(unsigned long nsecs); /*延時nsecs納秒*/

udelay(unsigned long usecs); /*延時usecs微秒*/

mdelay(unsigned long msecs); /*延時msecs毫秒*/

此三個宏延時的本質是“忙等待”,也就是說在延時的過程中,并沒有放棄CPU,而是根據CPU的頻率進行一定次數的循環來達到延時的目的。三個宏最終都是將各自的參數(延時的時間)經過一定的換算調用delay_loop()函數來循環耗時達到延時,delay_loop()如下:

?

static void delay_loop(unsigned long loops)

{

int d0;

?

__asm__ __volatile__(

"/tjmp 1f/n"

".align 16/n"

"1:/tjmp 2f/n"

".align 16/n"

"2:/tdecl %0/n/tjns 2b"

:"=&a" (d0)

:"0" (loops));

}

可以明顯的看到每次自減loops,然后判斷,如果為0,則結束,否則跳到標號2處,形成循環。這就是所謂的“忙等待”。

2、長延時:

在內核中,一個直觀的延時的方法是將所要延遲的時間設置的當前的jiffies加上要延遲的時間,這樣就可以簡單的通過比較當前的jiffies和設置的時間來判斷延時的時間時候到來。針對此方法,內核中提供了簡單的宏用于判斷延時是否完成。

time_after(jiffies,delay); /*此刻如果還沒有到達延時的時間,則返回真,否則返回0*/

time_before(jiffies,delay);/*如果延時還沒有完成,則返回真,否則返回0*/

其中time_aftertime_before分別被定義為:

?

#define time_after(a,b) /

(typecheck(unsigned long, a) && /

typecheck(unsigned long, b) && /

((long)(b) - (long)(a) < 0))

#define time_before(a,b) time_after(b,a)

在具體使用中也是將time_after或者time_before作為while循環的判斷語句,進行忙等待延時。

3、睡眠延時:

與忙等待延時相對的是睡眠延時,在延時的過程中,進程是處于睡眠狀態,這意味著其他的任務可以在這是被調度執行,提高了CPU的有效利用率。在睡眠給定的時間后,任務又被重新調度執行。內核提供的睡眠延時函數是:

void msleep(unsigned int msecs)

unsigned long msleep_interruptible(unsigned int msecs)

則會兩個函數的區別是調用msleep()函數進行睡眠延時的進程不能被信號打斷,而調用msleep_interruptible()函數延時的進程可以被信號喚醒。一下給出msleep()函數的代碼:

?

void msleep(unsigned int msecs)

{

unsigned long timeout = msecs_to_jiffies(msecs) + 1;

?

while (timeout)

timeout = schedule_timeout_uninterruptible(timeout);

}

可以看出msleep()本質還是依靠schedule_timeout_uninterruptible()函數實現的。在每次被重新調度執行時,如果睡眠沒有完成,則重新進入睡眠直到到達睡眠的時間。

轉自:http://blog.csdn.net/edison0716/article/details/5415364

轉載于:https://www.cnblogs.com/wangfengju/archive/2013/04/13/6173185.html

總結

以上是生活随笔為你收集整理的Linux 2.6 内核定时器的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。