Linux驱动技术关键之一:内核定时器与延迟工作

来源:
导读 大家好,我是本期栏目编辑小友,现在为大家讲解Linux驱动技术关键之一:内核定时器与延迟工作问题。 内核定时

大家好,我是本期栏目编辑小友,现在为大家讲解Linux驱动技术关键之一:内核定时器与延迟工作问题。

内核定时器

软件上的定时器最终取决于硬件时钟。简单地说,内核将检测在内核中注册的每个定时器是否在时钟中断发生后到期。如果过期,它将回调相应的注册函数,并作为中断的下半部分执行。实际上,时钟中断处理程序触发TIMER_SOFTIRQ软中断来运行当前处理器上所有到期的定时器。

如果设备驱动想获取时间信息,需要定时服务,可以使用内核定时器。

要谈论内核计时器,我们必须首先谈论一个关于内核中时间的重要概念:jiffies变量。作为内核时钟的基础,jiffies每隔一个固定时间就会增加1,这叫做加一拍。这个固定间隔是通过定时器中断来实现的。每秒产生多少定时器中断由中定义的HZ宏决定,因此可以通过jiffies获得一段时间。例如,jiffies/HZ表示由系统启动。接下来的两秒是(jiffies/HZ 2),在内核中由jiffies测量,第二秒转换为jiffies 3360s * HZ,所以以jiff ies为单位,以当前时间为基准测量2秒:(jiff ies/HZ 2)* HZ=jiff ies 2 * HZ。如果想要获取当前时间,可以使用do_getTImeofday()。

//kernel/TIme/timeing . c 473/* * 474 * do _ gettimeofday-返回timeval中的时间475 * @tv:指向要设置的timeval的指针476 * 477 * NOTE:用户应该使用getnstimeofday()478 */479 void do _ gettimeofday(struct timeval * TV)转换为

为了给硬件足够的时间来完成一些任务,驱动程序经常需要将特定代码的执行延迟一段时间。根据延迟的长度,内核开发中使用了长延迟和短延迟两个概念。长时延的定义是:时延时间为多个jiffies,查询jiffies即可实现长时延:

time_before(jiffies,new _ jiffies);time _ after(new _ jiffiesmjiffies);

* *短延迟的定义是:延迟事件接近或短于一瞬间,可以称为短延迟。

ude lay();mde lay();

这两个函数都是繁忙的等待函数,消耗大量的CPU时间。前者使用软件循环来延迟指定数量的细微数字,而后者使用前者的嵌套来实现毫秒级延迟。

计时器

驱动程序可以注册一个内核定时器来指定将来某个时候要执行的功能。从注册的时候到内核的时候,注册的函数会在达到指定的时间后执行。也就是说,超时值是一个jiffies值,当jiffies值大于timer-expires时,将执行timer-function。API如下。

//设置定时器结构timer _ list my _ timer//初始化定时器void init _ timer(struct timer _ list * timer);mytimer.function=my _ functionmytimer.expires=jiffies HZ//添加timer void add _ timer(struct timer _ list * timer);//删除timer int del _ tiemr(structtimer _ list * timer);

例子

静态结构定时器列表TM;struct timeval oldtvvoid回调(无符号长arg){ struct time val TV;char * strp=(char *)arg;do _ gettimeofday(TV);printk('%s: %ld,%ld\n ',__func__,tv.tv_sec - oldtv.tv_sec,TV . TV _ usec-old TV . TV _ usec);oldtv=电视;tm.expires=jiffies 1 * HZadd _ timer(TM);} static int _ _ init demo _ init(void){ init _ timer(TM);do _ gettimeofday(oldtv);tm.function=回调;tm.data=(无符号long)' hello world ';tm.expires=jiffies 1 * HZadd _ timer(TM);返回0;}

延迟工作

Linux内核除了使用内核定时器完成定时延时工作外,还提供了一套打包的‘快捷键’——delay _ work,类似于内核定时器,其本质是利用工作队列和定时器来实现的。

//include/Linux/workqueue . h100 struct work _ struct { 101 atomic _ long _ t数据;102 struct list_head条目;103 work _ func _ t func104 # ifdef CONFIG _ LOCKDEP 105 struct LOCKDEP _ map LOCKDEP _ map;106 # endif 107 };113 struct delivered _ work { 114 struct work _ struct work;115 struct timer_list定时器;116 117 /*目标工作队列和CPU -timer用于对工作进行排队*/118 struct workqueue _ struct * wq;119 int cpu120 };

结构工作结构

-103-要延迟的函数,typedef void(work _ func _ t)(struct work _ struct work);

此时,我们可以使用delayed _ work对象和相应的调度API来实现指定任务的延迟执行。

//注册591静态内联bool schedule _ delayed _ work的延迟执行(struct delived _ work * dwork,无符号长延迟)//取消2975 bool cancel _ delived _ work(struct delived _ work * dwork)的延迟执行。

和内核定时器一样,延迟执行在超时时只会执行一次。如果要实现循环延迟,只需要在注册的函数中再注册一个延迟执行的函数。

schedule _ delivered _ work(work,ms ECS _ to _ jiffies(poll _ interval));

标签:

版权声明:转载此文是出于传递更多信息之目的。若有来源标注错误或侵犯了您的合法权益,请作者持权属证明与本网联系,我们将及时更正、删除,谢谢您的支持与理解。