内核延迟
1,忙等待短延时
内核中提供了如下3个函数用于纳秒、微秒和毫秒级的延时:
void ndelay(unsigned long nsecs); void udelay(unsigned long usecs); void mdelay(unsigned long msecs); //一般不建议直接使用mdelay()函数,这将无谓地耗费 CPU 资源
上述延迟的实现原理本质上是忙等待,它根据 CPU 频率进行一定次数的循环。其本质同如下代码:
void delay(unsigned int time) { while (time--); }
2、忙等待长延时函数
内核中进行延迟的一个很直观的方法是比较当前的 jiffies 和目标 jiffies(设置为当前 jiffies 加上时间间隔的 jiffies),直到未来的 jiffies 达到目标 jiffies。
利用jiffies和time_befor实现延时100个jiffies和2秒的代码:
/*延迟 100 个 jiffies*/ unsigned long delay = jiffies + 100; while (time_before(jiffies, delay)); /*再延迟 2s*/ unsigned long delay = jiffies + 2*HZ; while (time_before(jiffies, delay));
其中,time_befor()只是一个函数宏,与其对应的还有一个time_after():
#define time_after(a,b) \ (typecheck(unsigned long, a) && \ typecheck(unsigned long, b) && \ ((long)(b) - (long)(a) < 0)) #define time_before(a,b) time_after(b,a)
3、睡眠短延时
3.1 sleep类延时函数
下述函数将使得调用它的进程睡眠参数指定的时间,受系统 HZ 和进程调度的影响,msleep()类似函数的精度是有限的。msleep()、ssleep()不能被打断,而msleep_interruptible()则可以被打断。
void msleep(unsigned int millisecs); unsigned long msleep_interruptible(unsigned int millisecs); void ssleep(unsigned int seconds);
3.2 schedule类睡眠延时函数
signed long schedule_timeout_interruptible(signed long timeout); signed long schedule_timeout_uninterruptible(signed long timeout)
schedule_timeout()可以使当前任务睡眠指定的jiffies 之后重新被调度执行,它的实现原理是向系统添加一个定时器,在定时器处理函数中唤醒参数对应的进程。上一小节的sleep类函数的底层实现也是调用它实现的:
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); //返回剩余的延时时间 } signed long _ _sched schedule_timeout_interruptible(signed long timeout) { _ _set_current_state(TASK_INTERRUPTIBLE); //置进程状态为 TASK_INTERRUPTIBLE return schedule_timeout(timeout); } signed long _ _sched schedule_timeout_uninterruptible(signed long timeout) { _ _set_current_state(TASK_UNINTERRUPTIBLE); //置进程状态为 TASK_UNINTERRUPTIBLE return schedule_timeout(timeout); }
3.3 sleep_on类,在等待队列上睡眠的延时函数
函数可以将当前进程添加到等待队列中,从而在等待队列上睡眠。当超时发生时,进程将被唤醒(后者可以在超时前被打断):
sleep_on_timeout(wait_queue_head_t *q, unsigned long timeout); interruptible_sleep_on_timeout(wait_queue_head_t*q, unsigned long timeout);