Linux内核定时器
简介
我们在编译 Linux内核的时候可以通过图形化界面设置系统节拍率,按照如下路径打开配置界面:

可以看出,可选的系统节拍率为 100Hz、 200Hz、 250Hz、 300Hz、 500Hz和1000Hz,默认情况下选择 100Hz,编写 Linux驱动的时候会常常用到 HZ,HZ表示一秒的节拍数,也就是频率。即上面的这些频率值 定义在include/asm-generic/param.h里面
# undef HZ
# define HZ CONFIG_HZ // 这里定义 CONFIG_HZ即是通过配置界面生成在.config里面的值
# define USER_HZ 100
# define CLOCKS_PER_SEC (USER_HZ)
Linux内核使用全局变量 jiffies来记录系统从启动以来的系统节拍数,系统启动的时候会将 jiffies初始化为 0 ,jiffies定义在文件 include/linux/jiffies.h中,定义如下:
extern u64 __jiffy_data jiffies_64;
extern unsigned long volatile __jiffy_data jiffies;
// jiffies_64 和jiffies一个是64位的一个是32位的,jiffies其实就是jiffies_64的低32位而已
常用api函数如下:
unkown 通常为jiffies,known 通常是需要对比的值。
| 函数 | 功能 |
|---|---|
| time_after(unkown, known) | unkown>known 超时 返回真,否则返回假 |
| time_after_eq(unkown, known) | unkown>=known 刚超时 返回真,否则返回假 |
| time_before(unkown, known) | unkown<known 未超时 返回真,否则返回假 |
| time_before_eq(unkown, known) | unkown<=known 刚未超时 返回真,否则返回假 |
用法示例
unsigned long timeout;
timeout = jiffies + (2 * HZ); /* 超时的时间点 */
/*************************************
具体的代码
************************************/
/* 判断有没有超时 */
if(time_before(jiffies, timeout)) {
/* 超时未发生 */
} else {
/* 超时发生 */
}
ms us ns 和jiffies之间的相互转换函数API
| 函数 | 功能 |
|---|---|
| int jiffies_to_msecs(const unsigned long j) | 将jiffies类型的参数 转换为 毫秒 |
| int jiffies_to_usecs(const unsigned long j) | 将jiffies类型的参数 转换为 微秒 |
| u64 jiffies_to_nsecs(const unsigned long j) | 将jiffies类型的参数 转换为 纳秒 |
| long msecs_to_jiffies(const unsigned int m) | 将毫秒转换为jiffies类型 |
| long usecs_to_jiffies(const unsigned int u) | 将微秒转换为jiffies类型 |
| unsigned long nsecs_to_jiffies(u64 n) | 将纳秒转换为jiffies类型 |
内核定时器
Linux内核使用 timer_list结构体表示内核定时器,基于内核系统时钟层面上的软件定时器
struct timer_list {
struct list_head entry;
unsigned long expires; /* 定时器超时时间,单位是节拍数 */
struct tvec_base *base;
void (*function)(unsigned long); /* 定时处理函数 */
unsigned long data; /* 要传递给function函数的参数 */
int slack;
};
内核定时器相关的系统的API函数
| 函数 | 功能 |
|---|---|
| void init_timer(struct timer_list *timer) | 初始化定时器。 |
| void add_timer(struct timer_list *timer) | 向 Linux内核注册定时器 |
| int del_timer(struct timer_list * timer) | 删除定时器,不管定时器有没有被激活,都可以使用此函数删除。返回值0:定时器还没被激活 1:定时器已经激活。 |
| 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(2000));
}
/* 初始化函数 */
void init(void)
{
init_timer(&timer); /* 初始化定时器 */
timer.function = function; /* 设置定时处理函数 */
timer.expires=jffies + msecs_to_jiffies(2000);/* 超时时间2秒 */
timer.data = (unsigned long)&dev; /* 将设备结构体作为参数 */
add_timer(&timer); /* 启动定时器 */
}
/* 退出函数 */
void exit(void)
{
del_timer(&timer); /* 立即删除定时器 */
/* 或者使用 */
del_timer_sync(&timer); /* 会等定时器处理函数完成后在删除*/
}
内核常用的短延时函数
| 函数 | 功能 |
|---|---|
| void ndelay(unsigned long nsecs) | 纳秒 延时函数 |
| void udelay(unsigned long usecs) | 微秒 延时函数 |
| void mdelay(unsigned long mseces) | 毫秒 延时函数 |