1) msleep:实现毫秒级的延时,该延时保证至少延时所设置的延时时间,不会提前超时返回,会让出CPU
-
void msleep(unsigned int msecs)
-
{
-
unsigned
long timeout =
msecs_to_jiffies(msecs) +
1;
-
-
while (timeout)
-
timeout =
schedule_timeout_uninterruptible(timeout);
-
}
为什么在转换成jiffies时要+1呢?前边我们讲到,该延时要至少保证延时转换的jiffies时间,一个jiffies为10毫秒,比如我们可以查10个数表示一个jiffies,在数到5时调用了msleep,那么显然我们不能在此jiffies到时时返回,违反了至少延时设置的jiffies的原则,因此转换成jiffies+1是比较合适的,内核中也特意做了解释。
-
unsigned long msecs_to_jiffies(const unsigned int m)
-
{
-
/*
-
* Negative value, means infinite timeout:
-
*/
-
if ((
int)m <
0)
-
return MAX_JIFFY_OFFSET;
-
。
-
。
-
。
-
}
-
/*
-
* Change timeval to jiffies, trying to avoid the
-
* most obvious overflows..
-
*
-
* And some not so obvious.
-
*
-
* Note that we don't want to return LONG_MAX, because
-
* for various timeout reasons we often end up having
-
* to wait "jiffies+1" in order to guarantee that we wait
-
* at _least_ "jiffies" - so "jiffies+1" had better still
-
* be positive.
-
*/
-
#define MAX_JIFFY_OFFSET ((LONG_MAX >> 1)-1)
2)msleep_interruptible:毫秒级延时,该延时函数有可能被信号打断提前超时,返回剩余的时间,会让出CPU
-
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);
-
}
3)ssleep:秒级延时,通过调用msleep实现,会让出CPU
-
static inline void ssleep(unsigned int seconds)
-
{
-
msleep(seconds *
1000);
-
}
4)usleep_range:该延时函数实现微秒级延时,特别之处在于其可以设定一个超时范围,通过看源代码可以发现此函数设置任务状态为ASK_UNINTERRUPTIBLE,即该延时至少可以保证延时min微秒而不被打断。会让出CPU
-
/**
-
* usleep_range - Drop in replacement for udelay where wakeup is flexible
-
* @min: Minimum time in usecs to sleep
-
* @max: Maximum time in usecs to sleep
-
*/
-
void usleep_range(unsigned long min, unsigned long max)
-
{
-
__set_current_state(TASK_UNINTERRUPTIBLE);
-
do_usleep_range(min, max);
-
}
5)ndelay:纳秒级延时,不会让出CPU
-
static inline void ndelay(unsigned long x)
-
{
-
udelay(
DIV_ROUND_UP(x,
1000));
-
}
6)udelay:微秒延时,不会让出CPU
-
/*
-
* division by multiplication: you don't have to worry about
-
* loss of precision.
-
*
-
* Use only for very small delays ( < 2 msec). Should probably use a
-
* lookup table, really, as the multiplications take much too long with
-
* short delays. This is a "reasonable" implementation, though (and the
-
* first constant multiplications gets optimized away if the delay is
-
* a constant)
-
*/
-
#define __udelay(n) arm_delay_ops.udelay(n)
-
#define __const_udelay(n) arm_delay_ops.const_udelay(n)
-
-
#define udelay(n) \
-
(__builtin_constant_p(n) ? \
-
((n) > (MAX_UDELAY_MS * 1000) ? __bad_udelay() : \
-
__const_udelay((n) * UDELAY_MULT)) : \
-
__udelay(n))
关于__builtin_constant_p(x),准确的定义应该是:如果x的值在编译时能确定,那么该函数返回值为1。
对于arm_delay_ops来讲,内核有一套默认的回调函数
-
/*
-
* Default to the loop-based delay implementation.
-
*/
-
struct
arm_delay_ops arm_delay_ops = {
-
.delay = __loop_delay,
-
.const_udelay = __loop_const_udelay,
-
.udelay = __loop_udelay,
-
};
但是大部分厂商一般都会注册自己的timer,来提供延时使用,具体可参考arch/arm/lib/delay.c实现
-
/*
-
* Default to the loop-based delay implementation.
-
*/
-
struct
arm_delay_ops arm_delay_ops = {
-
.delay = __loop_delay,
-
.const_udelay = __loop_const_udelay,
-
.udelay = __loop_udelay,
-
};
-
-
#ifdef ARCH_HAS_READ_CURRENT_TIMER
-
static
void __timer_delay(
unsigned
long cycles)
-
{
-
cycles_t start =
get_cycles();
-
-
while ((
get_cycles() - start) < cycles)
-
cpu_relax();
-
}
-
-
static
void __timer_const_udelay(
unsigned
long xloops)
-
{
-
unsigned
long
long loops = xloops;
-
loops *= loops_per_jiffy;
-
__timer_delay(loops >> UDELAY_SHIFT);
-
}
-
-
static
void __timer_udelay(
unsigned
long usecs)
-
{
-
__timer_const_udelay(usecs * UDELAY_MULT);
-
}
-
-
void __init init_current_timer_delay(unsigned long freq)
-
{
-
pr_info(
"Switching to timer-based delay loop\n");
-
lpj_fine = freq / HZ;
//一个jiffy定时器跳变的值
-
loops_per_jiffy = lpj_fine;
-
arm_delay_ops.delay = __timer_delay;
-
arm_delay_ops.const_udelay = __timer_const_udelay;
-
arm_delay_ops.udelay = __timer_udelay;
-
}
-
-
unsigned long __cpuinit calibrate_delay_is_known(void)
-
{
-
return lpj_fine;
-
}
-
#endif
7)mdelay:毫秒级延时,ndelay的1000倍,不会让出CPU
-
#ifndef mdelay
-
#define mdelay(n) (\
-
(__builtin_constant_p(n) && (n)<=MAX_UDELAY_MS) ? udelay((n)*1000) : \
-
({unsigned long __ms=(n); while (__ms--) udelay(1000);}))
-
#endif
关于延时函数会不会让出CPU,使用时需要注意,一般对延时要求特别精确,使用不让出CPU的延时函数;对延时要求不是特别精确的,可以使用让出CPU的延时函数,为了保证延时时系统不会进入睡眠,通常在使用会让出CPU的延时前要加上wakelock锁来阻止睡眠。