linux timer机制
linux timer机制
一、clocksource与clockevent
Linux 2.6.16之前的系统,总是被动的接受时钟中断,然后运行中断处理程序最终可能导致调度的发生,如果实在没有任务可以运行,那么就执行idle,这也许也算一种创意,可是时钟中断还是会周期性的打破idle,然后查询有没有需要做的事情,如果没有继续idle这种方式没有什么问题,可是我们总是希望系统可以主动的做些事情,比如不是被动的接受中断而是主动的设置什么时候中断,因此必须将系统时钟发生中断这件事进行向上抽象,于是相应的clocksource和 clock_event_device,这两个结构体就是时钟以及时钟行为的抽象Clocksource好比就是一个钟表,我们需要一个钟表就是需要读出它的指针的值从而知道现在几点,就是这些,因此钟表都会有显示盘用于读数,至于钟表怎么运作,那就是钟表内部的机械原理了,记住钟表就是用来读数的另外我们为了害怕误事而需要闹铃,需要的是闹铃在一个时间段之后把我们唤醒,这是个事情,而这个事情不一定非要有钟表clock_event_device。钟表和闹铃其实是两个东西,钟表为你展示某些事情,而闹铃需要你的设置,设想一个场景,你手边有一个没有闹铃的钟表,还有一个没有钟表的闹铃,这个闹铃只能设置绝对时间,然后到期振铃,你现在不知道几点,可是你要睡觉并且得到通知必须在四个小时后去参加一个聚会,那么你现在要做什么?你肯定要看看你的钟表,然后设置你的闹钟。 clocksource代表了一个时钟源,一般都会有一个计数器,其中的read回调函数就是负责读出其计数器的值,可是我们为何找不到write或者set之类的回调函数呢?这些回调函数其实不应该在 closksource中,而应该在clock_event_device中clock_event_device的set_next_event致使系统明确的知道下一个中断什么时候到来,这其实没有什么不对,就是因为它是时钟相关的,而时钟中断在老的版本的内核里面的中断间隔也是确定的。新的内核越来越多的将硬件把手抽象给内核,或者将内核把手抽象给用户,这样的内核显得越来越成熟了,内核可以通过硬件把手操控硬件从而影响运行时的策略,而用户可以通过内核把手操控内核从而影响内核的运行时策略。内核对下面的硬件可以控制了,对上面的用户空间也提供了很多不错的操作接口,三层的联系越来越紧密但是却没有增加耦合性,实在是妙! clocksource好比一个钟表,仅仅带read回调函数就是负责读出其计数器的值clock_event_device好比一个不带时间显示的闹铃,其set_next_event函数使系统明确的知道下一个中断什么时候到来调度行为不再依赖HZ的值,底层的时钟硬件不再被在start_kernel中一次性的设置,而被封装了,可以随时设置,新的设置方式 显得更加直观。
从上图可以看出:
1. Timekeeping(可以理解为时间测量或者计时)是内核时间管理的一个核心组成部分。没有 Timekeeping,就无法更新系统时间,维持系统“心跳”。
Timekeeping/GTOD 在使用时钟源设备的基础上也采用类似的封装实现了体系结构的无关性和通用性。hrtimer 则可以通过 timekeeping 提供的接口完成定时器的更新,通过时钟事件设备提供的事件机制,完成对 timer 的管理。
GTOD 是一个通用的框架,用来实现诸如设置系统时间 gettimeofday 或者修改系统时间 settimeofday 等工作。
2. hrtimer最终是通过clocksouce的read回调函数来读取时间的。
3. tick emulation是通过hrtimer来模拟系统tick的
4. 进程调度、jiffies等是基于hrtimer的
5. clock event是通过krtimer设置的。
具体实现:
1. 在内核运行的过程中,采用了两种timer机制(周期模式、高精度模式)
2. 周期模式,跟先前的timer机制没有本质区别
timer采用period模式,直接产生tick,周期性地产生中断,执行timer中断服务程序
硬件timer的中断服务程序里面,直接执行进程时间片计算等关键任务。
3. 高精度模式:
timer采用oneshort模式
内核中会维护一个ktimer列表(其中肯定会建立一个名字叫sched_timer的ktimer节点)
sched_timer起的作用就是模拟周期性的硬件timer
sched_timer的周期,就是系统的tick时间
sched_timer的function函数tick_sched_timer()就是正真的系统的tick处理函数,