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

 内核     定时器    

软件上的定时器最终要依靠硬件     时钟   来实现,简单的说,内核会在时钟中断发生后检测各个注册到内核的定时器是否到期,如果到期,就回调相应的注册函数,将其作为中断底半部来执行。实际上,时钟中断处理程序会触发     TI   MER_SOF  TI RQ软中断,运行当前处理器上到期的所有定时器。
设备驱动程序如要获得时间信息以及需要定时服务,都可以使用内核定时器。

 Linux驱动技术关键之一:内核定时器与延迟工作_设计制作_电源/新能源

jiffies

要说内核定时器,首先就得说说内核中关于时间的一个重要的概念:jiffies变量,作为内核时钟的基础,jiffies每隔一个固定的时间就会增加1,称为增加一个节拍,这个固定间隔由定时器中断来实现,每秒中产生多少个定时器中断,由在中定义的HZ宏来确定,如此,可以通过jiffies获取一段时间,比如jiffies/HZ表示自系统启动的秒数。下两秒就是(jiffies/HZ+2),内核中用jiffies来计时,秒转换成的jiffies:seconds*HZ,所以以jiffiy为单位,以当前时刻为基准计时2秒:(jiffies/HZ+2)*HZ=jiffies+2*HZ如果要获取当前时间,可以使用do_get  TI meofday(),该函数填充一个struct  TI meval结构,有着接近微妙的分辨率。

//kernel/  TI me/timekee     pi   ng.c 473 /** 474 * do_gettimeofday - Returns the time of day in a timeval 475 * @tv: poin     te   r to the timeval to be set 476 * 477 * NOTE: Use     rs   should be converted to using getnstimeofday() 478 */ 479 void do_gettimeofday(struct timeval *tv)

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

time_before(jiffies, new_jiffies);time_after(new_jiffiesmjiffies);

**短延时的定义为:延迟事件接近或短于一个jiffy,实现短延时可以调用

udelay();mdelay();

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

定时器

驱动可以注册一个内核定时器,来指定一个函数在未来某个时间来执行。定时器从注册到内核开始计时,达到指定的时间后会执行注册的函数。即超时值是一个jiffies值,当jiffies值大于timer->expires时,timer->function就会被执行。API如下

//定一个定时器struct timer_list my_timer;//初始化定时器void init_timer(struct timer_list *timer);mytimer.function = my_function;mytimer.expires = jiffies +HZ;//增加定时器void add_timer(struct timer_list *timer);//删除定时器int del_tiemr(struct timer_list *timer);

实例

static struct timer_list tm;struct timeval oldtv;void callback(unsigned long arg){ struct timeval tv; char *strp = (char*)arg; do_gettimeofday(&tv); printk("%s: %ld, %ld\n", __func__, tv.tv_sec - oldtv.tv_sec, tv.tv_usec- oldtv.tv_usec); oldtv = tv; tm.expires = jiffies+1*HZ; add_timer(&tm);}static int __init demo_init(void){ init_timer(&tm); do_gettimeofday(&oldtv); tm.function= callback; tm.data = (unsigned long)"hello world"; tm.expires = jiffies+1*HZ; add_timer(&tm); return 0;}

延迟工作

除了使用内核定时器完成定时延迟工作,     Linux   内核还提供了一套封装好的"快捷方式"-delayed_work,和内核定时器类似,其本质也是利用工作队列和定时器实现,

//include/linux/workqueue.h100 struct work_struct { 101 ato     mi   c_long_t data;102 struct list_head entry;103 work_func_t func;104 #ifdef CONFIG_LOCKDEP105 struct lockdep_map lockdep_map;106 #endif107 };113 struct delayed_work { 114 struct work_struct work;115 struct timer_list timer;116 117 /* target workqueue and CPU ->timer uses to queue ->work */118 struct workqueue_struct *wq;119 int cpu;120 };

struct work_struct
--103-->需要延迟执行的函数, typedef void (work_func_t)(struct work_struct work);

至此,我们可以使用一个delayed_work对象以及相应的调度API实现对指定任务的延时执行

//注册一个延迟执行591 static inline bool schedule_delayed_work(struct delayed_work *dwork,unsigned long delay)//注销一个延迟执行2975 bool     can   cel_delayed_work(struct delayed_work *dwork)

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

schedule_delayed_work(&work,msecs_to_jiffies(poll_interval));

51
105
0
75

相关资讯

  1. 1、社交网络​1%的生活,99%的泡沫2116
  2. 2、谁在裸泳?2020年,DTC行业迎来直面真相时刻3709
  3. 3、微信公众平台开放素材管理接口,可在第三方开发平台上实现所有操作3329
  4. 4、如何通过智能化产能管理机制,解决口罩短缺问题?2704
  5. 5、抖音正在“惩罚”想占流量便宜的人122
  6. 6、今日头条,是门户新敌人4183
  7. 7、简历中的哪些细节会影响第一印象?2697
  8. 8、窥视浏览器的产品形态变化2635
  9. 9、“知乎书店”上线了,我们应如何看待“内容产品”变现?1594
  10. 10、七巨头如何抵御抖音?803
全部评论(0)
我也有话说
0
收藏
点赞
顶部