【摘要】 內(nèi)核定時(shí)器是內(nèi)核用來控制在未來某個(gè)時(shí)間點(diǎn)(基于jiffies(節(jié)拍總數(shù)))調(diào)度執(zhí)行某個(gè)函數(shù)的一種機(jī)制,相關(guān)函數(shù)位于 和 kernel/timer.c 文件中。 當(dāng)內(nèi)核定時(shí)器定時(shí)時(shí)間到達(dá)時(shí),會(huì)進(jìn)入用戶指定的函數(shù),相當(dāng)于軟中斷。內(nèi)核定時(shí)器注冊開啟后,運(yùn)行一次就不會(huì)再運(yùn)行(相當(dāng)于自動(dòng)注銷),我們可以重新設(shè)置定時(shí)器的超時(shí)時(shí)間,讓定時(shí)器重復(fù)運(yùn)行。
1. 內(nèi)核定時(shí)器介紹
內(nèi)核定時(shí)器是內(nèi)核用來控制在未來某個(gè)時(shí)間點(diǎn)(基于jiffies(節(jié)拍總數(shù)))調(diào)度執(zhí)行某個(gè)函數(shù)的一種機(jī)制,相關(guān)函數(shù)位于 和 kernel/timer.c 文件中。
當(dāng)內(nèi)核定時(shí)器定時(shí)時(shí)間到達(dá)時(shí),會(huì)進(jìn)入用戶指定的函數(shù),相當(dāng)于軟中斷。內(nèi)核定時(shí)器注冊開啟后,運(yùn)行一次就不會(huì)再運(yùn)行(相當(dāng)于自動(dòng)注銷),我們可以重新設(shè)置定時(shí)器的超時(shí)時(shí)間,讓定時(shí)器重復(fù)運(yùn)行。
每當(dāng)時(shí)鐘中斷發(fā)生時(shí),全局變量jiffies(一個(gè)32位的unsigned long 變量)就加1,因此jiffies記錄了linux系統(tǒng)啟動(dòng)后時(shí)鐘中斷發(fā)生的次數(shù),驅(qū)動(dòng)程序常利用jiffies來計(jì)算不同事件間的時(shí)間間隔。內(nèi)核每秒鐘將jiffies變量增加HZ次。因此,對于HZ值為100的系統(tǒng),jiffy+1等于隔了10ms,而對于HZ為1000的系統(tǒng),jiffy+1僅為1ms。
內(nèi)核定時(shí)器結(jié)構(gòu)體:
下面列出了需要關(guān)心的成員
struct timer_list {
unsigned long expires; //設(shè)置超時(shí)時(shí)間,用jiffies作為基準(zhǔn)值
void (*function)(unsigned long); //類似中斷服務(wù)函數(shù),設(shè)置定時(shí)器到時(shí)后處理的函數(shù)
unsigned long data; //中斷服務(wù)函數(shù)的參數(shù)
}
expires設(shè)置:以當(dāng)前時(shí)間為基準(zhǔn)加上延時(shí)時(shí)間,時(shí)間基準(zhǔn)用jiffies變量表示,延時(shí)時(shí)間可以使用以下兩個(gè)宏轉(zhuǎn)換成jiffies單位。
2. 內(nèi)核定時(shí)器相關(guān)API函數(shù)
2.1 修改定時(shí)器超時(shí)時(shí)間
函數(shù)原型 | *int mod_timer(struct timer_list timer, unsigned long expires) |
---|---|
函數(shù)功能 | 修改定時(shí)器超時(shí)時(shí)間 |
函數(shù)參數(shù) | timer:對應(yīng)的定時(shí)器結(jié)構(gòu)體 expires:超時(shí)時(shí)間 |
函數(shù)返回值 | 成功返回 :修改成功的時(shí)間值 |
函數(shù)定義文件 | \linux-3.5\kernel\timer.c |
2.2 初始化定時(shí)器
函數(shù)原型 | #define init_timer(timer)\ |
---|---|
函數(shù)功能 | 初始化定時(shí)器結(jié)構(gòu) |
函數(shù)參數(shù) | timer:對應(yīng)的定時(shí)器結(jié)構(gòu)體 |
函數(shù)定義文件 | \linux-3.5\include\linux\timer.h |
2.3 關(guān)閉定時(shí)器
函數(shù)原型 | int del_timer(struct timer_list *timer) |
---|---|
函數(shù)功能 | 關(guān)閉定時(shí)器,停用一個(gè)定時(shí)器。 |
函數(shù)參數(shù) | timer:對應(yīng)的定 時(shí)器結(jié)構(gòu)體 |
函數(shù)返回值 | 返回0:成功 |
函數(shù)定義文件 | \linux-3.5\include\linux\timer.h |
2.4 關(guān)閉定時(shí)器
函數(shù)原型 | int del_timer_sync(struct timer_list *timer) |
---|---|
函數(shù)功能 | 關(guān)閉定時(shí)器,停用一個(gè)定時(shí)器,多處理器使用。如果編內(nèi)核時(shí)不支持 SMP(多處理器), del_timer_sync()和 del_timer()等價(jià) |
函數(shù)參數(shù) | timer:對應(yīng)的定時(shí)器結(jié)構(gòu)體 |
函數(shù)返回值 | 返回0:成功 |
函數(shù)定義文件 | \linux-3.5\include\linux\timer.h |
2.5 轉(zhuǎn)換時(shí)間(微妙單位)
函數(shù)原型 | unsigned long usecs_to_jiffies(const unsigned int m) |
---|---|
函數(shù)功能 | 轉(zhuǎn)換時(shí)間(微妙單位),用于填充定時(shí)器結(jié)構(gòu)體,設(shè)置超時(shí)時(shí)間 |
函數(shù)參數(shù) | m:要轉(zhuǎn)換的時(shí)間值(微妙為單位) |
函數(shù)返回值 | 成功返回轉(zhuǎn)換成功的時(shí)間。用于填充定時(shí)器結(jié)構(gòu)體,設(shè)置超時(shí)時(shí)間 |
函數(shù)定義文件 | \linux-3.5\kernel\timer.c |
2.6 轉(zhuǎn)換時(shí)間(毫秒為單位)
函數(shù)原型 | unsigned long msecs_to_jiffies(const unsigned int m) |
---|---|
函數(shù)功能 | 轉(zhuǎn)換時(shí)間(毫秒為單位),用于填充定時(shí)器結(jié)構(gòu)體,設(shè)置超時(shí)時(shí)間 |
函數(shù)參數(shù) | m:要轉(zhuǎn)換的時(shí)間值(毫秒為單位) |
函數(shù)返回值 | 成功返回轉(zhuǎn)換成功的時(shí)間。用于填充定時(shí)器結(jié)構(gòu)體,設(shè)置超時(shí)時(shí)間 |
函數(shù)定義文件 | \linux-3.5\kernel\timer.c |
將jiffies單位轉(zhuǎn)為struct timespec結(jié)構(gòu)體表示:
Void jiffies_to_timespec(const unsigned long jiffies, struct timespec *value);
示例:
jiffies_to_timespec(jiffies,&value);
printk("value.ts_sec=%d\n",value.tv_sec);
printk("value.tv_nsec=%d\n",value.tv_nsec);
2.7 初始化定時(shí)器的結(jié)構(gòu)體成員
TIMER_INITIALIZER( _function, _expires, _data) 宏用于賦值定時(shí)器結(jié)構(gòu)體的function、 expires、 data 和 base 成員, 這個(gè)宏的定義如下所示:(被DEFINE_TIMER宏調(diào)用)
#define TIMER_INITIALIZER(_function, _expires, _data) { \
.entry = { .prev = TIMER_ENTRY_STATIC }, \
.function = (_function), \
.expires = (_expires), \
.data = (_data), \
.base = &boot_tvec_bases, \
.slack = -1, \
__TIMER_LOCKDEP_MAP_INITIALIZER( \
__FILE__ ":" __stringify(__LINE__)) \
}
2.8 初始化定時(shí)器并且賦值
DEFINE_TIMER( _na me , _functi o n, _e x pires, _data) 宏是定義并初始化定時(shí)器成員的“快捷方式”, 這個(gè)宏定義如下所示:
/*初始化定時(shí)器,并進(jìn)行賦值*/
#define DEFINE_TIMER(_name, _function, _expires, _data) \
struct timer_list _name = \
TIMER_INITIALIZER(_function, _expires, _data)
2.9 定時(shí)器初始化賦值
setup_timer()也可用于初始化定時(shí)器并賦值其成員, 其源代碼如下:
//初始化定時(shí)器并進(jìn)行賦值
#define setup_timer(timer, fn, data) \
do { \
static struct lock_class_key __key; \
setup_timer_key((timer), #timer, &__key, (fn), (data));\
} while (0)
static inline void setup_timer_key(struct timer_list * timer,
const char *name,
struct lock_class_key *key,
void (*function)(unsigned long),
unsigned long data)
{
timer->function = function;
timer->data = data;
init_timer_key(timer, name, key);
}
3. 使用定時(shí)器的步驟
(1) 定義定時(shí)器結(jié)構(gòu)體timer_list。
/*定義一個(gè)內(nèi)核定時(shí)器配置結(jié)構(gòu)體*/
static struct timer_list mytimer ;
(2) 設(shè)置超時(shí)時(shí)間,定義定時(shí)器處理函數(shù)和傳參。
mytimer.expires=jiffies+ msecs_to_jiffies(1000); /*設(shè)置定時(shí)器的超時(shí)時(shí)間,1000毫秒*/
//或者
//mytimer.expires=jiffies+HZ; /*設(shè)置定時(shí)器的超時(shí)時(shí)間,1000毫秒*/
mytimer.function = time_fun; /*定時(shí)器超時(shí)的回調(diào)函數(shù),類似中斷服務(wù)函數(shù)*/
mytimer.data = 12; /*傳給定時(shí)器服務(wù)函數(shù)的參數(shù)*/
(3) 開啟定時(shí)器。
init_timer(&mytimer); /*初始化定時(shí)器*/
add_timer(&mytimer); /*啟動(dòng)定時(shí)器*/
完整示例代碼:
#include
#include
#include
static struct timer_list timer;
static void timer_function(unsigned long data)
{
printk("data=%ld\n",data);
mod_timer(&timer,msecs_to_jiffies(3000)+jiffies);
}
static int __init tiny4412_linux_timer_init(void)
{
timer.expires=HZ*3+jiffies; /*單位是節(jié)拍*/
timer.function=timer_function;
timer.data=666;
/*1. 初始化定時(shí)器*/
init_timer(&timer);
/*2. 添加定時(shí)器到內(nèi)核*/
add_timer(&timer);
printk("驅(qū)動(dòng)測試: 驅(qū)動(dòng)安裝成功\n");
return 0;
}
static void __exit tiny4412_linux_timer_cleanup(void)
{
/*3. 刪除定時(shí)器*/
del_timer_sync(&timer);
printk("驅(qū)動(dòng)測試: 驅(qū)動(dòng)卸載成功\n");
}
module_init(tiny4412_linux_timer_init); /*驅(qū)動(dòng)入口--安裝驅(qū)動(dòng)的時(shí)候執(zhí)行*/
module_exit(tiny4412_linux_timer_cleanup); /*驅(qū)動(dòng)出口--卸載驅(qū)動(dòng)的時(shí)候執(zhí)行*/
MODULE_LICENSE("GPL"); /*設(shè)置模塊的許可證--GPL*/
4. 內(nèi)核提供的延時(shí)函數(shù)
Linux 內(nèi)核中提供了進(jìn)行納秒、微秒和毫秒延遲。
void ndelay(unsigned long nsecs) ;
void udelay(unsigned long usecs) ;
void mdelay(unsigned long msecs) ;
上述延遲的實(shí)現(xiàn)原理本質(zhì)上是忙等待,根據(jù) CPU 頻率進(jìn)行一定次數(shù)的循環(huán)。在內(nèi)核中,最好不要直接使用mdelay()函數(shù), 這將無謂地耗費(fèi)CPU資源。
void msleep(unsigned int millisecs) ;
unsigned long msleep_interruptible(unsigned int millisecs) ;
void ssleep(unsigned int seconds) ;
上述函數(shù)將使得調(diào)用它的進(jìn)程睡眠參數(shù)指定的時(shí)間, msleep()、 ssleep()不能被打斷,而 msleep_interruptible()則可以被打斷。
5. 精度較高的時(shí)間獲取方式
高精度定時(shí)器通常用ktime作為計(jì)時(shí)單位。
獲取內(nèi)核高精度時(shí)間單位: ktime_t ktime_get(void)
下面是一些時(shí)間輔助函數(shù)用于計(jì)算和轉(zhuǎn)換:
ktime_t ktime_set(const long secs, const unsigned long nsecs);
ktime_t ktime_sub(const ktime_t lhs, const ktime_t rhs);
ktime_t ktime_add(const ktime_t add1, const ktime_t add2);
ktime_t ktime_add_ns(const ktime_t kt, u64 nsec);
ktime_t ktime_sub_ns(const ktime_t kt, u64 nsec);
ktime_t timespec_to_ktime(const struct timespec ts);
ktime_t timeval_to_ktime(const struct timeval tv);
struct timespec ktime_to_timespec(const ktime_t kt); //轉(zhuǎn)換的時(shí)間通過timespec結(jié)構(gòu)體保存
struct timeval ktime_to_timeval(const ktime_t kt); //轉(zhuǎn)換的時(shí)間通過timeval結(jié)構(gòu)體保存
s64 ktime_to_ns(const ktime_t kt); //轉(zhuǎn)換為ns單位
int ktime_equal(const ktime_t cmp1, const ktime_t cmp2);
s64 ktime_to_us(const ktime_t kt); //轉(zhuǎn)換為us單位
s64 ktime_to_ms(const ktime_t kt); //轉(zhuǎn)換為ms單位
ktime_t ns_to_ktime(u64 ns);
示例: 計(jì)算經(jīng)過的一段時(shí)間
static int hello_init(void)
{
ktime_t my_time,my_time2;
unsigned int i,j;
unsigned int time_cnt=0;
my_time=ktime_get(); //獲取當(dāng)前時(shí)間
i=ktime_to_us(my_time); //轉(zhuǎn)us
udelay(600); //延時(shí)一段時(shí)間
my_time2=ktime_get(); //獲取當(dāng)前時(shí)間
j=ktime_to_us(my_time2); //轉(zhuǎn)us
printk("time_cnt=%ld\n",j-i); //得出之間差值,正確值為: 600
return 0;
}
-
內(nèi)核
+關(guān)注
關(guān)注
3文章
1372瀏覽量
40276 -
定時(shí)器
+關(guān)注
關(guān)注
23文章
3246瀏覽量
114715 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4327瀏覽量
62569
發(fā)布評論請先 登錄
相關(guān)推薦
評論