在内核中,以jiffies为单位的进行的延迟通常被认为是长延时。
一种可能但非最佳的实现长延时的方法是忙等待,它本身不利用CPU进行有用的工作,同时还不让其他应用使用CPU。
来个示例:
unsigned long timeout = jiffies + HZ;
while(time_before(jiffies, timeout)) {
cpu_relax();
}
对cpu_relax的调用将以架构相关的方式执行,其中不执行大量的处理器代码。在许多系统上,该函数根本不会做任何事情;而在对称多线程(“超线程”)系统上,它可能将处理器让给其他线程。但不论是哪种情况,只要可能,我们都应该尽量避免使用这种方式。
实现长延时的更好方法是睡眠等待而不是忙等待,在这种方式中,本进程会在等待时将处理器出让给其他进程。
schedule_timeout便能实现此功能:
/**
* schedule_timeout - sleep until timeout
* @timeout: timeout value in jiffies
*
* Make the current task sleep until @timeout jiffies have
* elapsed. The routine will return immediately unless
* the current task state has been set (see set_current_state()).
*
* You can set the task state as follows -
*
* %TASK_UNINTERRUPTIBLE - at least @timeout jiffies are guaranteed to
* pass before the routine returns. The routine will return 0
*
* %TASK_INTERRUPTIBLE - the routine may return early if a signal is
* delivered to the current task. In this case the remaining time
* in jiffies will be returned, or 0 if the timer expired in time
*
* The current task state is guaranteed to be TASK_RUNNING when this
* routine returns.
*
* Specifying a @timeout value of %MAX_SCHEDULE_TIMEOUT will schedule
* the CPU away without a bound on the timeout. In this case the return
* value will be %MAX_SCHEDULE_TIMEOUT.
*
* In all cases the return value is guaranteed to be non-negative.
*/
signed long __sched schedule_timeout(signed long timeout)
这种延时仅仅确保超时较低时的精度。由于只有在时钟节拍引发的内核调度才会更新jiffies,所以无论是在内核空间还是在用户空间,都很难使超时的精度比HZ更大了。另外,即使你的进程以及超时并可被调度,但是调度器仍然可能基于优先级策略选择运行队列的其他进程。
这个函数还有以下一些变种:
/*
* We can use __set_current_state() here because schedule_timeout() calls
* schedule() unconditionally.
*/
signed long __sched schedule_timeout_interruptible(signed long timeout)
{
__set_current_state(TASK_INTERRUPTIBLE);
return schedule_timeout(timeout);
}
EXPORT_SYMBOL(schedule_timeout_interruptible);
signed long __sched schedule_timeout_killable(signed long timeout)
{
__set_current_state(TASK_KILLABLE);
return schedule_timeout(timeout);
}
EXPORT_SYMBOL(schedule_timeout_killable);
signed long __sched schedule_timeout_uninterruptible(signed long timeout)
{
__set_current_state(TASK_UNINTERRUPTIBLE);
return schedule_timeout(timeout);
}
用于睡眠等待的另外两个函数是wait_event_timeout和msleep,它们的实现都基于schedule_timeout。
wait_event_timeout的使用场合是:在一个特定的条件满足或者超时发生后,希望代码继续运行。
msleep表示:睡眠指定的时间(以毫秒为单位)。
这种长延时技术仅仅适用于进程上下文。睡眠等待不能用于中断上下文。