linux驱动学习之内核定时器使用

内核定时器是内核用来控制在未来某个时间点调度执行某个函数的一种机制,而且是处于中断上下文中,所以调度函数必须遵守以下规则:
1) 没有 current 指针、不允许访问用户空间。因为没有进程上下文,相关代码和被中断的进程没有任何联系。
2) 定时器函数必须是原子的,不能进行睡眠或者调度. 原子代码不能调用 schedule 或者某种 wait_event, 也不能调用任何其他可能睡眠的函数. 例如, 调用 kmalloc(..., GFP_KERNEL) 是违犯规则的. 旗标也必须不能使用因为它们可能睡眠.
3) 任何被定时器函数存取的数据结构应当保护避免并发存取。

       一个重新注册它自己的定时器一直运行在同一个 CPU,内核代码能够通过调用函数 in_interrupt()告知是否它在中断上下文中运行, 如果处理器当前在中断上下文运行就返回非零, 要么硬件中断要么软件中断.另一函数in_atomic()用于判断调度被禁止时它的返回值是非零;

       内核定时器的调度函数运行过一次后自动注销,但可以通过在被调度的函数中重新调度自己来周期运行。

1.定义

定义时初始化
该宏会定义一个名叫 timer_name 内核定时器,并初始化其 function, expires, name 和 base 字段,由于在定义时初始化,初始化值不能有变量。
DEFINE_TIMER(timer_name, function_name, expires_value, data);

先定义后初始化
struct timer_list mytimer;
setup_timer(&mytimer, (*function)(unsigned long), unsigned long data);
mytimer.expires = jiffies + 5*HZ;
add_timer(struct timer_list *timer) 

2.相关函数

add_timer可以使定时器连接到内核定时链表中去,如果在链表内那么timer_pending会返回真 
static inline void add_timer(struct timer_list *timer)
{
	BUG_ON(timer_pending(timer));
	__mod_timer(timer, timer->expires);
}


要修改一个定时器的调度时间,如果修改的定时上次定时还没到返回1否则返回0。
int mod_timer(struct timer_list *timer, unsigned long expires)
mod_timer(timer, expires) is equivalent to:del_timer(timer); timer->expires = expires; add_timer(timer);
可见mod_timer可以替换add_timer,在多线程使用同一timer时,最好使用mod_timer,使用add_timer可能会报告BUG。


注销一个定时器,其中 del_timer_sync 是用在 SMP 系统上的(在非SMP系统上,它等于del_timer)要被注销的定时器函数正在另一个 cpu 上运行时,del_timer_sync() 会等待其运行完,所以这个函数会休眠。另外还应避免它和被调度的函数争用同一个锁。对于一个已经被运行过且没有重新注册自己的定时器而言,注销函数其实也没什么事可做。
del_timer(struct timer_list *timer) ;
del_timer_sync(struct timer_list *timer);


这个函数用来判断一个定时器是否被添加到了内核链表中以等待被调度运行。注意,当一个定时器函数即将要被运行前,内核会把相应的定时器从内核链表中删除(相当于注销)这样定时器函数就可以重新注册自己。
int timer_pending(const struct timer_list *timer);



你可能感兴趣的:(linux驱动学习之内核定时器使用)