您的位置 首页 资料

linux驱动之内核定时器驱动规划

我的环境:Fedora14内核版本为26381开发板:ARM9TQ2440移植内核版本:linux-26304定时器在linux内核中主要是采用一个结构体实现

我的环境:

Fedora 14 内核版别为2.6.38.1
开发板:ARM9 TQ2440
移植内核版别:linux-2.6.30.4
守时器在linux内核中首要是选用一个结构体完结的。可是需求留意守时器是一个只运转一次的目标,也便是当一个守时器完毕今后,还需求重现增加守时器。可是能够选用mod_timer()函数动态的改动守时器抵达时刻。
这个驱动首要完结内核守时器的根本操作。内核守时器首要是是经过下面的结构体struct timer_list完结。需求的头文件包括#include,可是在实践开发进程中不需求包括该头文件,由于在sched.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
};
守时器的完结首要是该结构体的填充和部分函数的合作即可完结。其间赤色的部分是最首要的几个元素,1、expires首要是用来界说守时器到期的时刻,一般选用jiffies这个全局变量和HZ这个全局变量合作设置该元素的值。比方expires = jiffies + n*HZ,其间jiffies是自启动以来的滴答数,HZ是一秒种的滴答数。
2、function能够知道是一个函数指针,该函数便是守时器的处理函数,相似咱们在中止中的中止函数,其实守时器和中止有很大的相似性。守时器处理函数是自己界说的函数。
3、data一般是完结参数的传递,从function的参数类型能够知道,data能够作为守时器处理函数的参数。
其他的元素能够经过内核的函数来初始化。
初始化函数为:
init_timer(struct timer_list * timer);
或许直接DEFINE_TIMER宏完结界说和初始化操作。
#define DEFINE_TIMER(_name, _function, _expires, _data)
struct timer_list _name =
TIMER_INITIALIZER(_function, _expires, _data)
增加守时器到内核的函数:
void add_timer(struct timer_list *timer)
{
BUG_ON(timer_pending(timer));
mod_timer(timer, timer->expires);
}
删去守时器函数,假如守时器的守时时刻还没有抵达,那么才能够删去守时器:
int del_timer(struct timer_list *timer)
修正守时器的抵达时刻,该函数的特点是,不论守时器是否抵达时刻,都会重现增加一个守时器到内核。所以能够在守时处理函数中能够调用该函数修正需求从头界说的抵达时刻。
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;
/*留意调用的条件,也便是说明当时的守时器为链表的最终一个*/
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:
*/
/*增加到链表的最终,这说明mod_timer完结了从头注册一个守时器的操作*/
list_add_tail(&timer->entry, vec);
}
从上面的剖析能够看出,mod_timer的完结进程比较复杂,可是根本上说明晰mod_timer函数从头注册守时器的操作进程。
一般来说守时器的根本操作首要是上面的几个函数。
我的根据内核守时器的驱动函数如下,参阅了宋宝华的Linux设备驱动开发详解(第二版)。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/ziliao/317786.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部