33 Linux内核高精度定时器实现延时

33.1 前言

对于Linux驱动开发来说,我们不可避免会使用到延时函数,其中最为常见的延时函数有msleep、usleep(sleep这些是睡眠不占用cpu的),还有mdelay、udelay(delay是CPU忙等待,定时精准但占用cpu),上述延时函数各有优缺点。对于普通情况的延时,也就是多一秒也没大关系的用sleep类延时函数完全没问题,对于有精准延时的用delay类函数一般也没啥问题。如果涉及到硬件时序操作的,我们必定要使用精准的延时函数,如果在对应的地方使用不精准的sleep类延时函数,则会出现下面时序巨大的时序偏差。

                              

然而,如果使用delay函数对于系统性能来说是一个硬伤害,CPU忙等待表示CPU干不了其它事情,只能瞎等。因此,为了解决这种资源浪费问题,必须用另外一个办法解决,那就是使用高精度定时器+条件等待,实现延时函数的功能。

33.2 hrtimer高精度定时器

内核从2.6.16开始加入了高精度定时器架构,高精度定时器架构具有稳定快速的查找、插入、删除定时能力及排序功能,红黑树(rbtree)来组织hrtimer,红黑树已经以库的形式存在于内核中,并被成功地使用在内存管理子系统和文件系统中,随着系统的运行,hrtimer不停地被创建和销毁,新的hrtimer按顺序被插入到红黑树中,树的最左边的节点就是最快到期的定时器,内核用一个hrtimer结构来表示一个高精度定时器。

hrtimer相关函数

void hrtimer_init(struct hrtimer *timer, clockid_t clock_id, enum hrtimer_mode mode)

高精度定时器初始化;timer高精度定时器数据结构;clockid定时的时间类型(如实时时间、开机时间);mode定时器模式

hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode)

高精度定时器启动;timer定时器结构;tim定时时间;mode定时器模式

ktime_t ktime_set(const long secs, const unsigned long nsecs)

定时器时间设定函数;secs秒;nsecs纳秒

hrtimer_forward_now(struct hrtimer *timer, ktime_t interval)

设置超时时间;interval下次超时时间

int hrtimer_cancel(struct hrtimer *timer)

关闭定时器

enum hrtimer_restart (*function)(struct hrtimer *)

定时器超时回调函数

33.3 Linux等待队列

在驱动开发中,有时不可避免需要进行阻塞,如当硬件数据未准备好,此时程序必须阻塞等待数据准备好才能读,否则读取到的数据内容将是无效数据。为了支持应用层这种阻塞与非阻塞的功能,驱动程序就需要提供阻塞(如等待队列,中断)和非阻塞方式(如轮询,异步通知)机制。

Linux内核中,等待队列是常用的阻塞条件出发机制,在数据或任务不能被读取或执行时,将要执行的任务放入等待队列中,当条件到达及唤醒等待队列时再执行即可。

等待队列阻塞分为ASK_UNINTERRUPTIBLE(不可打断)模式睡眠、TASK_INTERRUPTIBLE(可打断)模式睡眠,在不可打断睡眠中,就算发送kill信号程序也不会响应。

等待队列函数

wait_queue_head_t queue;

等待队列结构

init_waitqueue_head(wait_queue_head_t* queue)

初始化等待队列;

wait_event(*queue, int condition)

不可打断等待;condition等待条件

wait_event_interruptible(*queue, int condition)

可打断等待模式;

wait_event_timeout(queue, condition, timeout)

超时条件等待不可中断函数;

wait_event_interruptible_timeout(queue, condition, timeout)

超时条件等待可中断函数

wake_up(wait_queue_head_t *queue);

等待唤醒queue所有进程

wake_up_interruptible(wait_queue_head_t *queue)

等待唤醒queue所有进程

33.4 高精度定时器延时驱动实例

#include <linux/module.h>    
#include <linux/kernel.h>    
#include <linux/hrtimer.h>    
#include <linux/jiffies.h>    
  
struct _stIdelayMngr{  
    int nQueWaiting;                    /*等待队列条件*/  
    wait_queue_head_t iwaitQue;         /*等待队列*/  
    struct hrtimer ihrtimer;            /*高精度定时器*/  
};  
struct _stIdelayMngr stIdelayMngr;  
  
//示例程序  
int hrtimer_main()  
{  
    while(1)  
    {  
        /*启动高精度定时器,结合等待队列延时1ms*/      
        hrtimer_start(&stIdelayMngr.ihrtimer,ktime_set(0,1000*1000),HRTIMER_MODE_REL);  
        wait_event(stIdelayMngr.iwaitQue,stIdelayMngr.nQueWaiting);  
        stIdelayMngr.nQueWaiting = 0;  
  
        /*do something you want*/  
        //.....  
    }  
    return 0;  
}  
  
/* 定时器回调函数 */    
static enum hrtimer_restart hrtimer_hander(struct hrtimer *timer)    
{  
    stIdelayMngr.nQueWaiting = 1;  
    wake_up(&stIdelayMngr.iwaitQue);  
    return HRTIMER_NORESTART;  
}  
  
static int __init hrtimer_demo_init(void)    
{  
    memset(&stIdelayMngr,0,sizoef(stIdelayMngr));  
    /*初始化等待队列*/  
    stIdelayMngr.nQueWaiting = 0;  
    init_waitqueue_head(&stIdelayMngr.iwaitQue);  
  
    /*初始化高精度定时器*/  
    hrtimer_init(&stIdelayMngr.ihrtimer,CLOCK_MONOTONIC,HRTIMER_MODE_REL);    
    stIdelayMngr.ihrtimer.function = hrtimer_hander;    /* 设置回调函数 */    
    hrtimer_start(&stIdelayMngr.ihrtimer,ktime_set(1,0),HRTIMER_MODE_REL);  /* hrtimer启动 */    
  
    return 0;    
}  
  
static void __exit hrtimer_demo_exit(void)    
{  
    /* hrtimer注销 */    
    hrtimer_cancel(&stIdelayMngr.ihrtimer);  
}  
  
module_init(hrtimer_demo_init);    
module_exit(hrtimer_demo_exit);    
MODULE_LICENSE("GPL");  

 

 

猜你喜欢

转载自blog.csdn.net/Chasing_Chasing/article/details/90229183
33