Linux内核定时器简介及使用

28.1 前言

Linux内核定时器用于处理指定时间后,执行某个动作的。其特点如下:

(1)执行了一次便不会再次执行,处理后即失效;

(2)执行的动作函数中,不允许休眠和发生调度行为;

(3)应该对被访问的数据结构进行条件设置防止被调度;

在Linux内核定时器中,不得不说的一个东西就是jiffies。jiffies是记录着从电脑开机到现在总共的时钟中断次数,Linux系统时钟频率是一个常数HZ来决定的,一秒内时钟中断的次数等于Hz,所以jiffies一秒内增加的值也就是Hz,通常HZ=100,精度就是10ms,所以一般来说Linux的精确度是10毫秒。如果我们要进行秒定时操作,需设置expire = jiffies + xs*HZ

28.2 定时器数据结构

Linux内核管理着一个定时器队列,用户新增加一个定时器就会添加到队列中。一般是定义一个新的定时器结构,然后填充好回调函数等相关参数,添加到Linux定时器中断处理链表中,当Linux计时时间到达用户所设置的定时时,那么将会执行用户所设置的操作回调函数。

struct timer_list {  
       structlist_head entry;              //timer双向链表   
       unsignedlong expires;             //timer超时变量   
   
       void(*function)(unsigned long);   //timer超时回调函数  www.linuxidc.com 
       unsignedlong data;                  //传递给回调函数的数据,也就是定时器数据   
      struct tvec_base *base;            //timer base向量表用于timer_list的挂载和链表管理   
                                              //timer的一些扩展参数 
   …………… 
};  

28.3 相关函数说明

struct timer_list tm

定时器数据结构

init_timer(*tm)

初始化定时器结构;tm定时器数据结构指针

add_timer(*tm)

添加定时器;tm定时器结构指针

mod_timer(*tm,expire)

修改定时器;tm定时器数据结构;expire超时时间,一般jiffies+xs

del_timer(*tm)

删除定时器;tm定时器数据结构指针

定时器的使用步骤为:初始化定时器结构、定时器数据结构复制、添加定时器、编写定时器回调函数、删除定时器。

28.4 内核定时器实例

#include <linux/kernel.h>  
#include <linux/init.h>  
#include <linux/fs.h>  
#include <linux/module.h>  
#include <linux/time.h>  

#define I_DEVICE_NAME           "iTimer"  
static int major;  
static struct timer_list tm;  
  
void iTimer_callback(unsigned long arg)  
{  
    struct timeval tv;  
    char *strp = (char*)arg;  
    printk(KERN_EMERG "%s: %lu, %s\n", __func__, jiffies, strp);  
  
    mod_timer(&tm,jiffies+2*HZ); //使用mod_timer或再次add_timer函数重新触发
    //tm.expires = jiffies+1*HZ;  
    //add_timer(&tm);  
}  
  
static int iopen(struct inode *pnode, struct file *pfile)  
{  
    return 0;  
}  
  
static int iRead(struct file * file, const char __user * buffer, size_t count, loff_t * ppos) 
{  
    return 0;  
}  
  
static const struct file_operations stfops = {  
    .owner  = THIS_MODULE,  
    .read   = iRead,  
    .open   = iopen,  
};  
  
static int __init iTest_Init(void)  
{  
    /* 主设备号设置为0表示由系统自动分配主设备号 */  
    major = register_chrdev(0, I_DEVICE_NAME, &stfops);  
  
    init_timer(&tm);  
    tm.function= iTimer_callback;  
    tm.data = (unsigned long)"I am timer";
    tm.expires = jiffies+1*HZ;  
    add_timer(&tm);  
  
    return 0;  
}  
  
static void __exit iTest_Exit(void)  
{  
    unregister_chrdev(major, I_DEVICE_NAME);  
    del_timer(&tm);  
}  
  
module_init(iTest_Init);  
module_exit(iTest_Exit);  
  
MODULE_LICENSE("GPL");  

 

猜你喜欢

转载自blog.csdn.net/Chasing_Chasing/article/details/89555264