内核延时函数

1) msleep:实现毫秒级的延时,该延时保证至少延时所设置的延时时间,不会提前超时返回,会让出CPU


   
   
  1. void msleep(unsigned int msecs)
  2. {
  3. unsigned long timeout = msecs_to_jiffies(msecs) + 1;
  4. while (timeout)
  5. timeout = schedule_timeout_uninterruptible(timeout);
  6. }

为什么在转换成jiffies时要+1呢?前边我们讲到,该延时要至少保证延时转换的jiffies时间,一个jiffies为10毫秒,比如我们可以查10个数表示一个jiffies,在数到5时调用了msleep,那么显然我们不能在此jiffies到时时返回,违反了至少延时设置的jiffies的原则,因此转换成jiffies+1是比较合适的,内核中也特意做了解释。


   
   
  1. unsigned long msecs_to_jiffies(const unsigned int m)
  2. {
  3. /*
  4. * Negative value, means infinite timeout:
  5. */
  6. if (( int)m < 0)
  7. return MAX_JIFFY_OFFSET;
  8. }
  9. /*
  10. * Change timeval to jiffies, trying to avoid the
  11. * most obvious overflows..
  12. *
  13. * And some not so obvious.
  14. *
  15. * Note that we don't want to return LONG_MAX, because
  16. * for various timeout reasons we often end up having
  17. * to wait "jiffies+1" in order to guarantee that we wait
  18. * at _least_ "jiffies" - so "jiffies+1" had better still
  19. * be positive.
  20. */
  21. #define MAX_JIFFY_OFFSET ((LONG_MAX >> 1)-1)


2)msleep_interruptible:毫秒级延时,该延时函数有可能被信号打断提前超时,返回剩余的时间,会让出CPU


   
   
  1. unsigned long msleep_interruptible(unsigned int msecs)
  2. {
  3. unsigned long timeout = msecs_to_jiffies(msecs) + 1;
  4. while (timeout && ! signal_pending(current))
  5. timeout = schedule_timeout_interruptible(timeout);
  6. return jiffies_to_msecs(timeout);
  7. }

3)ssleep:秒级延时,通过调用msleep实现,会让出CPU


   
   
  1. static inline void ssleep(unsigned int seconds)
  2. {
  3. msleep(seconds * 1000);
  4. }

4)usleep_range:该延时函数实现微秒级延时,特别之处在于其可以设定一个超时范围,通过看源代码可以发现此函数设置任务状态为ASK_UNINTERRUPTIBLE,即该延时至少可以保证延时min微秒而不被打断。会让出CPU


   
   
  1. /**
  2. * usleep_range - Drop in replacement for udelay where wakeup is flexible
  3. * @min: Minimum time in usecs to sleep
  4. * @max: Maximum time in usecs to sleep
  5. */
  6. void usleep_range(unsigned long min, unsigned long max)
  7. {
  8. __set_current_state(TASK_UNINTERRUPTIBLE);
  9. do_usleep_range(min, max);
  10. }


5)ndelay:纳秒级延时,不会让出CPU


   
   
  1. static inline void ndelay(unsigned long x)
  2. {
  3. udelay( DIV_ROUND_UP(x, 1000));
  4. }


6)udelay:微秒延时,不会让出CPU


   
   
  1. /*
  2. * division by multiplication: you don't have to worry about
  3. * loss of precision.
  4. *
  5. * Use only for very small delays ( < 2 msec). Should probably use a
  6. * lookup table, really, as the multiplications take much too long with
  7. * short delays. This is a "reasonable" implementation, though (and the
  8. * first constant multiplications gets optimized away if the delay is
  9. * a constant)
  10. */
  11. #define __udelay(n) arm_delay_ops.udelay(n)
  12. #define __const_udelay(n) arm_delay_ops.const_udelay(n)
  13. #define udelay(n) \
  14. (__builtin_constant_p(n) ? \
  15. ((n) > (MAX_UDELAY_MS * 1000) ? __bad_udelay() : \
  16. __const_udelay((n) * UDELAY_MULT)) : \
  17. __udelay(n))


关于__builtin_constant_p(x),准确的定义应该是:如果x的值在编译时能确定,那么该函数返回值为1。

对于arm_delay_ops来讲,内核有一套默认的回调函数


   
   
  1. /*
  2. * Default to the loop-based delay implementation.
  3. */
  4. struct arm_delay_ops arm_delay_ops = {
  5. .delay = __loop_delay,
  6. .const_udelay = __loop_const_udelay,
  7. .udelay = __loop_udelay,
  8. };


但是大部分厂商一般都会注册自己的timer,来提供延时使用,具体可参考arch/arm/lib/delay.c实现


   
   
  1. /*
  2. * Default to the loop-based delay implementation.
  3. */
  4. struct arm_delay_ops arm_delay_ops = {
  5. .delay = __loop_delay,
  6. .const_udelay = __loop_const_udelay,
  7. .udelay = __loop_udelay,
  8. };
  9. #ifdef ARCH_HAS_READ_CURRENT_TIMER
  10. static void __timer_delay( unsigned long cycles)
  11. {
  12. cycles_t start = get_cycles();
  13. while (( get_cycles() - start) < cycles)
  14. cpu_relax();
  15. }
  16. static void __timer_const_udelay( unsigned long xloops)
  17. {
  18. unsigned long long loops = xloops;
  19. loops *= loops_per_jiffy;
  20. __timer_delay(loops >> UDELAY_SHIFT);
  21. }
  22. static void __timer_udelay( unsigned long usecs)
  23. {
  24. __timer_const_udelay(usecs * UDELAY_MULT);
  25. }
  26. void __init init_current_timer_delay(unsigned long freq)
  27. {
  28. pr_info( "Switching to timer-based delay loop\n");
  29. lpj_fine = freq / HZ; //一个jiffy定时器跳变的值
  30. loops_per_jiffy = lpj_fine;
  31. arm_delay_ops.delay = __timer_delay;
  32. arm_delay_ops.const_udelay = __timer_const_udelay;
  33. arm_delay_ops.udelay = __timer_udelay;
  34. }
  35. unsigned long __cpuinit calibrate_delay_is_known(void)
  36. {
  37. return lpj_fine;
  38. }
  39. #endif

7)mdelay:毫秒级延时,ndelay的1000倍,不会让出CPU


   
   
  1. #ifndef mdelay
  2. #define mdelay(n) (\
  3. (__builtin_constant_p(n) && (n)<=MAX_UDELAY_MS) ? udelay((n)*1000) : \
  4. ({unsigned long __ms=(n); while (__ms--) udelay(1000);}))
  5. #endif


 

关于延时函数会不会让出CPU,使用时需要注意,一般对延时要求特别精确,使用不让出CPU的延时函数;对延时要求不是特别精确的,可以使用让出CPU的延时函数,为了保证延时时系统不会进入睡眠,通常在使用会让出CPU的延时前要加上wakelock锁来阻止睡眠。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值