Linux_内核定时器

1.内核定时器

1.1.内核定时器简介和系统时钟

Linux内核定时器是一个基于系统时钟的软件模拟定时器。Linux内核定时器使用很简单,只需要提供超时时间和定时处理函数即可,当超时时间到了以后设置的定时器处理函数就会执行。
在使用Linux内核定时器要注意一点,内核定时器并不是周期性运行的,超时以后就会自动关闭,因此如果想实现周期性定时,那么就需要在定时处理函数中重新开启定时器。
之前大家学习过ucos系统,我们知道ucos系统是需要一个硬件定时器来提供系统时钟。同样,Linux系统要运行,也得需要硬件定时器来提供系统时钟。硬件定时器提供时钟源,时钟源的频率可以设置,设置好以后就周期性的产生定时中断,系统使用定时中断来计时。而中断周期性产生的频率就是系统频率,也叫做节拍率。Linux内核默认采用100Hz作为系统频率。在使用内核定时器时,经常使用以下两个标识符:

HZ:是一个宏,表示每秒的系统节拍数,即每秒进入多少次定时器中断。
jiffies:是一个全局变量,记录系统从启动以来的系统节拍数,系统启动的时候将jiffies初始化为0

1.2.内核定时器核心数据结构

Linux内核使用timer_list结构体描述一个定时器,该结构体在include\linux\timer.h文件中定义。

struct timer_list {
	/*
	 * All fields that change during normal runtime grouped to the
	 * same cacheline
	 */
	struct list_head entry;
	unsigned long expires;	/* 定时器超时时间,单位是节拍数 */		jiffies+5*HZ
	struct tvec_base *base;

	void (*function)(unsigned long);/* 定时器超时处理函数 */
	unsigned long data;		/* 传递给超时处理函数的参数 */
	int slack;
#ifdef CONFIG_TIMER_STATS
	int start_pid;
	void *start_site;
	char start_comm[16];
#endif
#ifdef CONFIG_LOCKDEP
	struct lockdep_map lockdep_map;
#endif
};

以上结构用来表示一个定时器,要想实现内核定时器就必须定义这个结构,实现expires,function,data这三个必要成员。如果想同时定时多段时间,就定义多个定时器。实现必须的成员。

注:Linux内核定时器是基于未来某个时间点(就是用jiffies来表示)来触发超时处理函数。
expires成员变量表示超时时间,单位为节拍数。比如,现在需要定义一个周期为两秒的定时器,那么这个定时器的超时时间就是jiffies + 2*HZ。	

注意: 如果内核定时器要设置超时时间为几微秒,几毫秒,怎么办?
10毫秒:jiffies + 0.01*HZ。这样写不准确!建议使用以下两个函数:

unsigned long usecs_to_jiffies(const unsigned int u);
作用:把微秒转换成时钟节拍
参数:u--时间微秒
返回:对应的时钟节拍数量
unsigned long msecs_to_jiffies(const unsigned int m);
作用:把毫秒转换成时钟节拍
参数:m--时间毫秒
返回:对应的时钟节拍数量

1.3.内核定时器使用步骤

1.构造定时器对象
头文件:#include <linux/timer.h>
宏原型:init_timer(timer)
宏功能:只是对struct timer_list结构成员进行了一些基础初始化的操作,function,expires,data还需要用户自己填充,相当于只剩下三个必要成员没有初始化。
宏参数:struct timer_list结构变量的地址
头文件:#include <linux/timer.h>
宏原型:setup_timer(timer, fn, data)	
宏功能:设置定时器中的function,data和一些基础成员,expires并没有初始化,需要用户自己进行初始化(直接赋值)。
宏参数:	timer	struct timer_list结构体变量的地址
		fn		内核定时器超时处理函数
		data	传给定时器超时处理函数的参数
2.启动定时器

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

头文件:	#include <linux/timer.h>
函数原型:void add_timer(struct timer_list *timer);
函数功能:向内核注册一个定时器,注册后会马上开始计时。
函数参数:要注册的定时器
函数返回值:无
3.修改定时器

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

头文件:	#include <linux/timer.h>
函数原型:int mod_timer(struct timer_list *timer, unsigned long expires);
函数功能:修改定时器定时时间值,并且重新激活该定时器。执行完成后定时器会马上启动定时。
函数参数:	timer	要修改超时时间的定时器
			expires	修改后的超时时间
函数返回值:无
4.删除定时器

del_timer函数用于删除一个定时器,不管定时器有没有被激活(有没有被启动)。

头文件:	#include <linux/timer.h>
函数原型:int del_timer(struct timer_list * timer);
函数功能:从内核定时链表上删除指定的定时器,删除后就不会再执行绑定的函数
函数参数:要删除的定时器
函数返回值:返回0表示定时器还没被激活,返回1表示定时器已经被激活

注:
不能在超时回调函数中调用该函数,调用del_timer删除定时器前会先等待定时器处理函数执行完毕!

1.4.内核定时器使用示例

使用过程示例:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/timer.h>	//内核定时器所需头文件

struct timer_list mytimer;	//定义一个内核定时器结构体变量

void timer_handler(unsigned long data)	//超时回调函数
{
	printk("time out\n");
	//printk("data = %d\n",data);
	mod_timer(&mytimer,jiffies + HZ*2);
}
static int __init xxx_init(void)
{
    printk("xxx_init\n");
	init_timer(&mytimer);	//对结构体进行基础初始化
	setup_timer(&mytimer,timer_handler,100);	//设置结构体的函数指针和参数	
	//mod_timer(&mytimer,jiffies + HZ*2);		//修改定时器定时时间值,并且重新注册
	mytimer.expires = jiffies + HZ*2;			//设置结构体的超时时间
	add_timer(&mytimer);						//注册定时器到内核
    return 0;
}
static void __exit xxx_exit(void)
{
    printk("xxx is exit\n");
	del_timer(&mytimer);	//若使用了循环定时,在卸载函数中未调用该函数,注销驱动时内核崩溃
}
module_init(xxx_init);
module_exit(xxx_exit);
MODULE_LICENSE("GPL");
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值