内核中有一个时钟,时钟每次的tick都会触发一个时钟中断,中断时将检查是否有定时器到期,根据需要在软件中断中执行定时器函数。因此:
内核定时器在时钟中断的下半段执行,非进程的上下文
不能使用休眠函数
不能访问用户空间
更详细的执行过程:
参考:http://www.cnblogs.com/leaven/archive/2010/08/19/1803382.html
实际上,内核为定时器维护着两个全局变量jiffies和timer_jiffies。
jiffies表示当前的时钟,timer_jiffies表示上次中断发生的时钟。一般来说,每个时钟都会发生中断。
jiffies-timer_jiffies表示,距离上次中断这段时间里发生中断的数目。当这个值为3时,需要调用timer_list列表中序号为1,2,3的定时器。
每个定时器的使用下面数据结构描述。
struct timer_list {
struct list_head entry;
unsigned long expires;
void (*function)(unsigned long);
unsigned long data;
struct tvec_base *base;
#ifdef CONFIG_TIMER_STATS
void *start_site;
char start_comm[16];
int start_pid;
#endif
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
方法一:
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;
void add_timer(struct timer_list *timer)
{
BUG_ON(timer_pending(timer));
mod_timer(timer, timer->expires);
}
int del_timer(struct timer_list *timer)
{
struct tvec_base *base;
unsigned long flags;
int ret = 0;
timer_stats_timer_clear_start_info(timer);
if (timer_pending(timer)) {
base = lock_timer_base(timer, &flags);
if (timer_pending(timer)) {
detach_timer(timer, 1);
ret = 1;
}
spin_unlock_irqrestore(&base->lock, flags);
}
return ret;
}
内核中维护着一个timer_list列表,注册和销毁的过程实际上就是添加或者删除列表的过程。
可以简单的认为这个列表中存在256个数组,内核在每个tick检查其中一个数组项,执行其中的定时器回调函数。
参考:http://blog.csdn.net/lizhiguo0532/article/details/6406161
和定时器相关的延时函数:
这些延时会浪费CPU资源:
mdelay udelay ndelay 以及time_before、time_after(高精度)
另外一种是让出CPU一段时间
void msleep(unsigned int msecs)
{
unsigned long timeout = msecs_to_jiffies(msecs) + 1;
while (timeout)
timeout = schedule_timeout_uninterruptible(timeout);
}
unsigned long msleep_interruptible(unsigned int msecs)
{
unsigned long timeout = msecs_to_jiffies(msecs) + 1;
while (timeout && !signal_pending(current))
timeout = schedule_timeout_interruptible(timeout);
return jiffies_to_msecs(timeout);
}
从中可以看到,schedule_timeout和schedule_timeout_xxx实际上实现了sleep相关函数。