新聞中心

EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > linux驅(qū)動(dòng)之內(nèi)核定時(shí)器驅(qū)動(dòng)設(shè)計(jì)

linux驅(qū)動(dòng)之內(nèi)核定時(shí)器驅(qū)動(dòng)設(shè)計(jì)

作者: 時(shí)間:2016-12-01 來(lái)源:網(wǎng)絡(luò) 收藏
我的環(huán)境:
Fedora 14 內(nèi)核版本為2.6.38.1
開(kāi)發(fā)板:ARM9 TQ2440
移植內(nèi)核版本:linux-2.6.30.4
定時(shí)器在linux內(nèi)核中主要是采用一個(gè)結(jié)構(gòu)體實(shí)現(xiàn)的。但是需要注意定時(shí)器是一個(gè)只運(yùn)行一次的對(duì)象,也就是當(dāng)一個(gè)定時(shí)器結(jié)束以后,還需要重現(xiàn)添加定時(shí)器。但是可以采用mod_timer()函數(shù)動(dòng)態(tài)的改變定時(shí)器到達(dá)時(shí)間。
這個(gè)驅(qū)動(dòng)主要實(shí)現(xiàn)內(nèi)核定時(shí)器的基本操作。內(nèi)核定時(shí)器主要是是通過(guò)下面的結(jié)構(gòu)體struct timer_list實(shí)現(xiàn)。需要的頭文件包括#include,但是在實(shí)際開(kāi)發(fā)過(guò)程中不需要包含該頭文件,因?yàn)樵趕ched.h中包含了該頭文件。
struct timer_list {
struct list_head entry;
unsigned long expires;
void (*function)(unsigned long);
unsigned long data;
struct tvec_base *base;
#ifdef CONFIG_TIMER_STATS
void *start_site;
char start_comm[16];
int start_pid;
#endif
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
定時(shí)器的實(shí)現(xiàn)主要是該結(jié)構(gòu)體的填充和部分函數(shù)的配合即可完成。其中紅色的部分是最主要的幾個(gè)元素,1、expires主要是用來(lái)定義定時(shí)器到期的時(shí)間,通常采用jiffies這個(gè)全局變量和HZ這個(gè)全局變量配合設(shè)置該元素的值。比如expires = jiffies + n*HZ,其中jiffies是自啟動(dòng)以來(lái)的滴答數(shù),HZ是一秒種的滴答數(shù)。
2、function可以知道是一個(gè)函數(shù)指針,該函數(shù)就是定時(shí)器的處理函數(shù),類(lèi)似我們?cè)谥袛嘀械闹袛嗪瘮?shù),其實(shí)定時(shí)器和中斷有很大的相似性。定時(shí)器處理函數(shù)是自己定義的函數(shù)。
3、data通常是實(shí)現(xiàn)參數(shù)的傳遞,從function的參數(shù)類(lèi)型可以知道,data可以作為定時(shí)器處理函數(shù)的參數(shù)。
其他的元素可以通過(guò)內(nèi)核的函數(shù)來(lái)初始化。
初始化函數(shù)為:
init_timer(struct timer_list * timer);
或者直接DEFINE_TIMER宏實(shí)現(xiàn)定義和初始化操作。
#define DEFINE_TIMER(_name, _function, _expires, _data)
struct timer_list _name =
TIMER_INITIALIZER(_function, _expires, _data)
添加定時(shí)器到內(nèi)核的函數(shù):
void add_timer(struct timer_list *timer)
{
BUG_ON(timer_pending(timer));
mod_timer(timer, timer->expires);
}
刪除定時(shí)器函數(shù),如果定時(shí)器的定時(shí)時(shí)間還沒(méi)有到達(dá),那么才可以刪除定時(shí)器:
int del_timer(struct timer_list *timer)
修改定時(shí)器的到達(dá)時(shí)間,該函數(shù)的特點(diǎn)是,不管定時(shí)器是否到達(dá)時(shí)間,都會(huì)重現(xiàn)添加一個(gè)定時(shí)器到內(nèi)核。所以可以在定時(shí)處理函數(shù)中可以調(diào)用該函數(shù)修改需要重新定義的到達(dá)時(shí)間。
int mode_timer(struct timer_list *timer,unsigned long expires)
int mod_timer(struct timer_list *timer, unsigned long expires)
{
/*
* 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;
/*注意調(diào)用的條件,也就是說(shuō)明當(dāng)前的定時(shí)器為鏈表的最后一個(gè)*/
return __mod_timer(timer, expires, false);
}
static inline int
__mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
{
struct tvec_base *base, *new_base;
unsigned long flags;
int ret;
ret = 0;
timer_stats_timer_set_start_info(timer);
BUG_ON(!timer->function);
base = lock_timer_base(timer, &flags);
if (timer_pending(timer)) {
detach_timer(timer, 0);
ret = 1;
} else {
if (pending_only)
goto out_unlock;
}
debug_timer_activate(timer);
new_base = __get_cpu_var(tvec_bases);
if (base != new_base) {
/*
* We are trying to schedule the timer on the local CPU.
* However we cant change timers base while it is running,
* otherwise del_timer_sync() cant detect that the timers
* handler yet has not finished. This also guarantees that
* the timer is serialized wrt itself.
*/
if (likely(base->running_timer != timer)) {
/* See the comment in lock_timer_base() */
timer_set_base(timer, NULL);
spin_unlock(&base->lock);
base = new_base;
spin_lock(&base->lock);
timer_set_base(timer, base);
}
}
timer->expires = expires;
internal_add_timer(base, timer);
out_unlock:
spin_unlock_irqrestore(&base->lock, flags);
return ret;
}
static void internal_add_timer(struct tvec_base *base, struct timer_list *timer)
{
unsigned long expires = timer->expires;
unsigned long idx = expires - base->timer_jiffies;
struct list_head *vec;
if (idx < TVR_SIZE) {
int i = expires & TVR_MASK;
vec = base->tv1.vec + i;
} else if (idx < 1 << (TVR_BITS + TVN_BITS)) {
int i = (expires >> TVR_BITS) & TVN_MASK;
vec = base->tv2.vec + i;
} else if (idx < 1 << (TVR_BITS + 2 * TVN_BITS)) {
int i = (expires >> (TVR_BITS + TVN_BITS)) & TVN_MASK;
vec = base->tv3.vec + i;
} else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)) {
int i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK;
vec = base->tv4.vec + i;
} else if ((signed long) idx < 0) {
/*
* Can happen if you add a timer with expires == jiffies,
* or you set a timer to go off in the past
*/
vec = base->tv1.vec + (base->timer_jiffies & TVR_MASK);
} else {
int i;
/* If the timeout is larger than 0xffffffff on 64-bit
* architectures then we use the maximum timeout:
*/
if (idx > 0xffffffffUL) {
idx = 0xffffffffUL;
expires = idx + base->timer_jiffies;
}
i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;
vec = base->tv5.vec + i;
}
/*
* Timers are FIFO:
*/
/*添加到鏈表的最后,這說(shuō)明mod_timer實(shí)現(xiàn)了重新注冊(cè)一個(gè)定時(shí)器的操作*/
list_add_tail(&timer->entry, vec);
}
從上面的分析可以看出,mod_timer的實(shí)現(xiàn)過(guò)程比較復(fù)雜,但是基本上說(shuō)明了mod_timer函數(shù)重新注冊(cè)定時(shí)器的操作過(guò)程。
一般而言定時(shí)器的基本操作主要是上面的幾個(gè)函數(shù)。
我的基于內(nèi)核定時(shí)器的驅(qū)動(dòng)函數(shù)如下,參考了宋寶華的Linux設(shè)備驅(qū)動(dòng)開(kāi)發(fā)詳解(第二版)。
上一頁(yè) 1 2 下一頁(yè)

評(píng)論


技術(shù)專(zhuān)區(qū)

關(guān)閉