一:内核时间管理
1、硬件定时器提供时钟源,时钟源的频率可以设置,设置好以后就可以周期性的产生定时中断,系统就可以使用定时中断来计时。中断周期性的产生的频率就是系统频率也叫做节拍率,比如1000Hz,500Hz,100Hz就是系统节拍率。系统节拍率可以设置,在配置Linux内核时可以进行设置,默认值为100Hz也就是10ms,在Linux内核中用“HZ”表示:
# undef HZ
# define HZ CONFIG_HZ /* Internal kernel timer frequency */
# define USER_HZ 100 /* some user interfaces are */
# define CLOCKS_PER_SEC (USER_HZ) /* in "ticks" like times() */
2、Linux内核使用全局变量jiffies来记录系统从启动以来的系统节拍数,系统启动时会将jiffies初始化为0。
extern u64 __jiffy_data jiffies_64;
extern unsigned long volatile __jiffy_data jiffies;
对于jiffies数据的溢出问题,Linux内核提供了一些API来进行处理:
#define time_after(a,b) \
(typecheck(unsigned long, a) && \
typecheck(unsigned long, b) && \
((long)((b) - (a)) < 0))
#define time_before(a,b) time_after(b,a)
#define time_after_eq(a,b) \
(typecheck(unsigned long, a) && \
typecheck(unsigned long, b) && \
((long)((a) - (b)) >= 0))
#define time_before_eq(a,b) time_after_eq(b,a)
time_after(a, b):一般a值为jiffies,b值为比较值。a超过b时返回真,否则为假。time_before函数返回值相反。函数time_after_eq与time_before_eq多了一个等于判断条件。
linux内核还提供几组jiffies与ms,us,ns之间换算的API:
unsigned int jiffies_to_msecs(const unsigned long j)
unsigned int jiffies_to_usecs(const unsigned long j)
inline u64 jiffies_to_nsecs(const unsigned long j)
unsigned long msecs_to_jiffies(const unsigned int m)
unsigned long usecs_to_jiffies(const unsigned int u)
unsigned long nsecs_to_jiffies(u64 n)
二:内核定时器
1、 Linux内核定时器使用方法只需要提供超时时间(类似于定时时间)和超时处理函数即可,当超时时间到达以后就会执行相应的超时处理函数,需要注意的是Linux内核定时器并不是周期性运行的,超时之后就会关闭,如果想要实现循环只需要在超时处理函数中重新启动定时器即可。
Linux内核定时器定义:
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;
};
2、内核定时器相关API
(1)初始化
void init_timer(struct timer_list *timer)
(2)注册定时器,想内核注册之后定时器就会开始运行
void add_timer(struct timer_list *timer)
(3)删除定时器,返回值为0表示定时器还没被激活,否则已经激活
int del_timer(struct timer_list * timer)
(4)等待定时器退出后(即使用完毕)再删除,不能用于中断上下文中
int del_timer_sync(struct timer_list *timer)
(5)修改定时值
int mod_timer(struct timer_list *timer, unsigned long expires)
三:示例
struct timer_list timer; /* 定义定时器 */
/* 定时器回调函数 */
void function(unsigned long arg)
{
/*
* 定时器处理代码
*/
/* 如果需要定时器周期性运行的话就使用 mod_timer
* 函数重新设置超时值并且启动定时器。
*/
mod_timer(&dev->timertest, jiffies + msecs_to_jiffies(2));
}
/* 初始化函数 */
void init(void)
{
init_timer(&timer); /* 初始化定时器 */
timer.function = function; /* 设置定时处理函数 */
timer.expires=jffies + msecs_to_jiffies(2);/* 超时时间 2 秒 */
timer.data = (unsigned long)&dev; /* 将设备结构体作为参数 */
add_timer(&timer); /* 启动定时器 */
}
/* 退出函数 */
void exit(void)
{
del_timer(&timer); /* 删除定时器 */
/* 或者使用 */
del_timer_sync(&timer);
}