linux内核定时器的使用
1、timer的使用
timer相关函数的定义在kernel\time\timer.c和include\linux\timer.h中。
定时器的结构体为
// include\linux\timer.h
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
};
其中function()为定时器期满后执行的函数。expires是定时器到期的时间(jiffies),entry用于内核维护定时器的链表,用户不用关心。
tiemr_list的结构体从4.14发生了变化,其中删除了data成员变量,同时function的参数类型也发生了变化。其中一些使用的接口也发生了变化。
1、首先是通过两个宏来初始化定时器。
(1)
// include\linux\timer.h
/**
* timer_setup - prepare a timer for first use
* @timer: the timer in question
* @callback: the function to call when timer expires
* @flags: any TIMER_* flags
*
* Regular timer initialization should use either DEFINE_TIMER() above,
* or timer_setup(). For timers on the stack, timer_setup_on_stack() must
* be used and must be balanced with a call to destroy_timer_on_stack().
*/
#define timer_setup(timer, callback, flags) \
__init_timer((timer), (callback), (flags))
#define __init_timer(_timer, _fn, _flags) \
init_timer_key((_timer), (_fn), (_flags), NULL, NULL)
/**
* init_timer_key - initialize a timer
* @timer: the timer to be initialized
* @func: timer callback function
* @flags: timer flags
* @name: name of the timer
* @key: lockdep class key of the fake lock used for tracking timer
* sync lock dependencies
*
* init_timer_key() must be done to a timer prior calling *any* of the
* other timer functions.
*/
void init_timer_key(struct timer_list *timer,
void (*func)(struct timer_list *), unsigned int flags,
const char *name, struct lock_class_key *key)
{
debug_init(timer);
do_init_timer(timer, func, flags, name, key);
}
@timer:struct timer_list类型,提前定义好的timer结构体。需要申请的定时器。
@callback: timer超时的回调函数。注意这里的回调函数的参数类型为struct timer_list *
(2)
或者使用DEFINE_TIMER定义并初始化timer.
// include\linux\timer.h
#define DEFINE_TIMER(_name, _function) \
struct timer_list _name = \
__TIMER_INITIALIZER(_function, 0)
2、为timer的expires赋值。
3、调用add_timer注册内核定时器,将定时器加入到内核动态定时器链表中。
// kernel\tiem\timer.c
void add_timer(struct timer_list *timer)
{
BUG_ON(timer_pending(timer));
mod_timer(timer, timer->expires);
}
EXPORT_SYMBOL(add_timer);
2 其他API
删除定时器
// kernel\tiem\timer.c
int del_timer(struct timer_list *timer)
{
struct timer_base *base;
unsigned long flags;
int ret = 0;
debug_assert_init(timer);
if (timer_pending(timer)) {
base = lock_timer_base(timer, &flags);
ret = detach_if_pending(timer, base, true);
raw_spin_unlock_irqrestore(&base->lock, flags);
}
return ret;
}
EXPORT_SYMBOL(del_timer);
del_timer_sync是del_timer()的同步版,在删除一个定时器时需等待其被执行完,因此该函数的调用不能发生在中断上下文。
// kernel\tiem\timer.c
int del_timer_sync(struct timer_list *timer)
{
#ifdef CONFIG_LOCKDEP
unsigned long flags;
/*
* If lockdep gives a backtrace here, please reference
* the synchronization rules above.
*/
local_irq_save(flags);
lock_map_acquire(&timer->lockdep_map);
lock_map_release(&timer->lockdep_map);
local_irq_restore(flags);
#endif
/*
* don't use it in hardirq context, because it
* could lead to deadlock.
*/
WARN_ON(in_irq() && !(timer->flags & TIMER_IRQSAFE));
for (;;) {
int ret = try_to_del_timer_sync(timer);
if (ret >= 0)
return ret;
cpu_relax();
}
}
修改定时器的expire
// kernel\tiem\timer.c
int mod_timer(struct timer_list *timer, unsigned long expires)
{
return __mod_timer(timer, expires, 0);
}
该函数用于修改定时器的到期时间。