Linux内核定时器

一、内核时间的相关概念

1. 墙上时钟:也就是实际时间。

2. 系统时间:自系统启动开始所经过的时间。

3. 时钟中断:内核会周期性的产生时钟中断,在中断处理函数中执行一些与时间相关的操作,如更新时间,进程调度,检查时间片等。

4. 节拍率:在linux内核中,通过编程定义节拍率,也就是HZ。每1/HZ秒发生一次时钟中断。在ARM中,节拍率被定义为100,节拍率越大,系统进入时钟中断就越频繁,时间和进程调度等操作就越准确,但对系统的负担也就越大。
HZ在Linux内核源码目录下的arch/arm/include/asm/param.h定义:
#ifdef __KERNEL__
#define HZ CONFIG_HZ /* Internal kernel timer frequency */
#define USER_HZ 100 /* User interfaces are in "ticks" */
#define CLOCKS_PER_SEC (USER_HZ) /* like times() */
#else
#define HZ 100
#endif
可见,内核空间的HZ由__KERNEL__和CONFIG_HZ决定,而CONFIG_HZ在.config(选择编译选项后产生的配置文件)中定义,如在顶层目录下的.config有如下定义:CONFIG_HZ=256。
HZ在内核的源代码中是一个全局常量可以修改,但是一旦内核编译成镜像文件时,HZ就是一个常量了。HZ的值一般在10~1000之间。HZ越大,系统计时越精确,系统的实时性越好,但是系统的负担就会重。一般CPU的主频越高,HZ越的值越大。

5. jiffies:32位的全局变量,用来记录自系统启动以来产生的节拍的总数。系统启动时清零,每次时钟中断加一。所以,一秒内的时钟中断次数(即jiffies一秒内增加的值)也就等于HZ。如果系统时间以秒来表示,那就等于jiffies/HZ秒。

6. 实时时钟(RTC):体系结构中用于维持系统时间的设备,就像电脑的BIOS,需要在关机状态时通过电池供电。系统启动时通过读取RTC
来初始化墙上时钟


二、Linux内核定时器

2.1 定义及初始化一个定时器结构体timer_list
timer_list在Linux内核源码目录下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;
struct tvec_base *base;


void (*function)(unsigned long);
unsigned long data;


int slack;


#ifdef CONFIG_TIMER_STATS
void *start_site;
char start_comm[16];
int start_pid;
#endif
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};

关键成员说明:
.expires:定时器超时处理函数的超时时间
.function:定时器超时处理函数
.data:定时器超时处理函数的参数

这三个成员是由用户设置,其余一般由内核处理


此外,还有一个关于定时器结构体的宏定义,在Linux内核源码目录下include/linux/timer.h下定义:
#define DEFINE_TIMER(_name, _function, _expires, _data) \
struct timer_list _name = \
TIMER_INITIALIZER(_function, _expires, _data)

2.1.1 直接定义一个定时器结构体,如:
struct timer_list timer;

2.1.2 使用宏定义一个定时器结构体,如:
DEFINE_TIMER(timer, timer_func,100);

2.2 设置超时时间,定义定时器处理函数和传参
指定timer的expires、function和data。

2.2.1 给结构体成员分别赋值或,如:
void timer_func(unsigned long data)
{

}

static int __init timer_dev_init(void)
{
timer.funciton = timer_func;
timer.expires = jiffies+5*HZ;
timer.data = 100;
}

2.3 使用init_timer()完成全部初始化;
函数原型:int init_timer(struct timer_list *timer);
参数说明:
timer: 定时器结构体变量地址
返回值:
成功返回0,失败返回一个负的错误码。

如:init_timer(&timer);


2.4 激活定时器
激活定时器使用add_timer();
函数原型:int add_timer(struct timer_list *timer);
参数说明:
timer: 定时器结构体变量地址
返回值:
成功返回0,失败返回一个负的错误码。

如:add_timer(&timer);

当调用add_timer后,就会将定时器交由内核来管理,当时间一到,内核调用进程/*swapper*/来执行处理函数,因此,若设置了重复执行,当rmmod驱动(若没有删除定时器)后,定时器超时处理函数会继续执行,定时器激活后,它只会在指定时间执行一次处理函数,执行后会将定时器在内核中移除。

2.5 修改定时器
如果要实现隔指定时间又重复执行,可使用如下方法:

2.5.1 在定时器处理函数中添加如下代码,即再次激活定时器。
timer.expires = jiffies+5*HZ;
add_timer(&timer);

2.5.2 在定时器处理函数中使用mod_timer();
这是改变定时器超时时间的函数,如果在指定的定时器(timer)没超时前调用,超时时间会更新为新的新的超时时间(expires)。
如果在定时器超时后调用,那就相当于重新指定超时时间并再次激活定时器。

函数原型:int mod_timer(struct timer_list *timer, unsigned long expires);
参数说明:
timer: 定时器结构体变量地址
expires:定时时间
返回值:
成功返回0,失败返回一个负的错误码。

如:mod_timer(&timer, jiffies+5*HZ);

2.6 删除定时器
若想在定时器没有超时前取消定时器,则使用del_timer();
函数原型:void del_timer(struct timer_list *timer);
参数说明:
timer: 定时器结构体变量地址
返回值:
无返回值。

如:del_timer(&timer);


三、Linux内核定时器实例

驱动程序(timer_dev.c):

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/timer.h>	
#include <linux/sched.h>	//current->comm

//1. 定义一个定时器结构体
static struct timer_list timer;

void timer_func(unsigned long data)
{
	printk("data:%lu\n", data);
	printk("jiffies:%lu\n", jiffies);
	printk("current.comm:%s\n", current->comm);
	
	//修改定时器
	mod_timer(&timer, jiffies+2*HZ);
}

static int __init timer_dev_init(void)
{
	//2. 设置超时时间,定义定时器处理函数和传参
	timer.expires = jiffies+5*HZ;
	timer.function = timer_func;
	timer.data = 100;
	
	//3. 初始化定时器结构体
	init_timer(&timer);
	
	//4. 激活定时器
	add_timer(&timer);
	
	printk("timer_dev init\n");
	printk("current.comm:%s\n", current->comm);
	
	return 0;
	
}

static void __exit timer_dev_exit(void)
{
	//删除定时器
	del_timer(&timer);
	
	printk("timer_dev exit\n");
}

module_init(timer_dev_init); 
module_exit(timer_dev_exit); 
MODULE_LICENSE("GPL");

编译文件(Makefile):

obj-m += timer_dev.o 
KERN_DIR=/home/gec/linux-2.6.35.7-gec-v3.0-gt110

modules:
	$(MAKE) -C $(KERN_DIR) M=$(PWD) modules
clean:
	$(MAKE) -C $(KERN_DIR) M=$(PWD) modules clean


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值