一、概述
在計算機系統,CPU是以一個節拍一個節拍運行的(cpu cycle),這就是CPU的頻率(HZ)。類似的,操作系統需要提供超時功能,顯示時間(如PC機右下角的時鐘),統計(CPU占有率計算)等功能,也需要有一個節拍(操作系統的頻率HZ)觸發操作系統做上述相關功能處理,內核在內部使用了一個全局變量記錄了系統從啟動後經過了多少個節拍,這就是tick值,通常由另外一個更形象的說法“嘀嗒”,在linux下用jiffies表示(該值為long型,為了防止32位系統下該值翻轉,同時用了一個64位數jiffies_64來記錄)。
那麼誰來觸發這個節拍呢,通常由時鐘芯片來實現。由於內核需要運行在不同的硬件設備上,因此,內核抽象出了通用的時鐘事件處理框架。其典型流程如下:
硬件<-->相關驅動代碼<-->通用時鐘處理代碼<-->高分辨率定時器處理框架<-->高/低分辨率定時器處理<-->超時處理
上述流程從左到右為時鐘觸發處理流程,從右到左是設置配置流程。高分辨率定時器提供了比低分辨率定時器高很多的精度(通常前者為納秒級,而後者為毫秒級),高精度定時器需要在編譯內核時指定CONFIG_HIGH_RES_TIMERS才支持。
二、實現文件及入口函數說明:
clockchips.h/clockevents.c: 定義時鐘事件設備struct clock_event_device,該結構抽象了時鐘事件的通用處理代碼,從結構體定義可以看出,主要為設置時鐘芯片的觸發模式(周期觸發還是單觸發),設置超時事件,已經超時事件的處理函數(時鐘中斷處理)等。
clocksource.h/clocksource.c: 定義了時鐘源struct clocksource,該結構抽象了時鐘源的處理,主要是使能時鐘源,去使能時鐘源,讀取時鐘源的cycle值,暫停和恢復時鐘源等操作。
這4個文件為通用時鐘處理代碼,在它們的下一層,就是時鐘芯片的驅動代碼。如IA-32/AMD CPU的PIT(programmable interrupt timer,由時鐘芯片8253實現,相關實現可參看I8253.h/I8253.c
tick.h: tick時鐘頭文件,定義了兩個結構:
struct tick_device:經典tick時鐘設備定義,低精度定時器。
struct tick_sched: 高精度定時器模擬tick時鐘,或動態時鐘(tickless)使用。
tick-common.c:經典tick時鐘的實現。tick_handle_periodic為入口函數
tick_handle_periodic->do_timer(全局時鐘)->jiffies_64更新
update_wall_time
calc_global_load
->update_process_times->run_local_timers->hrtimer_run_queues/TIMER_SOFTIRQ->__run_timers(低分辨率定時器)
rcu_check_callbacks
scheduler_tick
run_posix_cpu_timers
tick-internal.h:一些通用的支撐代碼
tick-broadcast.c:廣播模式的時鐘處理。在一些系統,為了省電進入節能模式後,可能會停止某些時鐘事件,這時候可以通過其他的設備廣播一個時鐘事件。
tick-oneshot.c:高精度定時器單觸發方式的一些通用處理代碼
tick-sched.c: 切換到動態時鐘及動態時鐘的實現
timer.c/h:低精度定時器的實現, 定時器節點管理上采用了級聯方式。
hrtimer.c/h:高精度定時器的實現。hrtimer_interrupt為入口函數
hrtimer_interrupt->__run_hrtimer
與hrtimer_run_queues的區別?是通用框架的一部分,在每個硬件中斷中觸發。called by run_local_timers,沒有高精度時鐘系統才會運行。
timerqueue.c/h:高精度定時器節點隊列,封裝了rbtree的操作。
ktime_t為高精度定時器的定時時間
tick_setup_sched_timer:在切換到高精度模式時,啟動一個高精度定時器模擬周期tick時鐘。
struct hrtimer_sleeper :任務定時操作是如此普遍,內核實現了此類公用接口,以方便使用。