内核定时器软件上的定时器最终是由硬件时钟来实现的。简单的说,内核会在时钟中断发生后,检测每次向内核注册的时序,设备是否过期,如果过期,则回调相应的注册函数,作为中断的下半部分执行。事实上,时钟中断处理程序会触发TIMER_SOFTIRQ软中断,运行所有在当前处理器上到期的定时器。如果设备驱动需要获取时间信息,需要定时服务,可以使用内核定时器。jiffies要说内核定时器,首先得说说内核中关于时间的一个重要概念:jiffies变量,作为内核时钟的基础,jiffies每隔固定的时间加1,称为加一打。固定间隔是通过定时器中断来实现的。每秒产生多少定时器中断由中定义的HZ宏决定。这样就可以通过jiffies获取一段时间,比如jiffies/HZSecondssincesystemboot。接下来的两秒是(jiffies/HZ+2),内核用jiffies来计时,秒转换成jiffies:seconds*HZ,所以以jiffy为单位,以当前时间为基准来计时2seconds:(jiffies/HZ+2)*HZ=jiffies+2*HZ如果想获取当前时间,可以使用do_gettimeofday(),填充一个structtimeval结构,精度接近微秒。//kernel/time/timekeeping.c/***do_gettimeofday-Returnsthetimeofdayinatimeval*@tv:pointertothetimevaltobeset**NOTE:Usersshouldbeconvertedtousinggetnstimeofday()*/voiddo_gettimeofday(structtimeval*tv)驱动程序经常需要延迟特定代码的执行一段时间。根据延迟的长短,内核开发中使用了长延迟和短延迟两个概念。长延时的定义是:延时时间>多个jiffies,查询jiffies的方法可以实现长延时:time_before(jiffies,new_jiffies);time_after(new_jiffiesmjiffies);**短延时的定义是:延时事件close或者比jiffy短,可以调用udelay();mdelay()实现短暂的延迟;这两个函数都是忙等待函数,消耗大量CPU时间。前者使用软件循环来延迟指定的微秒数,后者使用前者的嵌套实现毫秒级的延迟。一个定时器驱动程序可以注册一个内核定时器来指定一个函数在未来的某个时间执行。定时器在注册到内核时开始计时,注册的函数会在到达指定时间后执行。即超时值是一个jiffies值。当jiffies值大于timer->expires时,timer->function会被执行。API如下//设置定时器structtimer_listmy_timer;//初始化定时器voidinit_timer(structtimer_list*timer);mytimer.function=my_function;mytimer.expires=jiffies+HZ;//添加定时器voidadd_timer(structtimer_list*timer);//删除计时器intdel_tiemr(structtimer_list*timer);instancestaticstructtimer_listtm;structtimevaloldtv;voidcallback(unsignedlongarg){structtimevaltv;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);}staticint__initdemo_init(void){init_timer(&tm);do_gettimeofday(&oldtv);tm.function=callback;tm.data=(unsignedlong)"helloworld";tm.expires=jiffies+1*HZ;add_timer(&tm);return0;}延时工作除了使用内核定时器完成定时延时工作外,linux内核也提供了一套封装的“快捷方式”-delayed_work,类似于内核定时器,其本质也是使用工作队列和定时器实现的,//include/linux/workqueue.hstructwork_struct{atomic_long_tdata;structlist_headentry;work_func_tfunc;#ifdefCONFIG_LOCKDEPstructlockdep_maplockdep_map;#endif};structdelayed_work{114structwork_structwork;structtimer_listtimer;/*targetworkqueueandCPU->timerusestoqueue->work*/structworkqueue_struct*wq;intcpu;};--103-->需要延时的函数,typedefvoid(work_func_t)(structwork_structwork);至此,我们可以使用一个delayed_work对象和对应的调度API来实现指定任务的延迟执行//registeradelayedexecution591staticinlineboolschedule_delayed_work(structdelayed_work*dwork,unsignedlongdelay)//registeradelayedexecution2975boolcancel_delayed_work(structdelayed_work*dwork)andkerneltimer同理,延时执行只会在超时时执行一次。如果要实现循环延迟,只需要注册一个延迟执行函数schedule_delayed_work(&work,msecs_to_jiffies(poll_interval));