概述:上一个基于Kernel 定时器,编写简单的demo,接下来看看定时器相关的数据结构和API。
kernel版本:4.0
1、timer_list 结构体
PATH: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
- int start_pid;
- void *start_site;
- char start_comm[16];
- #endif
- #ifdef CONFIG_LOCKDEP
- struct lockdep_map lockdep_map;
- #endif
- };
此处没有定义“CONFIG_TIMER_STATS” 和 “CONFIG_LOCKDEP”,所以只有最基本的
- struct list_head entry; /*内核中timer 链表挂接点,初始化时添加到kernel timer 链表末尾,并将下一个指向NULL */
- unsigned long expires; /* timer_list 启动时间间隔,初始化传入一个值,从初始化结束开始计算,如果到达这个时间点,则执行 下面的 function函数。
- struct tvec_base *base; */记录该软件时钟所在的 struct tvec_base 变量 */
-
- void (*function)(unsigned long); /* 时间到了的时候的回调函数 */
- unsigned long data; /* 回调函数参数 */
-
- int slack; /* 初始化的时候设置为了 -1, 后续的代码暂时未见使用 */
此时有一个新的结构体出现:
- struct tvec_base {
- spinlock_t lock; // 同步用的锁
- struct timer_list *running_timer; // 该base 指向的 timer_list
- unsigned long timer_jiffies; //下述几个都是timer_lsit 的时钟周期
- unsigned long next_timer;
- unsigned long active_timers;
- unsigned long all_timers;
- int cpu;
- struct tvec_root tv1; //这几个是软件时钟的记录链表
- struct tvec tv2;
- struct tvec tv3;
- struct tvec tv4;
- struct tvec tv5;
- } ____cacheline_aligned;
对于 struct tvec 结构体具体怎么使用,暂时还不是特别清楚,后续深入到这部分再进行补充。
2. 相关的接口函数
(1).初始化
- /*初始化 timer */
- setup_timer(&test_timer, timer_test_callback, 0);
- /*调用关系如下*/
- //1.宏定义
- #define setup_timer(timer, fn, data) \
- __setup_timer((timer), (fn), (data), 0)
- //2. 展开 __setup_timer
- #define __setup_timer(_timer, _fn, _data, _flags) \
- do { \
- __init_timer((_timer), (_flags)); \ /*继续宏定义,做初始化动作*/
- (_timer)->function = (_fn); \ /*挂接回调函数*/
- (_timer)->data = (_data); \ /*赋值回调函数参数*/
- } while (0)
-
- //3.展开 __init_timer
- #ifdef #ifdef CONFIG_LOCKDEP
- #define __init_timer(_timer, _flags) \
- do { \
- static struct lock_class_key __key; \
- init_timer_key((_timer), (_flags), #_timer, &__key); \
- } while (0)
-
- #define __init_timer_on_stack(_timer, _flags) \
- do { \
- static struct lock_class_key __key; \
- init_timer_on_stack_key((_timer), (_flags), #_timer, &__key); \
- } while (0)
- #else
- #define __init_timer(_timer, _flags) \
- init_timer_key((_timer), (_flags), NULL, NULL)
- #define __init_timer_on_stack(_timer, _flags) \
- init_timer_on_stack_key((_timer), (_flags), NULL, NULL)
- #endif
- #define __init_timer(_timer, _flags) \
- do { \
- static struct lock_class_key __key; \
- init_timer_key((_timer), (_flags), #_timer, &__key); \
- } while (0)
-
- #define __init_timer_on_stack(_timer, _flags) \
- do { \
- static struct lock_class_key __key; \
- init_timer_on_stack_key((_timer), (_flags), #_timer, &__key); \
- } while (0)
- #else //CONFIG_LOCKDEP 未定义,应该定走else
- #define __init_timer(_timer, _flags) \
- init_timer_key((_timer), (_flags), NULL, NULL)
- #define __init_timer_on_stack(_timer, _flags) \
- init_timer_on_stack_key((_timer), (_flags), NULL, NULL)
- #endif
-
- //4. 展开后,调用的是 init_timer_key() 函数
- void init_timer_key(struct timer_list *timer, unsigned int flags,
- const char *name, struct lock_class_key *key)
- {
- debug_init(timer);
- do_init_timer(timer, flags, name, key);
- }
- //5. debug_init() 方法是没有实现的,因为没有配置对应的config
- //6. do_init_timer()函数做了真正的初始动作,代码如下
- static void do_init_timer(struct timer_list *timer, unsigned int flags,
- const char *name, struct lock_class_key *key)
- {
- struct tvec_base *base = raw_cpu_read(tvec_bases);
-
- timer->entry.next = NULL;
- timer->base = (void *)((unsigned long)base | flags);
- timer->slack = -1;
- #ifdef CONFIG_TIMER_STATS
- timer->start_site = NULL;
- timer->start_pid = -1;
- memset(timer->start_comm, 0, TASK_COMM_LEN);
- #endif
- lockdep_init_map(&timer->lockdep_map, name, key, 0);
- }
(2).设置超时时间, 超时后调用回调函数
- /*更改时间*/
-
- ret = mod_timer(&test_timer, jiffies + msecs_to_jiffies(3000));
- //1. 函数原型
- int mod_timer(struct timer_list *timer, unsigned long expires)
- {
- expires = apply_slack(timer, expires);
-
- if (timer_pending(timer) && timer->expires == expires)
- return 1;
-
- return __mod_timer(timer, expires, false, TIMER_NOT_PINNED);
- }
(3).删除定时器
- del_timer(&test_timer);
-
- //函数原型
- int del_timer(struct timer_list *timer)
- {
- struct tvec_base *base;
- unsigned long flags;
- int ret = 0;
-
- debug_assert_init(timer);
-
- timer_stats_timer_clear_start_info(timer);
- if (timer_pending(timer)) {
- base = lock_timer_base(timer, &flags);
- ret = detach_if_pending(timer, base, true);
- spin_unlock_irqrestore(&base->lock, flags);
- }
-
- return ret;
- }
关于 timer 相关的API,也不算多,在 kernle/linux/timer.h中,有如下几个常用的
- static inline int timer_pending(const struct timer_list * timer)
- {
- return timer->entry.next != NULL;
- }
-
- extern void add_timer_on(struct timer_list *timer, int cpu);
- extern int del_timer(struct timer_list * timer);
- extern int mod_timer(struct timer_list *timer, unsigned long expires);
- extern int mod_timer_pending(struct timer_list *timer, unsigned long expires);
- extern int mod_timer_pinned(struct timer_list *timer, unsigned long expires);
-
- extern void set_timer_slack(struct timer_list *time, int slack_hz);
struct timer_list 中的“slack” 成员,是对延时进行微调整,但是不能起到完全控制的时间的作用,看如下对比验证:
验证一: slack 做全部延时时间设置,超时函数中的时间设置为0

===》 时间对不上
验证二:slack不设置,超时时长全部从超时函数设置

===> 基本可以对上,和之前的验证一致。
验证三: 两个都设置

==> 准确度偏高