Linux内核时钟系统和定时器实现

1. linux内核时钟系统和定时器实现Linux 2.6.16之前,内核只支持低精度时钟,内核定时器的工作方式:

  • 系统启动后,会读取时钟源设备(RTC, HPET,PIT…),初始化当前系统时间;
  • 内核会根据HZ(系统定时器频率,节拍率)参数值,设置时钟事件设备,启动tick(节拍)中断 。HZ表示1秒种产生多少个时钟硬件中断,tick就表示连续两个中断的间隔时间 。在我电脑上,HZ=250,一个tick = 1/HZ, 所以默认一个tick为4ms 。
cat /boot/config-`uname -r` | grep 'CONFIG_HZ='CONFIG_HZ=250
  • 设置时钟事件设备后,时钟事件设备会定时产生一个tick中断,触发时钟中断处理函数,更新系统时钟,并检测timer wheel,进行超时事件的处理 。
在上面工作方式下,Linux 2.6.16 之前,内核软件定时器采用timer wheel多级时间轮的实现机制,维护操作系统的所有定时事件 。timer wheel的触发是基于系统tick周期性中断 。
所以说这之前,linux只能支持ms级别的时钟,随着时钟源硬件设备的精度提高和软件高精度计时的需求,有了高精度时钟的内核设计 。
Linux 2.6.16 ,内核支持了高精度的时钟,内核采用新的定时器hrtimer,其实现逻辑和Linux 2.6.16 之前定时器逻辑区别:
  • hrtimer采用红黑树进行高精度定时器的管理,而不是时间轮;
  • 高精度时钟定时器不在依赖系统的tick中断,而是基于事件触发 。
【Linux内核时钟系统和定时器实现】旧内核的定时器实现依赖于系统定时器硬件定期的tick,基于该tick,内核会扫描timer wheel处理超时事件,会更新jiffies,wall time(墙上时间,现实时间),process的使用时间等等工作 。
新的内核不再会直接支持周期性的tick,新内核定时器框架采用了基于事件触发,而不是以前的周期性触发 。新内核实现了hrtimer(high resolution timer),hrtimer的设计目的,就是为了解决time wheel的缺点:
  • 低精度;timer wheel只能支持ms级别的精度,hrtimer可以支持ns级别;
  • Timer wheel与内核其他模块的高耦合性;
新内核的hrtimer的触发和设置不像之前在定期的tick中断中进行,而是动态调整的,即基于事件触发,hrtimer的工作原理:通过将高精度时钟硬件的下次中断触发时间设置为红黑树中最早到期的 Timer 的时间,时钟到期后从红黑树中得到下一个 Timer 的到期时间,并设置硬件,如此循环反复 。
在高精度时钟模式下,操作系统内核仍然需要周期性的tick中断,以便刷新内核的一些任务 。前面可以知道,hrtimer是基于事件的,不会周期性出发tick中断,所以为了实现周期性的tick中断(dynamic tick):系统创建了一个模拟 tick 时钟的特殊 hrtimer,将其超时时间设置为一个tick时长,在超时回来后,完成对应的工作,然后再次设置下一个tick的超时时间,以此达到周期性tick中断的需求 。
引入了dynamic tick,是为了能够在使用高精度时钟的同时节约能源,,这样会产生tickless 情况下,会跳过一些 tick 。这里只是简单介绍,有兴趣可以读kernel源码 。
Linux内核时钟系统和定时器实现

文章插图
 
上图1是Linux 2.6.16以来内核定时器实现的结构,
新内核对相关的时间硬件设备进行了统一的封装,定义了主要有下面两个结构:
  • 时钟源设备(closk source device):抽象那些能够提供计时功能的系统硬件,比如 RTC(Real Time Clock)、TSC(Time Stamp Counter),HPET,ACPI PM-Timer,PIT等 。不同时钟源提供的精度不一样,现在pc大都是支持高精度模式(high-resolution mode)也支持低精度模式(low-resolution mode) 。
  • 时钟事件设备(clock event device):系统中可以触发 one-shot(单次)或者周期性中断的设备都可以作为时钟事件设备 。
当前内核同时存在新旧timer wheel 和 hrtimer两套timer的实现,内核启动后会进行从低精度模式到高精度时钟模式的切换,hrtimer模拟的tick中断将驱动传统的低精度定时器系统(基于时间轮)和内核进程调度 。
内核定时器系统增加了hrtimer之后,对于用户层开放的定时器相关接口基本都是通过hrtimer进行实现的,从内核源码可以看到:
*These timers are currently used for:*- itimers*- POSIX timers*- nanosleep*- precise in-kernel timing* 
2. 用户层定时器API接口上面介绍完linux内核定时器的实现后,下面简单说一下,基于内核定时器实现的,对用户层开放的定时器API:间隔定时器itimer和POSIX定时器 。


推荐阅读