Linux驱动之定时器和延时

内核中有一个时钟,时钟每次的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相关函数。




你可能感兴趣的:(Linux驱动)