一、内核定时器的作用
- 在linux中周期性的干一些事情
- 在特定某个时间干一件事情
比如:按键扫描,控制灯闪烁等 。
二、内核定时器的数据组成–timer_list结构体
struct timer_list {
/**
* All fields that change during normal runtime grouped to the
* same cacheline
*/
struct list_head entry;
unsigned long expires; /* 定时器唤醒(超时)时间 */
struct tvec_base *base;
void (*function)(unsigned long); /* 唤醒后要做的事 */
unsigned long data;
int slack;
#ifdef CONFIG_TIMER_STATS
void *start_site;
char start_comm[16];
int start_pid;
#endif
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
P.S.>其中我们主要来填充唤醒时间和唤醒后要做的事。其它参数初始化可以使用系统提供的固定的定时器初始化函数。
三、 timer的API函数:
初始化定时器:
void init_timer(struct timer_list * timer);
增加定时器:
void add_timer(struct timer_list * timer);
删除定时器:
int del_timer(struct timer_list * timer);
判断一个处在定时器管理队列中的定时器对象是否已经被调度执行:
static inline int timer_pending(const struct timer_list * timer)
修改定时器的expire,常用于重复定时:
int mod_timer(struct timer_list *timer, unsigned long expires);
P.S.>
关于pending:一个处于pending状态的定时器是处在处理器的定时器管理队列中正等待被调度执行的定时器对象 。add_timer只是把一个定时器对象加入到内核的管理队列,但是何时执行实际上由时钟中断(更确切地,是内核在时钟中断的softirq部分才开始扫描定时器管理队列),一个定时器对象pending意味着它的回调函数(timer->function) 尚未被调度执行,而一旦一个定时器对象被调度执行,之后它将被从定时器管理队列中摘除,除非它再次被提交。
关于expires参数:它的单位是jiffies。
四、使用定时器的一般流程为:
(1)创建timer、编写超时定时器处理函数function;
(2)为timer的expires、data、function赋值;
(3)调用add_timer添加一个定时器;此函数会把初始化的参数加入到定时器链表中去。这里要注意的是内核定时器是一个单次的定时器;
(4)在定时器到期时,function被执行;
(5)在程序中涉及timer控制的地方适当地调用del_timer、mod_timer删除timer或修改timer的expires。
五、应用举例
#include <linux/time.h>
/* 定义一个定时器指针 */
static struct timer_list *timer;
/* 参数是timer中的变量data */
void function_handle(unsigned long data)
{
/* 做你想做的事 */
......
/* 因为内核定时器是一个单次的定时器,所以如果想要多次重复定
* 时需要在定时器绑定的函数结尾重新装载时间,并启动定时。
* Kernel Timer restart
*/
mod_timer(timer,jiffies + HZ/50);
}
int xxxx_init(void)
{
timer = kzalloc(sizeof(struct timer_list), GFP_KERNEL);
if (!timer )
{
/* 错误处理 */
}
/* 具体任务的注册等 */
......
/* 初始化定时器 */
init_timer(timer );
/* 绑定定时时间到后的执行函数 */
timer->function = function_handle;
/* 定时的时间点,当前时间的20ms之后 */
timer->expires = jiffies + (HZ/50);
/* 添加并启动定时器 */
add_timer(timer);
}
void xxxx_exit(void)
{
/* 具体任务的卸载等 */
......
/* 删除定时器 */
del_timer(timer);
}
module_init(xxxx_init);
module_exit(xxxx_exit);
MODULE_LICENSE("GPL");