【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下。

[cpp] view plain copy
  1. config TICK_ONESHOT  
  2.     bool  
  3.   
  4. config NO_HZ  
  5.     bool "Tickless System (Dynamic Ticks)"  
  6.     depends on !ARCH_USES_GETTIMEOFFSET && GENERIC_CLOCKEVENTS  
  7.     select TICK_ONESHOT  
  8.     help  
  9.       This option enables a tickless system: timer interrupts will  
  10.       only trigger on an as-needed basis both when the system is  
  11.       busy and when the system is idle.  
  12.   
  13. config HIGH_RES_TIMERS  
  14.     bool "High Resolution Timer Support"  
  15.     depends on !ARCH_USES_GETTIMEOFFSET && GENERIC_CLOCKEVENTS  
  16.     select TICK_ONESHOT  
  17.     help  
  18.       This option enables high resolution timer support. If your  
  19.       hardware is not capable then this option only increases  
  20.       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子系统吧,首先对于网上的一些介绍,看下整个框架图:

【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/下

[cpp] view plain copy
  1. obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o timecompare.o  
  2. obj-y += timeconv.o posix-clock.o #alarmtimer.o  
  3.   
  4. obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD)     += clockevents.o  
  5. obj-$(CONFIG_GENERIC_CLOCKEVENTS)       += tick-common.o  
  6. obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += tick-broadcast.o  
  7. obj-$(CONFIG_TICK_ONESHOT)          += tick-oneshot.o  
  8. obj-$(CONFIG_TICK_ONESHOT)          += tick-sched.o  
  9. obj-$(CONFIG_TIMER_STATS)           += timer_stats.o  

    有一些代码不在time目录下,而是直接在kernel目录下,hrtimer.c、posix-timers.c等。

    网上关于代码的介绍很详细,这里就直接贴个图了:

【Linux内核】timer子系统

    写得很好很详细,不过自己还是得记录下。了解了timer子系统的框架,跟模块的简单介绍,源码的一些介绍,知识点貌似有点多啊。那么接下去还是先看看timer的系统启动流程,然后再分析各个模块的功能吧。

    系统起来后会调用start_kernel,然后接着调用调用tick_init,init_timers,hrtimer_init,timekeeping_init,time_init,具体如下图所示。

    【Linux内核】timer子系统

    其中init_timers相当于time wheel低精度timer,hrtime_init相当于hrtimer高精度timer,以及timekeeping_init就是gtod了和而time_init就是我们所要适配的和平台相关的timer的移植了。

    既然已经了解了基本的功能和代码,也知道了系统启动流程,那么接下去就一个一个来学习了