一、定义:
/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和基于它的一些操作(函数)来完成定时出发工作或者完成某周期性的事物。
三、个字段详解:
1、struct list_head entry;
定时器链表,用于存放软定时器,该链表根据定时器expirex字段的值将它们分组存放。
2、unsigned long expires;
定时器的到期时间,到达expires时间后,定时器将调用其成员函数function,其中将data字段作为function的参数。该字段表示的时间是以时间节拍为单位。例如如果你想定时一秒,则expires=jiffies+HZ*1。关于jiffies的详解见:http://blog.chinaunix.net/u2/73528/showart_1130865.html
3、void (*function)(unsigned long);
定时器处理函数,也就是说到达expires时间时,function函数将被调用执行。起参数来自定时器的data字段。
4、unsigned long data;
在调用function函数时,该字段作为其参数被使用。
四、操作:
1、定义及初始化:
(1)
struct timer_list timer;
void init_timer(struct timer_list *timer);
init_timer()函数被定义在kernel/timer.c中,实际上是将timer的entry的next指针置为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,否则修改定时器时间,返回0。mod_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_after和time_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
分享到:
相关推荐
《Linux2.6内核标准教程》适合Linux内核爱好者、Linux驱动开发人员、Linux系统工程师参考使用,也可以作为计算机及相关专业学生深入学 习操作系统的参考书。 引用: 目录 第1章 Linux内核学习基础 1 1.1 为什么...
《Linux2.6内核标准教程》适合Linux内核爱好者、Linux驱动开发人员、Linux系统工程师参考使用,也可以作为计算机及相关专业学生深入学 习操作系统的参考书。 引用: 目录 第1章 Linux内核学习基础 1 1.1 为什么...
《Linux 2.6内核标准教程》是一本专为Linux内核爱好者、驱动开发者和系统工程师设计的深度解析书籍。它旨在帮助读者理解和掌握Linux内核的核心工作原理,通过详细解析内核的关键组件,引领读者进入Linux内核的世界。...
《Linux2.6内核标准教程》适合Linux内核爱好者、Linux驱动开发人员、Linux系统工程师参考使用,也可以作为计算机及相关专业学生深入学 习操作系统的参考书。 引用: 目录 第1章 Linux内核学习基础 1 1.1 为什么...
《Linux2.6内核标准教程》适合Linux内核爱好者、Linux驱动开发人员、Linux系统工程师参考使用,也可以作为计算机及相关专业学生深入学 习操作系统的参考书。 引用: 目录 第1章 Linux内核学习基础 1 1.1 为什么...
《Linux2.6内核标准教程》适合Linux内核爱好者、Linux驱动开发人员、Linux系统工程师参考使用,也可以作为计算机及相关专业学生深入学 习操作系统的参考书。 引用: 目录 第1章 Linux内核学习基础 1 1.1 为什么...
Linux 2.6内核的中断机制是操作系统核心的重要组成部分,它负责处理来自硬件的各种事件,如键盘输入、网络数据包接收或定时器中断。在实时性方面,Linux内核的默认实现并不理想,尤其对于需要快速响应的嵌入式系统而...
【Linux2.6内核实时性分析与改进方案】 Linux2.6内核是Linux操作系统的一个重要版本,它在实时性方面相对于早期版本有了显著的提升。然而,即便如此,对于需要高度实时性能的应用,例如嵌入式系统和消费电子产品,...
Linux 2.6内核支持许多高级特性,如中断处理、定时器、锁机制、内存管理等,这些都是内核模块开发中的重要知识点。通过实践,开发者可以掌握如何利用这些机制来实现特定的功能,从而更好地理解和扩展Linux内核。
《Linux2.6内核标准教程》适合Linux内核爱好者、Linux驱动开发人员、Linux系统工程师参考使用,也可以作为计算机及相关专业学生深入学 习操作系统的参考书。 引用: 目录 第1章 Linux内核学习基础 1 1.1 为什么...
《Linux2.6内核标准教程》适合Linux内核爱好者、Linux驱动开发人员、Linux系统工程师参考使用,也可以作为计算机及相关专业学生深入学 习操作系统的参考书。 引用: 目录 第1章 Linux内核学习基础 1 1.1 为什么...
《Linux2.6内核标准教程》适合Linux内核爱好者、Linux驱动开发人员、Linux系统工程师参考使用,也可以作为计算机及相关专业学生深入学 习操作系统的参考书。 引用: 目录 第1章 Linux内核学习基础 1 1.1 为什么...
在Linux系统中,内核定时器是用于在特定时间间隔执行特定操作的重要机制。它们是内核编程中的关键组件,特别是在需要延时或周期性任务的场合。本篇将深入探讨Linux内核定时器的编程,包括如何创建、管理以及它们的...
《Linux 2.6内核源代码解析与学习指南》 Linux 2.6内核是Linux操作系统的核心,它的源代码对于理解操作系统的工作原理、进行系统级编程以及进行Linux系统的移植和优化至关重要。Linux 2.6.39是这个系列的一个重要...
在Linux-2.6.11.12版本的内核中,包含了多个关键领域的源代码和注释,这对于理解操作系统的工作原理以及进行内核级别的编程至关重要。 1. **同步机制**:在多线程环境中,同步是非常关键的,以确保数据的一致性和...
### Linux 2.6 内核配置选项注解 #### Code Maturity Level Options - **Prompt for development and/or incomplete code/drivers (y):** 这个选项允许用户在编译过程中选择那些开发中或未完成的代码及驱动。通常...
【Linux-2.6内核在S3C2410上的移植分析和实现】 嵌入式Linux在当今的物联网和智能设备中扮演着至关重要的角色,尤其在以S3C2410为代表的嵌入式处理器上进行Linux内核的移植是开发的关键步骤。本文详细介绍了如何将...
【嵌入式Linux内核体系架构】中的【系统调用】和【定时器】是Linux内核中的核心组件,它们对于系统的运行至关重要。系统调用是用户空间与内核空间交互的主要桥梁,允许用户程序安全地访问操作系统提供的各种服务。 ...
《嵌入式Linux2.6的实时性能研究与优化》一文主要探讨了Linux2.6内核在嵌入式环境中的实时性能问题,并提出了针对性的优化策略。文章指出,尽管Linux内核在功能和稳定性上表现出色,但在实时性方面仍有不足,这主要...