zoukankan      html  css  js  c++  java
  • 内核延时功能

    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
    ");
    	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锁,防止睡眠。

    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    Mysql 时间操作
    curl 学习
    CURL详解
    mysql 获取当前时间戳
    php开启openssl的方法
    0,null,empty,空,false,isset
    ecshop微信扫描支付开发
    seaJs的简单应用
    js运动框架之掉落的扑克牌(重心、弹起效果)
    js运动框架完成块的宽高透明度及颜色的渐变
  • 原文地址:https://www.cnblogs.com/blfshiye/p/4803669.html
Copyright © 2011-2022 走看看