内核需要定时器来实现一定的延时。
数据结构定义:
struct timer_list {
struct list_head entry; /* entry in linked list of timers */
unsigned long expires; /* expiration value, in jiffies */
void (*function)(unsigned long); /* the timer handler function */
unsigned long data; /* lone argument to the handler */
struct tvec_t_base_s *base; /* internal timer field, do not touch */
};
操作:
void init_timer(struct timer_list *timer);
TIMER_INITIALIZER(_functioin, _expires, _data)宏用于赋值定时器结构体的function、expires、data和base成员。
DEFINE_TIMER(_name, _function, _expires, _data)
setup_timer()也可用于初始化定时器并赋值其成员。
增加定时器
void add_timer(struct timer_list *timer);
删除定时器
int del_timer(struct timer_list *timer);
int del_timer _sync (struct timer_list *timer);注:该函数不能用于中断上下文中,其他情况下尽量用户该函数。
修改定时器的expire
int mod_timer(struct timer_list *timer, unsigned long expires);
内核定时器模板 |
/*XXX设备结构体*/ struct xxx_dev { struct cdev cdev; … timer_list xxx_timer;/*设备要使用的定时器*/ };
/*xxx驱动中的某函数*/ xxx_funcl(…) { struct xxx_dev *dev = filp->private_data; … /*初始化定时器*/ init_timer(&dev->xxx_timer); dev->xxx_timer.function = &xxx_do_timer; dev->xxx_timer.data = (unsigned long)dev; /*设备结构体指针作为定时器处理函数参数*/ dev->xxx_timer.expires = jiffies + delay; /*添加(注册)定时器*/ add_timer(&dev->xxx_timer); … };
/*xxx驱动中的某函数*/ xxx_func2(…) { … /*删除定时器*/ del_timer(&dev->xxx_timer); … }
/*定时器处理函数*/ static void xxx_do_timer(unsigned long arg) { struct xxx_device *dev = (struct xxx_device*)(arg); … /*调度定时器再执行*/ dev->xxx_timer.expires = jiffies + delay; add_timer(&dev->xxx_timer); … } |
延时机制
1. 忙等待,如:
unsigned long timeout = jiffies + 10; /* ten ticks */
while (time_before(jiffies, timeout))
;
2. 重新调度,如:
unsigned long delay = jiffies + 5*HZ;
while (time_before(jiffies, delay))
cond_resched();
其中,cond_resched()仅调度一个设置了need_resched标志的进程。
3. 小延时
有时,内核代码需要更精确的延时,如小于一个时钟滴答。通常小于1毫秒,基于jiffies的延时是不能满足要求的。内核提供了三个函数分别处理微秒,纳秒和毫秒,原型如下:
void udelay(unsigned long usecs) //微秒
void ndelay(unsigned long nsecs) //纳秒
void mdelay(unsigned long msecs) //毫秒
udelay()实现为一个循环,它能知道一个给定的时间段有多少次迭代。mdelay()函数基于udelay()函数实现的。内核知道处理器1秒钟能完成的循环次数。udelay()函数仅用于非常小的延迟。超过1毫秒的延迟不要使用udelay()。对于较长的延时,使用mdelay()。类似于忙等待,一般情况下,不要使用这些函数,除非有必要。
4. schedule_timeout()
一种更好的延迟执行的方式是使用schedule_timeout()函数。该调用将当前任务标记为睡眠状态直到指定的时间已经过去。通常,睡眠的时间很难保证与指定指定的时间一致。调用方式如下:
/* set task’s state to interruptible sleep */
set_current_state(TASK_INTERRUPTIBLE);
/* take a nap and wake up in “s” seconds */
schedule_timeout(s * HZ);