内核定时器的使用


前言:
· 内核定时器是一个精度低的定时器(一般都是毫秒级别的),他是基于内核中的 jiffies 变量来实现的
· 软件意义上的定时器最终都是依赖硬件定时器来实现的
· 内核定时器的精低精度的定时器,一般用做看门狗等对时间精度不敏感的情况下使用
· 假如要定时1个 jiffies 的时间长度,内核定时器是无法做到准确定时的,因为内核定时器可能是在上一个jiffies刚走完一定的时间,又还没到下一个 jiffies 时就开始定时,这样会导致实际的定时时间小于一个 jiffies 的长度

1 struct timer_list

· timer_list 是将 expires 与 jiffies 进行比较实现的,但 jiffies 大于或等于 expires 时,即定时器到期

#include <linux/timer.h>

/* 老版 Linux 中的定义 */
struct timer_list {
	/*
	 * All fields that change during normal runtime grouped to the
	 * same cacheline
	*/
	struct hlist_node	entry; /* 哈希表,kernel 用于管理 timer_list  */
	unsigned long		expires;	/* 定时器到时时间,单位是节拍数 */
	/* 当定时器满期后,function 函数将被执行 */
	void			(*function)(struct timer_list *);
	u32			flags;	/* 时钟标志位 */

/* 用于在内核锁的情况下跟踪计时器的使用情况 */
#ifdef CONFIG_LOCKDEP
	struct lockdep_map	lockdep_map;
#endif
};

/* 当今主流的 Linux 中的定义 */
struct timer_list {
	struct hlist_node	entry;	/* 哈希表,kernel 用于管理 timer_list  */
	unsigned long		expires;	/* 定时器到时时间,单位是节拍数 */
	/* 当定时器满期后,function 函数将被执行 */
	void			(*function)(unsigned long);	
	unsigned long		data;	/* 回调函数的参数 */
	u32			flags;		/* 时钟标志位 */
	int			slack;		
};
· u32 flags (也定义在 linux/timer.h 中)
	· TIMER_CPUMASK:表示定时器可以在哪些 CPU 上运行
	· TIMER_MIGRATING:表示定时器正在迁移中
	· TIMER_BASEMASK:是 TIMER_CPUMASK 和 TIMER_MIGRATING 的位或运算结果
	· TIMER_DEFERRABLE:表示该定时器是 deferrable 的,即不会阻塞 CPU,而是在 CPU 空闲时执行
	· TIMER_PINNED:表示该定时器是固定在 CPU 上的,不能移动到其他 CPU 上。
	· TIMER_IRQSAFE:表示该定时器是 irqsafe 的,即在执行回调函数时不会影响其他中断的处理
	· TIMER_ARRAYSHIFT:表示 TIMER_ONESHOT、TIMER_IRQSAFE 和 TIMER_PINNED 这三个位的位置
	· TIMER_ARRAYMASK:是 TIMER_CPUMASK、TIMER_ARRAYSHIFT 和 TIMER_BASEMASK 的按位与运算结果
	· TIMER_TRACE_FLAGMASK:是 TIMER_MIGRATING、TIMER_DEFERRABLE、TIMER_PINNED 和 TIMER_IRQSAFE 的按位或运算结果,用于标记定时器的一些属性

2 init_timer 初始化定时器

· 将 timer_list 的 entry 的 next 指针赋值为 NULL,并给 base 指针赋值

#include <linux/timer.h>

// init_timer 是一个宏定义,等价于下面的函数形式
void init_timer(struct timer_list *timer);

· struct timer_list *timer:要初始化的 struct timer_list 对象

3 add_timer 增加定时器

· 将对应的定时器加入到内核动态定时器链表中,注册内核定时器

#include <linux/timer.h>

void add_timer(struct timer_list *timer);

· struct timer_list *timer:要增加的 struct timer_list 对象

4 删除定时器

4.1 del_timer 直接删除定时器

#include <linux/timer.h>

int del_timer(struct timer_list *timer);

· int:执行成功返回 0,失败返回非零
· struct timer_list *timer:要删除的 struct timer_list 对象

4.2 del_timer_sync 同步后删除定时器

· del_timer_sync 是 del_timer 的同步版本,在删除一个定时器时需要等待其被处理完后,再进行删除
· 有休眠等待,不能用于中断上下文

#include <linux/timer.h>

int del_timer_sync(struct timer_list *timer);

· int:执行成功返回 0,失败返回非零
· struct timer_list *timer:要增加的 struct timer_list 对象

5 mod_timer 修改定时器的 expire

· 用于修改定时器的到期时间,在新的被传入的 expires 到来后才会执行定时器函数

#include <linux/timer.h>

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

· int:执行成功返回 0,失败返回非零
· struct timer_list *timer:要操作的 struct timer_list 对象
· unsigned long expires:将 expires 修改成的值

6 具体使用案例说明

/* 设备结构体 */
struct try_dev {	
	struct cdev cdev;
	...
	timer_list *xxx_timer;  // 设备要使用的内核定时器指针
}

/* 在初始化设备结构体函数中 */
xxx xxx_init(xxx){
	try_dev .timer =  (struct timer_list *)kmalloc(sizeof(struct timer_list), GFP_KERNEL);
    if(try_dev .timer == NULL) {
        pr_err("struct timer_list kmalloc error");
    } else {
        memset(try_dev .timer, 0, sizeof(struct timer_list)); 
        init_timer(try_dev.timer);
        /* 绑定定时器的处理函数 */
        try_dev.timer->function = timer_handle;
        /* 传入设备结构体的地址给定时器处理函数 */
        try_dev.timer->data = (unsigned long)&try_dev;
    }
}

/* 需要使用到定时器时的某函数 */
xxx xxx_function(xxx){
	...
	try_dev.timer->expires = jiffier + delay;
	add_timer(try_dev.timer);
	...
}

/* 需要删除定时器时的某函数 */
xxx xxx_function(xxx){
	...
	del_timer(try_dev.timer);
	...
}

/* 内核定时器的服务处理函数 */
static void timer_handle(unsigned long arg) {
	struct try_dev *p = (struct try_dev *)arg;
	...
	/* 若需循环使用定时器 */
	p->timer->expires = jiffies + delay;
	add_timer(p->timer);
	...
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值