kernel-4.0 定时数据结构和API

概述:上一个基于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不设置,超时时长全部从超时函数设置

===> 基本可以对上,和之前的验证一致。

验证三: 两个都设置

 ==> 准确度偏高

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值