内核定时器

概念

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");  //模块作者
posted @ 2021-11-06 00:11  WuYunTaXue  阅读(298)  评论(0编辑  收藏  举报