内核定时器和延迟

1. 定时器

#include <timer.h>

struct timer_list {
    struct list_head entry;
    unsigned long expires;

    void (*function)(unsigned long);
    unsigned long data;

    struct tvec_base *base;
#ifdef CONFIG_TIMER_STATS
    void *start_site;
    char start_comm[16];
    int start_pid;
#endif
#ifdef CONFIG_LOCKDEP
    struct lockdep_map lockdep_map;
#endif
};
static void timer_handle(unsigned long data)
{
    mod_timer(&timer, jiffies + HZ);
}

struct timer_list timer;
init_timer(&timer);
timer.expires = expire;
timer.data = (unsigned long )data;
timer.function = timer_handle;
add_timer(&timer);

del_timer(&timer);

HZ:每秒的周期次数(周期/秒)

2. delay
有时驱动程序不但需要很短暂的延迟(比时钟节拍还短)而且还要求延迟的时间很精确

#include <delay.h>

void ndelay(unsigned long nsecs)
static inline void udelay(unsigned long usecs);
#define mdelay(n) udelay((n) * 1000)

毫秒级以上的延时,最好不要直接使用mdelay函数,这将无谓的浪费cpu的资源
注:不要在持有锁时或禁止中断时使用忙等待

3. sleep
毫秒级以上的延时

static inline void msleep(unsigned int msecs)
{
    unsigned long timeout = MSECS(msecs) + 1;

    while (timeout) {
        set_current_state(TASK_UNINTERRUPTIBLE);
        timeout = schedule_timeout(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);
}

static inline void ssleep(unsigned int seconds)
{
    msleep(seconds * 1000);
}

注:受系统HZ以及进程调度的影响,msleep类似函数的精度是有限的

4. 长延迟

#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)

5. schedule_timeout
让需要延迟执行的任务睡眠到指定的延迟时间耗尽后再重新运行

//睡s秒后自动唤醒
schedule_timeout(s * HZ);

由于schedule_timeout函数需要调用调度程序,所以调用它的代码必须保证能够睡眠,调用代码必须处于进程上下文中,并且不能持有锁

signed long __sched schedule_timeout(signed long timeout)
{
    struct timer_list timer;
    unsigned long expire;

    switch (timeout)
    {
    case MAX_SCHEDULE_TIMEOUT:
        /*
         * These two special cases are useful to be comfortable
         * in the caller. Nothing more. We could take
         * MAX_SCHEDULE_TIMEOUT from one of the negative value
         * but I' d like to return a valid offset (>=0) to allow
         * the caller to do everything it want with the retval.
         */
        schedule();
        goto out;
    default:
        /*
         * Another bit of PARANOID. Note that the retval will be
         * 0 since no piece of kernel is supposed to do a check
         * for a negative retval of schedule_timeout() (since it
         * should never happens anyway). You just have the printk()
         * that will tell you if something is gone wrong and where.
         */
        if (timeout < 0) {
            printk(KERN_ERR "schedule_timeout: wrong timeout "
                "value %lx
", timeout);
            dump_stack();
            current->state = TASK_RUNNING;
            goto out;
        }
    }

    expire = timeout + jiffies;

    setup_timer_on_stack(&timer, process_timeout, (unsigned long)current);
    __mod_timer(&timer, expire, false, TIMER_NOT_PINNED);
    schedule();
    del_singleshot_timer_sync(&timer);

    /* Remove the timer from the object tracker */
    destroy_timer_on_stack(&timer);

    timeout = expire - jiffies;

 out:
    return timeout < 0 ? 0 : timeout;
}
signed long __sched schedule_timeout_interruptible(signed long timeout)
{
    __set_current_state(TASK_INTERRUPTIBLE);
    return schedule_timeout(timeout);
}
原文地址:https://www.cnblogs.com/zhangxuechao/p/11709803.html