内核定时器 -32

Posted 杨斌并

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了内核定时器 -32相关的知识,希望对你有一定的参考价值。

内核定时器

Linux内核定时器概念

​ 不同于单片机定时器,Linux内核定时器是一种基于未来时间点的计时方式,以当前时刻为启动的时间点,以未来的某一时刻为终止点。比如,现在是10点5分,我要定时5分钟,那么定时就是10点5分+5分钟=10点10分。这个和咱们的手机闹钟很类似。比如你要定一个第二天早晨的8点的闹钟,就是当前时间定时到第二天早晨8点。
需要注意的是,内核定时器定时精度不高,不能作为高精度定时器使用。并且内核定时器并不是周期性运行的,超时以后就会自动关闭,因此如果想要实现周期性定时,那么就需要在定时处理函数中重新开启定时器。

Linux内核定时器基础知识

Linux内核使用timer_list 结构体表示内核定时器,timer_list定义在文件include/linux/timer.h中,

定义如下:

struct timer_list {
    struct list_head entry;
    unsigned long expires;/*定时器超时时间,不是时长,单位是节拍数*/
    struct tvec base *base;
    void (*function)(unsigned long); /*定时处理函数*/
    unsigned long data; /*要传递给 function 函数的参数*/
    int slack;
}

在这个结构体中,有几个参数我们需要重点关注一下。

  • 一个是expires到期时间,单位是节拍数。等于定时的当前的时钟节拍计数(存储在系统的全局变量jiffies)+定时时长对应的时钟节拍数量。

  • 那么我怎么把时间转换成节拍数量呢?

    示例:从现在开始定时1秒:

  • 内核中有一个宏 HZ,表示一秒对应的时钟节拍数,那么我们就可以通过这个宏来把时间转换成节拍数。所以,定时1秒就是:expires = jiffies + 1*HZ。

  • HZ的值我们是可以设置的,也就是说一秒对应的时钟拍数我们是可以设置的,Linux内核会使用 CONFIG_HZ来设置自己的系统时钟。打开文件include/asm-generic/param.h,有如下内容:

#define undef HZ
#define HZ CONFIG_HZ
#define USER HZ 100

宏HZ就是CONFIG HZ,因此 HZ=100,表示一秒的节拍数是100,们在编译 Linux内核的时候可以通过图形化界面设置系统节拍率,按照如下路径打开配置界面。

make meunconfig
kernel  features  Timer frequency  //路径
  • 可选的系统节拍率为100Hz、200Hz、250Hz、300Hz、500Hz 和1000Hz。默认是100Hz。

  • 第二个我们需要关心的参数是function超时处理函数,这个并不是硬件中断服务程序。原型:

    void function(unsigned long data);
    
  • 第三个参数是data传递给超时处理函数的参数,可以把一个变量的地址转换成unsigned long .

Linux内核定时器相关操作函数(#include <linux/timer.h>)

时间转换函数

  • ms转换为时钟节拍函数
unsigned long msecs_to_jiffies(const unsigned int m)
  • us转换为时钟节拍函数
unsigned long usecs_to_jiffies(const unsigned int u)

举例:

定时10ms

计算: jiffies + msecs_to_jiffies(10)<2>定时10us
计算: jiffies + usecs_to jiffies(10)<2>宏DEFINE_TIMER

原型:

#define DEFINE_TIMER(_name,_function,_expires,_data)

作用:

静态定义结构体变量并且初始化初始化function, expires, data 成员。

参数:

  • name变量名;
  • function超时处理函数;
  • data传递给超时处理函数的参数
  • expires到点时间,一般在启动定时前需要重新初始化。

  • add_timer函数

原型:

void add_timer(struct timer_list*timer)

作用:

add_timer函数用于向Linux内核注册定时器,使用add_timer函数向内核注册定时器以后,定时器就会开始运行

参数:

  • timer:要注册的定时器。

  • del_timer函数

原型:

int del_timer(struct timer_list * timer)

作用:

​ del_timer函数用于删除一个定时器,不管定时器有没有被激活,都可以使用此函数删除。在多处理器系统上,定时器可能会在其他的处理器上运行,因此在调用del_timer函数删除定时器之前要先等待其他处理器的定时处理器函数退出

参数:

  • timer:要删除的定时器。
  • 返回值: 0,定时器还没被激活;1,定时器已经激活。

  • mod_timer.函数

函数原型:

int mod_timer(struct timer_list *timer, unsigned long expires)

作用:

mod_timer 函数用于修改定时值,如果定时器还没有激活的话, mod_timer 函数会激活定时器!

参数:

  • timer:要修改超时时间(定时值)的定时器。expires:修改后的超时时间。
  • 返回值:0,调用mod_timer函数前定时器未被激活;1,调用mod_timer函数前定时器已被激活

代码

  • helloworld.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/timer.h>

static void  timer_function(unsigned long data);

DEFINE_TIMER(test_timer, timer_function, 0, 0);
static void timer_function(unsigned long data){

    printk("timer_function \\n");
    mod_timer(&test_timer, jiffies + 1*HZ);
}



static int hello_init(void){
    printk(KERN_EMERG "hello world enter \\n");
    test_timer.expires = jiffies + 1*HZ;
    add_timer(&test_timer);
    return 0;
}

static void hello_exit(void){
    printk(KERN_EMERG "hello world exit! \\n");
    del_timer(&test_timer);
}

module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("LIYU");

以上是关于内核定时器 -32的主要内容,如果未能解决你的问题,请参考以下文章

一个内核定时器模块

内核定时器

Linux驱动开发-内核定时器

Linux 内核定时器实验

Linux内核定时器

Linux内核定时器