内核延时
查阅内核代码时经常看到和应用到延时,本文用于归纳延时相关内容。
一. 短延时
void ndelay(unsigned long nsecs); void udelay(unsigned long usecs); void mdelay(unsigned long msecs);
短延时的本质是忙等。
毫秒时延已经很大了,在内核中,最好不要直接使用mdelay(),无谓消耗cpu资源,对于毫秒级以上时延,内核提供如下函数:
void msleep(unsigned int msecs); unsigned long msleep_interruptible(unsigned int msecs); void ssleep(unsigned long secs);
msleep(),ssleep()不能被打断,msleep_interruptible()则可以被打断。
二. 长延时
内核中进行延时的一个很直观的方法是比较当前的jiffies和目标jiffies,直到未来的jiffies达到目标jiffies。
unsigned long delay = jiffies + 100; while(time_before(jiffies, delay)); unsigned long delay = jiffies + 2*Hz; while(time_before(jiffies, delay));
延时100jiffies,然后再延时2s。
#define time_after(a,b) \ (typecheck(unsigned long, a) && \ typecheck(unsigned long, b) && \ ((long)((b) - (a)) < 0)) #define time_before(a,b) time_after(b,a)
不推荐(禁止)直接jiffies值比较,因为jiffies有溢出,必须考虑wrap,推荐使用time_after()和time_before()。
三. 睡眠延时
linux/sched.h extern signed long schedule_timeout(signed long timeout); extern signed long schedule_timeout_interruptible(signed long timeout); extern signed long schedule_timeout_killable(signed long timeout); extern signed long schedule_timeout_uninterruptible(signed long timeout);
schedule_timeout()可以使当前任务睡眠指定的jiffies之后重新调度执行,msleep()和msleep_interruptible()本质就是依靠schedule_timeout_uninterruptible()和schedule_timeout_interruptible()实现的。
extern void sleep_on(wait_queue_head_t *q); extern long sleep_on_timeout(wait_queue_head_t *q, signed long timeout); extern void interruptible_sleep_on(wait_queue_head_t *q); extern long interruptible_sleep_on_timeout(wait_queue_head_t *q, signed long timeout);
将当前进程添加到等待队列中,从而在等待队列上睡眠。当超时发生时,进程被唤醒。
参考:
1. 设备驱动开发详解 宋宝华