timer(内核定时器)函数及其用法(初级)

timer(内核定时器)函数及其用法(初级)

写在最前

  1. 本文有demo版本,见:timer实例,可以结合代码一起看本文。
  2. 由于timer的函数接口在不同的内核版本大有不同,所以导致某些函数在某些版本不适用,本文所使用的代码版本为linux-5.10.60,其他版本的内核需要检查下函数接口。
  3. 从timer框架层面来说,没有太大变化,整体的设计思想要是弄明白了,timer也就完全够用了。
  4. 本文是timer的初级文章,只介绍关键的数据结构和函数,不做深入探究,在后续的中级文章中,我们会去探究timer硬件层面的设计。

timer原理(初级)

linux kernel 提供了内核定时器机制,其核心是由硬件产生中断来追踪时间流动情况,定时器到期(expires)后,会执行指定的某个具体的函数(function)。

timer代码分析

再次说明:下面的代码是基于linux-5.10.60,可能与你正在使用的内核有一定的差别,一切以你正在使用的内核为准,本文只做引导分析,让你知道如何使用timer。

关键数据结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 位于include/linux/timer.h,只关注下面的几项,其他项在中级文章中再做解释
* @expires:到期时间,即定时器在什么时间点后到期,注意:当前的时间为jiffies,不懂jiffies的自行google
* @function:回调函数,即timer到期后要执行的函数,注意:此函数的入参和返回值要符合下面的要求
* tips :在旧版还有一个data的项,那是给函数入参用的,当前内核已经废弃
*/
struct timer_list {
/*
* All fields that change during normal runtime grouped to the
* same cacheline
*/
struct hlist_node entry;
unsigned long expires;
void (*function)(struct timer_list *);
u32 flags;

#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};

关键函数

  1. 函数使用流程:
    初始化(初始化函数中)->添加到内核timer中(初始化函数中)->重新添加到内核timer中(回调函数中)->注销(注销函数中)
  2. 函数的实际用法可以参考文章前面的链接,也就是:timer实例
  3. 具体的函数如下

初始化

1
2
3
4
5
6
7
/**
* @timer: the timer in question 定时器名
* @callback: the function to call when timer expires 回调函数
* @flags: any TIMER_* flags 定时器标记,一般填0
*/
#define timer_setup(timer, callback, flags) \
__init_timer((timer), (callback), (flags))

调用timer_setup后还要进行如下赋值操作:
timer.expires = xxx;
在旧的版本里面用的是init_timer(timer)接口,所以旧版本除了上面还有额外的赋值操作:
timer.data = 0;
timer.function = funcyyy;

注册/开启 timer

timer要生效,还要必须被连接到内核专用的链表中。

1
2
/* @timer: the timer in question 定时器名 */
extern void add_timer(struct timer_list *timer);

重新注册(修改)timer

定时器在到期之后,如何不重新注册(修改)到内核,那么timer就不会再接着执行,这种有点类似“一次性”,所以我们要修改到期时间,让其接着运行(类似望梅止渴,就是让定时器程序一直看不到终点(到期时间))。

1
2
3
4
5
/**
* @timer: the timer in question 定时器名
* @expires: 到期时间
*/
extern int mod_timer(struct timer_list *timer, unsigned long expires);

注销timer

在模块退出或者不再使用timer时,要将timer注销。

1
2
3
4
5
6
7
8
/* @timer: the timer in question 定时器名 */
extern int del_timer(struct timer_list * timer);

#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT)
extern int del_timer_sync(struct timer_list *timer);
#else
# define del_timer_sync(t) del_timer(t)
#endif

这里要说明一下,注销timer有两个,我们一般用del_timer_sync这个函数就好了。

其他函数

当前还有一些其他的函数没有做介绍,因为一般情况下用不上,所以放到后续的中级文章中再做介绍。

0%