前言
定时器是我们最常用到的功能,一般用来完成定时功能,本章我们就来学习一下 Linux 内
核提供的定时器 API 函数,通过这些定时器 API 函数我们可以完成很多要求定时的应用。Linux
内核也提供了短延时函数,比如微秒、纳秒、毫秒延时函数,本章我们就来学习一下这些和时
间有关的功能。
一、普通定时器使用
这种定时精度低,对实时性要求不严格的场合可以用,内核中使用 CONFIG_HZ 来设置自己的系统时
钟。打开文件 include/asm-generic/param.h,有如下内容:
# undef HZ
# define HZ CONFIG_HZ
# 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;
//判断有没有超时,实际就是比较两个数的大小
#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)
代码实例
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/hrtimer.h>
#include <linux/jiffies.h>
//定义一个timer_dev结构体
struct timer_dev{
int timeperiod; /* 定时周期,单位为 ms */
struct timer_list timer; /* 定义一个定时器 */
spinlock_t lock; /* 定义自旋锁 */
};
struct timer_dev dev;
//定时器回调函数
void normal_timer_hander(unsigned long arg)
{
printk("enter normal_timer_hander\r\n");
//修改定时值并且重新启动定时器
mod_timer(&dev.timer, jiffies + msecs_to_jiffies(2000));
}
static int __init test_init(void)
{
init_timer(&dev.timer); //初始化定时器,必须的必
//设置定时器回调函数
dev.timer.function = normal_timer_hander;
//定时器超时时间设置,单位为节拍数,使用毫秒转节拍
dev.timer.expires=jiffies + msecs_to_jiffies(2000);//2S
//将设备结构体作为参数
dev.timer.data = (unsigned long)&dev;
//向Linux内核注册定时器,注册之后定时器就会开始运行
add_timer(&dev.timer);
}
static void __exit test_exit(void)
{
del_timer(&dev.timer); //删除定时器
//del_timer_sync(&dev.timer);//会等待其他处理器使用完定时器再删除
}
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");
二、高精度定时器使用
高精度定时器,为我们提供了纳秒级别的定时精度,以满足对精确时间有迫切需求的应用程序或内核驱动。
hrtimer 结构体定义在<Linux/hrtimer.h>中,如下:
/**
* The hrtimer structure must be initialized by hrtimer_init()
*/
struct hrtimer {
struct timerqueue_node node;
ktime_t _softexpires;
enum hrtimer_restart (*function)(struct hrtimer *);
struct hrtimer_clock_base *base;
u8 state;
u8 is_rel;
u8 is_soft;
};
看到没有,hrtimer定义的结构体必须用hrtimer_init()函数来初始化
_softexpires :记录了定时器到期时间
function:定时器回调函数,该函数返回一个枚举值,它决定了该hrtimer是否需要被重新激活。
base:clock基类,里面有很多跟时间相关的,比如我们常用的get_time()函数
代码实例
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/hrtimer.h>
#include <linux/jiffies.h>
//定义一个hrtimer
static struct hrtimer timer;
ktime_t kt;
//定时器回调函数
static enum hrtimer_restart hrtimer_hander(struct hrtimer *timer)
{
printk("enter hrtimer_hander\r\n");
hrtimer_forward(timer,timer->base->get_time(),kt);
//hrtimer_forward_now(timer, ktime_set(1,0));//同上面函数
return HRTIMER_RESTART; //重启定时器
}
static int __init test_init(void)
{
//设置定时时间
kt = ktime_set(1,10000000);// 1s 10000000ns = 1s+10ms
//hrtimer_init(timer, which_clock, mode);
//which_clock:表示选择系统的哪种时钟,一种CLOCK_REALTIME表示绝对时间,另一种CLOCK_MONOTONIC表示相对时间。
//mode:表示hrtimer的类型,HRTIMER_MODE_ABS,HRTIMER_MODE_REL,前者是绝对模式,对应于CLOCK_REALTIME时钟
hrtimer_init(&timer,CLOCK_MONOTONIC,HRTIMER_MODE_REL);
//启动一个定时器
hrtimer_start(&timer,kt,HRTIMER_MODE_REL);
timer.function = hrtimer_hander;//设置定时器回调函数
return 0;
}
static void __exit test_exit(void)
{
//取消一个定时器,并等待其执行完毕
hrtimer_cancel(&timer);
printk("------------test over---------------\r\n");
}
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");
参考文献:
https://kunaly.blog.csdn.net/article/details/99641461
https://blog.csdn.net/lhl_blog/article/details/106824066