内核延时

查阅内核代码时经常看到和应用到延时,本文用于归纳延时相关内容。

一. 短延时

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. 设备驱动开发详解  宋宝华

posted @ 2018-03-18 16:52  yuxi_o  阅读(586)  评论(0编辑  收藏  举报