Linux时间子系统中的定时器的引擎:clockeventdevice.doc
《Linux时间子系统中的定时器的引擎:clockeventdevice.doc》由会员分享,可在线阅读,更多相关《Linux时间子系统中的定时器的引擎:clockeventdevice.doc(13页珍藏版)》请在三一办公上搜索。
1、Linux时间子系统中的定时器的引擎:clock_event_device早期的内核版本中,进程的调度基于一个称之为tick的时钟滴答,通常使用时钟中断来定时地产生TIck信号,每次TIck定时中断都会进行进程的统计和调度,并对TIck进行计数,记录在一个jiffies变量中,定时器的设计也是基于jiffies。这时候的内核代码中,几乎所有关于时钟的操作都是在machine级的代码中实现,很多公共的代码要在每个平台上重复实现。随后,随着通用时钟框架的引入,内核需要支持高精度的定时器,为此,通用时间框架为定时器硬件定义了一个标准的接口:clock_event_device,machine级的代码
2、只要按这个标准接口实现相应的硬件控制功能,剩下的与平台无关的特性则统一由通用时间框架层来实现。1. 时钟事件软件架构本系列文章的第一节中,我们曾经讨论了时钟源设备:clocksource,现在又来一个时钟事件设备:clock_event_device,它们有何区别?看名字,好像都是给系统提供时钟的设备,实际上,clocksource不能被编程,没有产生事件的能力,它主要被用于TImekeeper来实现对真实时间进行精确的统计,而clock_event_device则是可编程的,它可以工作在周期触发或单次触发模式,系统可以对它进行编程,以确定下一次事件触发的时间,clock_event_devi
3、ce主要用于实现普通定时器和高精度定时器,同时也用于产生tick事件,供给进程调度子系统使用。时钟事件设备与通用时间框架中的其他模块的关系如下图所示:图1.1 clock_event_device软件架构与clocksource一样,系统中可以存在多个clock_event_device,系统会根据它们的精度和能力,选择合适的clock_event_device对系统提供时钟事件服务。在smp系统中,为了减少处理器间的通信开销,基本上每个cpu都会具备一个属于自己的本地clock_event_device,独立地为该cpu提供时钟事件服务,smp中的每个cpu基于本地的clock_event_
4、device,建立自己的tick_device,普通定时器和高精度定时器。在软件架构上看,clock_event_device被分为了两层,与硬件相关的被放在了machine层,而与硬件无关的通用代码则被集中到了通用时间框架层,这符合内核对软件的设计需求,平台的开发者只需实现平台相关的接口即可,无需关注复杂的上层时间框架。tick_device是基于clock_event_device的进一步封装,用于代替原有的时钟滴答中断,给内核提供tick事件,以完成进程的调度和进程信息统计,负载平衡和时间更新等操作。2. 时钟事件设备相关数据结构2.1 struct clock_event_device
5、时钟事件设备的核心数据结构是clock_event_device结构,它代表着一个时钟硬件设备,该设备就好像是一个具有事件触发能力(通常就是指中断)的clocksource,它不停地计数,当计数值达到预先编程设定的数值那一刻,会引发一个时钟事件中断,继而触发该设备的事件处理回调函数,以完成对时钟事件的处理。clock_event_device结构的定义如下:cppview plaincopystructclock_event_devicevoid(*event_handler)(structclock_event_device*);int(*set_next_event)(unsignedlo
6、ngevt,structclock_event_device*);int(*set_next_ktime)(ktime_texpires,structclock_event_device*);ktime_tnext_event;u64max_delta_ns;u64min_delta_ns;u32mult;u32shift;enumclock_event_modemode;unsignedintfeatures;unsignedlongretries;void(*broadcast)(conststructcpumask*mask);void(*set_mode)(enumclock_even
7、t_modemode,structclock_event_device*);unsignedlongmin_delta_ticks;unsignedlongmax_delta_ticks;constchar*name;intrating;intirq;conststructcpumask*cpumask;structlist_headlist;_cacheline_aligned;event_handler 该字段是一个回调函数指针,通常由通用框架层设置,在时间中断到来时,machine底层的的中断服务程序会调用该回调,框架层利用该回调实现对时钟事件的处理。set_next_event设置下一
8、次时间触发的时间,使用类似于clocksource的cycle计数值(离现在的cycle差值)作为参数。set_next_ktime设置下一次时间触发的时间,直接使用ktime时间作为参数。max_delta_ns 可设置的最大时间差,单位是纳秒。min_delta_ns 可设置的最小时间差,单位是纳秒。mult shift与clocksource中的类似,只不过是用于把纳秒转换为cycle。mode该时钟事件设备的工作模式,两种主要的工作模式分别是:CLOCK_EVT_MODE_PERIODIC 周期触发模式,设置后按给定的周期不停地触发事件;CLOCK_EVT_MODE_ONESHOT 单
9、次触发模式,只在设置好的触发时刻触发一次;set_mode函数指针,用于设置时钟事件设备的工作模式。rating 表示该设备的精度等级。list 系统中注册的时钟事件设备用该字段挂在全局链表变量clockevent_devices上。2.2 全局变量clockevent_devices系统中所有注册的clock_event_device都会挂在该链表下面,它在kernel/time/clockevents.c中定义:cppview plaincopystaticLIST_HEAD(clockevent_devices);2.3 全局变量clockevents_chain通用时间框架初始化时会注
10、册一个通知链(NOTIFIER),当系统中的时钟时间设备的状态发生变化时,利用该通知链通知系统的其它模块。cppview plaincopy/*Notificationforclockevents*/staticRAW_NOTIFIER_HEAD(clockevents_chain);3. clock_event_device的初始化和注册每一个machine,都要定义一个自己的machine_desc结构,该结构定义了该machine的一些最基本的特性,其中需要设定一个sys_timer结构指针,machine级的代码负责定义sys_timer结构,sys_timer的声明很简单:cppvi
11、ew plaincopystructsys_timervoid(*init)(void);void(*suspend)(void);void(*resume)(void);#ifdefCONFIG_ARCH_USES_GETTIMEOFFSETunsignedlong(*offset)(void);#endif;通常,我们至少要定义它的init字段,系统初始化阶段,该init回调会被调用,该init回调函数的主要作用就是完成系统中的clocksource和clock_event_device的硬件初始化工作,以samsung的exynos4为例,在V3.4内核的代码树中,machine_des
12、c的定义如下:cppview plaincopyMACHINE_START(SMDK4412,SMDK4412)/*Maintainer:KukjinKim*/*Maintainer:ChanghwanYoun*/.atag_offset=0x100,.init_irq=exynos4_init_irq,.map_io=smdk4x12_map_io,.handle_irq=gic_handle_irq,.init_machine=smdk4x12_machine_init,.timer=.restart=exynos4_restart,MACHINE_END定义的sys_timer是exyn
13、os4_timer,它的定义和init回调定义如下:cppview plaincopystaticvoid_initexynos4_timer_init(void)if(soc_is_exynos4210()mct_int_type=MCT_INT_SPI;elsemct_int_type=MCT_INT_PPI;exynos4_timer_resources();exynos4_clocksource_init();exynos4_clockevent_init();structsys_timerexynos4_timer=.init=exynos4_timer_init,;exynos4_
14、clockevent_init函数显然是初始化和注册clock_event_device的合适时机,在这里,它注册了一个rating为250的clock_event_device,并把它指定给cpu0:cppview plaincopystaticstructclock_event_devicemct_comp_device=.name=mct-comp,.features=CLOCK_EVT_FEAT_PERIODIC|CLOCK_EVT_FEAT_ONESHOT,.rating=250,.set_next_event=exynos4_comp_set_next_event,.set_mod
15、e=exynos4_comp_set_mode,;.staticvoidexynos4_clockevent_init(void)clockevents_calc_mult_shift(.mct_comp_device.cpumask=cpumask_of(0);clockevents_register_device(setup_irq(EXYNOS4_IRQ_MCT_G0,因为这个阶段其它cpu核尚未开始工作,所以该clock_event_device也只是在启动阶段给系统提供服务,实际上,因为exynos4是一个smp系统,具备2-4个cpu核心,前面说过,smp系统中,通常会使用各个cp
16、u的本地定时器来为每个cpu单独提供时钟事件服务,继续翻阅代码,在系统初始化的后段,kernel_init会被调用,它会调用smp_prepare_cpus,其中会调用percpu_timer_setup函数,在arch/arm/kernel/smp.c中,为每个cpu定义了一个clock_event_device:cppview plaincopy/*Timer(localorbroadcast)support*/staticDEFINE_PER_CPU(structclock_event_device,percpu_clockevent);percpu_timer_setup最终会调用ex
17、ynos4_local_timer_setup函数完成对本地clock_event_device的初始化工作:cppview plaincopystaticint_cpuinitexynos4_local_timer_setup(structclock_event_device*evt).evt-name=mevt-name;evt-cpumask=cpumask_of(cpu);evt-set_next_event=exynos4_tick_set_next_event;evt-set_mode=exynos4_tick_set_mode;evt-features=CLOCK_EVT_FEA
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Linux 时间 子系统 中的 定时器 引擎 clockeventdevice
链接地址:https://www.31ppt.com/p-4842981.html