【Linux内核】timer子系统
一般来说要让整个linux系统跑起来,那么一个必须的就是linux的时钟,也就是时间子系统了,这里正好工作需要,那么就研究下linux下的时间子系统了。
linux内核必须完成两种主要的定时测量。一个是计时,保存当前的时间和日期,以便能通过time(),gettimeofday()等系统调用,返回给用户程序,另一个是定时,这种机制主要是告诉内核或者应用程序,某一时间间隔已经过去了,触发回调函数,然后做一些事情。
对于硬件主要有实时时钟RTC和CPU本地Timer,其中RTC是cpu外部的其他芯片,或者内部的模块,不过都是需要外部单独提供类似纽扣电池供电。Linux只用RTC来获取时间和日期,关于RTC以后在rtc子系统里面再详细介绍。CPU本地Timer其实就是用的CPU内部的Timer模块,一般是CPU的Timer模块可以计数,当然这个是通过晶振再加上倍频分频等给主芯片的,然后主芯片内部根据跑的不同主频来实现计数,这个计数只能递增或者递减,然后溢出后会有中断,一般是可以设置这个溢出的值的。嵌入式系统要跑起来,都需要时钟,具体的移植代码主要在arch下,根据不同的体系做不通的移植。
linux具有Dynamic Ticks和High Resolution Timer, 详细可以参考kernel/time/Kconfig下。
- config TICK_ONESHOT
- bool
- config NO_HZ
- bool "Tickless System (Dynamic Ticks)"
- depends on !ARCH_USES_GETTIMEOFFSET && GENERIC_CLOCKEVENTS
- select TICK_ONESHOT
- help
- This option enables a tickless system: timer interrupts will
- only trigger on an as-needed basis both when the system is
- busy and when the system is idle.
- config HIGH_RES_TIMERS
- bool "High Resolution Timer Support"
- depends on !ARCH_USES_GETTIMEOFFSET && GENERIC_CLOCKEVENTS
- select TICK_ONESHOT
- help
- This option enables high resolution timer support. If your
- hardware is not capable then this option only increases
- the size of the kernel image.
其中CONFIG_NO_HZ用来控制Dynamic Ticks,CONFIG_HIGH_REST_TIMERS控制High Resolution Timer。
若是没有选择上述的高精度timer和动态tick的话,那么就用linux系统的低精度timer了
因为现在的linux虽然还是可以使用低精度的timer,但是趋势是高精度hrtimer,所以上一篇试着翻译一下hrtimer的一些介绍,翻译的不是很好,看来英语还得好好学习啊,下面还是好好学习下linux的timer子系统吧,首先对于网上的一些介绍,看下整个框架图:
从上图可以得知,首先最底层是cpu的本地timer模块了,什么都得依赖于这个最底层硬件。然后是时钟源clock source模块,时钟事件clock event模块了,这两个是一个抽象,能提供时钟的都是时钟源,能触发one-shot或者周期性中断的设备就是时钟事件设备了。hrtimer就是高精度timer了。timekeeping/GTOD是内核时间管理的一个核心部分,没有timerkeeping如其名,就是维持心跳,GTOD主要用来实现设置系统时间,gettimeofday或者修改系统时间settimeofday等。timer wheel是老的架构下的timer子系统,低精度。periodic ticks就是周期性地tick,所以dynamic就是动态的tick了,tick其实翻译为中文就是时钟的滴答声,所以这个也很好理解了,之后再细细讲解这些模块吧。
既然简单了解了整个timer的框架,那么接下去,我们来看看内核代码中关于timer子系统的源码路径了。
在linux/kernel/time/下
- obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o timecompare.o
- obj-y += timeconv.o posix-clock.o #alarmtimer.o
- obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD) += clockevents.o
- obj-$(CONFIG_GENERIC_CLOCKEVENTS) += tick-common.o
- obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += tick-broadcast.o
- obj-$(CONFIG_TICK_ONESHOT) += tick-oneshot.o
- obj-$(CONFIG_TICK_ONESHOT) += tick-sched.o
- obj-$(CONFIG_TIMER_STATS) += timer_stats.o
有一些代码不在time目录下,而是直接在kernel目录下,hrtimer.c、posix-timers.c等。
网上关于代码的介绍很详细,这里就直接贴个图了:
写得很好很详细,不过自己还是得记录下。了解了timer子系统的框架,跟模块的简单介绍,源码的一些介绍,知识点貌似有点多啊。那么接下去还是先看看timer的系统启动流程,然后再分析各个模块的功能吧。
系统起来后会调用start_kernel,然后接着调用调用tick_init,init_timers,hrtimer_init,timekeeping_init,time_init,具体如下图所示。
其中init_timers相当于time wheel低精度timer,hrtime_init相当于hrtimer高精度timer,以及timekeeping_init就是gtod了和而time_init就是我们所要适配的和平台相关的timer的移植了。
既然已经了解了基本的功能和代码,也知道了系统启动流程,那么接下去就一个一个来学习了