5. linux 内核定时器
1. 定时器简介
软件上的定时器最终要依靠硬件时钟来实现,简单的说,内核会在时钟中断发生后检测各个注册到内核的定时器是否到期,如果到期,就回调相应的注册函数,将其作为中断底半部来执行。实际上,时钟中断处理程序会触发TIMER_SOFTIRQ软中断,运行当前处理器上到期的所有定时器。设备驱动程序如要获得时间信息以及需要定时服务,都可以使用内核定时器。
2. jiffies 变量
要说内核定时器,首先就得说说内核中关于时间的一个重要的概念: jiffies 变量,作为内核时钟的基础,jiffies 每隔一个固定的时间就会增加1,称为增加一个节拍,这个固定间隔由定时器中断来实现,每秒中产生多少个定时器中断,由在<linux/param.h>
中定义的 HZ 宏来确定,如此,可以通过 jiffies 获取一段时间,比如 jiffies/HZ 表示自系统启动的秒数。下两秒就是(jiffies/HZ+2), 内核中用jiffies来计时,秒转换成的jiffies:secondsHZ,所以以jiffiy为单位,以当前时刻为基准计时2秒: (jiffies/HZ+2)HZ=jiffies+2*HZ。
3.定时器相关API
#include <linux/timer.h>
void init_timer(struct timer_list *timer);
void add_timer(struvt timer_list *timer);
void mod_timer(struct timer_list *timer, unsigned long expires);
//定时器是否在运行
int timer_pending(struct timer_list *timer);
void del_timer(struct timer_list *timer);
//确保删除定时器不会在另外一个CPU上运行
void del_timer_sync(struct timer_list *timer);
4. 驱动例程
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/timer.h>
struct timer_list tm;
MODULE_LICENSE("GPL");
void call_back(unsigned long arg)
{
printk("Timer is now!\n");
//定时器执行完,需要重新注册
tm.expires = jiffies + 2*HZ;
add_timer(&tm);
}
static int timer_init(void)
{
printk("Timer is Init!\n");
init_timer(&tm);
tm.function = call_back;
//定时器两秒后触发
tm.expires = jiffies + 2 * HZ;
add_timer(&tm);
return 0;
}
static void timer_exit(void)
{
printk("Exist timer ...\n");
del_timer(&tm);
}
module_init(timer_init);
module_exit(timer_exit);
说明:使用dmesg
可以查看内核打印