内核定时器
概念
Linux内核定时器使用基于时间点的计时方式:以当前时刻为启动时间点,以未来的某一时刻为终止点。
内核定时器精度不高
内核定时器不是周期性运行的,超时后会自动关闭。可以在定时器处理函数中重新开启定时器。
结构体和函数
include/linux/timer.h
timer_list结构体
struct timer_list{
struct list_head entry;
unsigned long expires; //定时器的超时节拍数
struct tvec_base *base;
void (*function)(unsigned long); //定时处理函数
unsigned long data; //传递给定时处理函数的参数
int slack;
};
expires需要的是节拍数,并不是时间参数
变量
内核中全局变量jiffies表示当前的节拍数,宏HZ表示一秒对应的时钟节拍数。
内核有一个宏HZ,表示一秒对应的节拍数。CONFIG_HZ可以在编译内核的时候配置Kernel Features ---- Timer frequency选项里。视频教程里一秒默认节拍是100hz,即一秒的节拍数是100.
时间转换函数
ms转换为时钟节拍
unsigned long msecs_to_jiffies(const unsigned int m)
us转换为时钟节拍
unsigned long usecs_to_jiffies(const unsigned int u)
定时10ms:expires = jiffies + msecs_to_jiffies(10)
定时10us:expires = jiffies + usecs_to_jiffies(10)
初始化宏
静态定义结构体变量并初始化function,expires,data成员
#define DEFINE_TIMER(_name, _function, _expires, _data)
//参数
_name变量名,用于初始化的timer_list结构体
_function超时处理函数,
_expires到点时间,节拍
_data传递给超时处理函数的参数
add_timer函数
void add_timer(struct timer_list *timer)
向Linux内核注册定时器,使用add_timer注册定时器后,定时器就会开始运行
del_timer函数
int del_timer(struct timer_list *timer)
删除一个定时器,不管定时器是否激活,都可以使用此函数删除。
在多处理器系统上,定时器可能会在其他的处理器上运行,因此调用删除定时器时会等待其他处理器的定时处理函数退出。
返回值:0,定时器还未被激活;1,定时器已经激活
mod_timer函数
修改定时值,如果定时器还没有激活,调用函数会激活定时器
int mod_timer(struct timer_list *timer, unsigned long expires)
返回值:0,定时器还未被激活;1,定时器已经激活
在定时器处理函数里可以调用此函数重新设置定时器。
实验思路
- 使用DEFINE_TIMER宏定义并初始化定时器
- 定义编写定时器处理函数,在函数里可以通过mod_timer函数修改并再次激活定时器
- 在模块入口处使用add_timer函数向内核注册定时器,并在此重新编辑定时器结构体的定时节拍函数
- 模块出口处,del_timer释放定时器
代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/timer.h>
//声明定时器处理函数
static void ta_timer_func(unsigned long dat);
//定义、初始化定时器,expires参数不必再此初始化,在需要开启的时候再计算节拍
DEFINE_TIMER(taxue_timer, ta_timer_func, 0, 0);
//定义定时器处理函数
static void ta_timer_func(unsigned long dat){
static int count=0;
printk("hello timer count=%d\n",count++);
if(count <= 50){
//修改定时器,让定时器再次工作
//节拍设置为当前时间+count*10毫秒
mod_timer(&taxue_timer, jiffies + msecs_to_jiffies(count*10));
}else{
printk("done\n");
}
}
static int driver_init_timer(void){
printk("Hello TaXue\n");
taxue_timer.expires = jiffies + 1*HZ; //当前节拍+1秒节拍
add_timer(&taxue_timer); //向内核注册定时器
return 0;
}
static void driver_exit_timer(void){
del_timer(&taxue_timer); //删除定时器
printk("platform driver exit!\n");
}
module_init(driver_init_timer); //模块入口,加载驱动时执行参数内的函数
module_exit(driver_exit_timer); //模块出口,卸载模块时执行参数内的函数
MODULE_LICENSE("Dual BSD/GPL"); //遵循BSD和GPL开源许可
MODULE_AUTHOR("TAXUE"); //模块作者