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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

内核定时器的使用

發(fā)布時(shí)間:2025/3/21 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 内核定时器的使用 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

???內(nèi)核定時(shí)器的使用

LINUX內(nèi)核定時(shí)器是內(nèi)核用來控制在未來某個(gè)時(shí)間點(diǎn)(基于jiffies)調(diào)度執(zhí)行某個(gè)函數(shù)的一種機(jī)制,其實(shí)現(xiàn)位于?<linux/timer.h>和?kernel/timer.c?文件中。

被調(diào)度的函數(shù)肯定是異步執(zhí)行的,它類似于一種“軟件中斷”,而且是處于非進(jìn)程的上下文中,所以調(diào)度函數(shù)必須遵守以下規(guī)則:

1)?沒有?current?指針、不允許訪問用戶空間。因?yàn)闆]有進(jìn)程上下文,相關(guān)代碼和被中斷的進(jìn)程沒有任何聯(lián)系。

2)?不能執(zhí)行休眠(或可能引起休眠的函數(shù))和調(diào)度。

3)?任何被訪問的數(shù)據(jù)結(jié)構(gòu)都應(yīng)該針對并發(fā)訪問進(jìn)行保護(hù),以防止競爭條件。

?

內(nèi)核定時(shí)器的調(diào)度函數(shù)運(yùn)行過一次后就不會(huì)再被運(yùn)行了(相當(dāng)于自動(dòng)注銷),但可以通過在被調(diào)度的函數(shù)中重新調(diào)度自己來周期運(yùn)行。

?

在SMP系統(tǒng)中,調(diào)度函數(shù)總是在注冊它的同一CPU上運(yùn)行,以盡可能獲得緩存的局域性。

?

定時(shí)器API

?

內(nèi)核定時(shí)器的數(shù)據(jù)結(jié)構(gòu)

struct timer_list {

????struct list_head entry;

?

????unsigned long expires;

????void (*function)(unsigned long);

????unsigned long data;

?

????struct tvec_base *base;

????/* ... */

};

其中?expires?字段表示期望定時(shí)器執(zhí)行的?jiffies?值,到達(dá)該?jiffies?值時(shí),將調(diào)用?function?函數(shù),并傳遞?data?作為參數(shù)。當(dāng)一個(gè)定時(shí)器被注冊到內(nèi)核之后,entry?字段用來連接該定時(shí)器到一個(gè)內(nèi)核鏈表中。base?字段是內(nèi)核內(nèi)部實(shí)現(xiàn)所用的。

需要注意的是?expires?的值是32位的,因?yàn)閮?nèi)核定時(shí)器并不適用于長的未來時(shí)間點(diǎn)。

?

初始化

在使用?struct timer_list?之前,需要初始化該數(shù)據(jù)結(jié)構(gòu),確保所有的字段都被正確地設(shè)置。初始化有兩種方法。

方法一:

DEFINE_TIMER(timer_name, function_name, expires_value, data);

該宏會(huì)靜態(tài)創(chuàng)建一個(gè)名叫?timer_name?內(nèi)核定時(shí)器,并初始化其?function, expires, name?和?base?字段。

?

方法二:

struct timer_list mytimer;

setup_timer(&mytimer, (*function)(unsigned long), unsigned long data);

mytimer.expires = jiffies + 5*HZ;

方法3:

struct timer_list mytimer;

init_timer(&mytimer);????

??mytimer ->timer.expires = jiffies + 5*HZ;

??mytimer ->timer.data = (unsigned long) dev;

??mytimer ->timer.function = &corkscrew_timer; /* timer handler */

通過init_timer()動(dòng)態(tài)地定義一個(gè)定時(shí)器,此后,將處理函數(shù)的地址和參數(shù)綁定給一個(gè)timer_list,

注意,無論用哪種方法初始化,其本質(zhì)都只是給字段賦值,所以只要在運(yùn)行?add_timer()?之前,expires, function?和?data?字段都可以直接再修改。

關(guān)于上面這些宏和函數(shù)的定義,參見?include/linux/timer.h。

?

注冊

定時(shí)器要生效,還必須被連接到內(nèi)核專門的鏈表中,這可以通過?add_timer(struct timer_list *timer)?來實(shí)現(xiàn)。

?

重新注冊

要修改一個(gè)定時(shí)器的調(diào)度時(shí)間,可以通過調(diào)用?mod_timer(struct timer_list *timer, unsigned long expires)。mod_timer()?會(huì)重新注冊定時(shí)器到內(nèi)核,而不管定時(shí)器函數(shù)是否被運(yùn)行過。

?

注銷

注銷一個(gè)定時(shí)器,可以通過?del_timer(struct timer_list *timer)?或?del_timer_sync(struct timer_list *timer)。其中?del_timer_sync?是用在?SMP?系統(tǒng)上的(在非SMP系統(tǒng)上,它等于del_timer),當(dāng)要被注銷的定時(shí)器函數(shù)正在另一個(gè)?cpu?上運(yùn)行時(shí),del_timer_sync()?會(huì)等待其運(yùn)行完,所以這個(gè)函數(shù)會(huì)休眠。另外還應(yīng)避免它和被調(diào)度的函數(shù)爭用同一個(gè)鎖。對于一個(gè)已經(jīng)被運(yùn)行過且沒有重新注冊自己的定時(shí)器而言,注銷函數(shù)其實(shí)也沒什么事可做。

?

int timer_pending(const struct timer_list *timer)

這個(gè)函數(shù)用來判斷一個(gè)定時(shí)器是否被添加到了內(nèi)核鏈表中以等待被調(diào)度運(yùn)行。注意,當(dāng)一個(gè)定時(shí)器函數(shù)即將要被運(yùn)行前,內(nèi)核會(huì)把相應(yīng)的定時(shí)器從內(nèi)核鏈表中刪除(相當(dāng)于注銷)

?

一個(gè)簡單的例子

#include <linux/module.h>

#include <linux/timer.h>

#include <linux/jiffies.h>

?

struct timer_list mytimer;

?

static void myfunc(unsigned long data)

{

????????printk("%s/n", (char *)data);

????????mod_timer(&mytimer, jiffies + 2*HZ);

}

?

static int __init mytimer_init(void)

{

????????setup_timer(&mytimer, myfunc, (unsigned long)"Hello, world!");

????????mytimer.expires = jiffies + HZ;

????????add_timer(&mytimer);

?

????????return 0;

}

?

static void __exit mytimer_exit(void)

{

????????del_timer(&mytimer);

}

?

module_init(mytimer_init);

module_exit(mytimer_exit);

?

例子2

static struct timer_list power_button_poll_timer;

?

static void power_button_poll(unsigned long dummy)

{

?if (gpio_line_get(N2100_POWER_BUTTON) == 0) {

??ctrl_alt_del();

??return;

?}

?

?power_button_poll_timer.expires = jiffies + (HZ / 10);

?add_timer(&power_button_poll_timer);

}

?

?

static void __init n2100_init_machine(void)

{

?init_timer(&power_button_poll_timer);

?power_button_poll_timer.function = power_button_poll;

?power_button_poll_timer.expires = jiffies + (HZ / 10);

?add_timer(&power_button_poll_timer);

}

?

?

?

例子3

?

設(shè)備open時(shí)初始化和注冊定時(shí)器

?

static int corkscrew_open(struct net_device *dev)

?

{

??init_timer(&vp->timer);????

??vp->timer.expires = jiffies + media_tbl[dev->if_port].wait;

??vp->timer.data = (unsigned long) dev;

??vp->timer.function = &corkscrew_timer; /* timer handler */

??add_timer(&vp->timer);

}

定時(shí)器超時(shí)處理函數(shù),對定時(shí)器的超時(shí)時(shí)間重新賦值

?

static void corkscrew_timer(unsigned long data)

{

????vp->timer.expires = jiffies + media_tbl[dev->if_port].wait;

????add_timer(&vp->timer);

}

?

設(shè)備close時(shí)刪除定時(shí)器

static int corkscrew_close(struct net_device *dev)

{

?;

?del_timer(&vp->timer);

}

例子4

本例子用DEFINE_TIMER靜態(tài)創(chuàng)建定時(shí)器

#include <linux/module.h>

#include <linux/jiffies.h>

#include <linux/kernel.h>

#include <linux/init.h>

#include <linux/timer.h>

#include <linux/leds.h>

?

static void ledtrig_ide_timerfunc(unsigned long data);

?

DEFINE_LED_TRIGGER(ledtrig_ide);

static DEFINE_TIMER(ledtrig_ide_timer, ledtrig_ide_timerfunc, 0, 0);

static int ide_activity;

static int ide_lastactivity;

?

void ledtrig_ide_activity(void)

{

???????ide_activity++;

???????if (!timer_pending(&ledtrig_ide_timer))

??????????????mod_timer(&ledtrig_ide_timer, jiffies + msecs_to_jiffies(10));

}

EXPORT_SYMBOL(ledtrig_ide_activity);

?

static void ledtrig_ide_timerfunc(unsigned long data)

{

???????if (ide_lastactivity != ide_activity) {

??????????????ide_lastactivity = ide_activity;

??????????????led_trigger_event(ledtrig_ide, LED_FULL);

??????????????mod_timer(&ledtrig_ide_timer, jiffies + msecs_to_jiffies(10));

???????} else {

??????????????led_trigger_event(ledtrig_ide, LED_OFF);

???????}

}

?

static int __init ledtrig_ide_init(void)

{

???????led_trigger_register_simple("ide-disk", &ledtrig_ide);

???????return 0;

}

?

static void __exit ledtrig_ide_exit(void)

{

???????led_trigger_unregister_simple(ledtrig_ide);

}

?

module_init(ledtrig_ide_init);

module_exit(ledtrig_ide_exit);

?

MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");

MODULE_DESCRIPTION("LED IDE Disk Activity Trigger");

MODULE_LICENSE("GPL");

?

?

總結(jié)

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

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。