设备驱动程序经常需要某些特定代码延迟一段时间后执行,为了让硬件能完成某些任务。
长延迟
忙等待
把执行延迟若干个时钟滴答,或对延迟的精度要求不高。
while(time_before(jiffies, j1))
{
cpu_relax();
}
会降低系统性能。
让出处理器
在不需要CPU时主动释放CPU,通过调用schedule函数实现,<linux/sched.h>。
while(time_before(jiffies, j1))
{
schedule();
}
超时
实现延迟的最好方法应该是让内核为我们完成相应的工作。有两种构造基于jiffies超时的路径,使用哪个则依赖于驱动程序是否在等待其它事件。
一、等待队列
驱动程序使用等待队列来等待其它一些事件,希望在特定时间段中运行,则可以使用wait_event_timeout或者wait_event_interruptible_timeout函数,这两个函数会在给定的等待队列上休眠,会在超时到期时返回。
二、不等待特定事件而延迟
schedule_timeout函数,<linux/sched.h>可以避免声明和和使用多于的等待队列头。
signed long schedule_timeout(signed long timeout);
schedule_timeout调用前要设置当前进程状态
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(delay);
调度器会在超时且其状态变成TASK_RUNNING时才会运行这个进程。
短延迟
当设备驱动程序需要处理硬件的延迟时,这种延迟通常最多涉及到几十毫秒,这时时钟滴答不是正确的方法。
ndelay、udelay和mdelay几个内核函数可以很好地完成短延迟任务,分别延迟指定的纳秒、微秒和毫秒。
<linux/delay.h>
void ndelay(unsigned long nsecs);
void udelay(unsigned long usecs);
void mdelay(unsigned long msecs);
一般性规则,延迟上千个纳秒应使用udelay(微秒)而不是ndelay(纳秒),毫秒级延迟应使用mdelay而不是更细粒度的短延迟函数。
以上三个延迟函数都是忙等待函数,延迟过程中无法运行其它任务。
实现毫秒级或更长延迟还有其它一些函数,不涉及忙等待,<linux/delay.h>
void msleep(unsigned int millisecs); //不可中断
unsigned long msleep_interruptible(unsignd int millisecs); //可中断,进程提前唤醒时返回剩余毫秒数
void ssleep(unsigned int secs); //秒级延迟,不可中断
本文介绍了Linux内核中实现延时的各种方法,包括忙等待和非忙等待的长延迟与短延迟技术。长延迟可通过while循环结合cpu_relax()或schedule()实现,短延迟则利用ndelay(), udelay(), mdelay()等函数完成。此外,还介绍了如何使用等待队列和schedule_timeout()函数来实现超时处理。
494

被折叠的 条评论
为什么被折叠?



