Linux核心時間管理子系統——時鐘源
阿新 • • 發佈:2019-01-15
struct clocksource { /* * Hotpath data, fits in a single cache line when the * clocksource itself is cacheline aligned. */ cycle_t (*read)(struct clocksource *cs); cycle_t cycle_last; cycle_t mask; u32 mult; u32 shift; u64 max_idle_ns; u32 maxadj; #ifdef CONFIG_ARCH_CLOCKSOURCE_DATA struct arch_clocksource_data archdata; #endif const char *name; struct list_head list; int rating; int (*enable)(struct clocksource *cs); void (*disable)(struct clocksource *cs); unsigned long flags; void (*suspend)(struct clocksource *cs); void (*resume)(struct clocksource *cs); /* private: */ #ifdef CONFIG_CLOCKSOURCE_WATCHDOG /* Watchdog related data, used by the framework */ struct list_head wd_list; cycle_t cs_last; cycle_t wd_last; #endif } ____cacheline_aligned;
read()
返回當前時鐘源的計數值,即cycle數。rating
時鐘源的等級,越高越好。mult和shift
用於將時鐘源的計數值換算為納秒,即(cycle * mult) >> shift 可以得到相應的納秒數。mask
時鐘源的計數值用型別cycle_t表示,該型別其實就是無符號64位數。但是時鐘源實際的計數範圍可能小於64位,mask的作用就是表示真實的計數範圍。對於一個32位的時鐘源硬體,mask等於0xffffffff,即32個bit 1。這種方法的好處是即使時鐘源發生溢位,一樣可以通過簡單的計算得出實際經歷的cycle數。如下所示,假設上次讀時鐘源得到的計數值是cycle_last,這次讀取的計數值是cycle_now,則經歷的cycle數等於: (cycle_now - cycle_last) & mask 對於一個32位的時鐘源,假設cycle_last=0xffffffff,cycle_now=0,即發生了溢位,通過上面的等式依然可以得到經歷了一次cycle。max_idle_ns
時鐘源的註冊
核心提供了多個函式用於註冊新的時鐘源。其中帶_hz或_khz字尾的函式可以根據hz/khz引數自動計算mult和shift,簡化了呼叫者的負擔。註冊函式完成下面的工作: 1. 將新的clock source掛在連結串列clocksource_list上。連結串列上的時鐘源按rating從大到小排序。 2. 根據clock source的flags決定是否需要將新的clock source掛在連結串列watchdog_list上。詳見clock source watchdog一節。 3. 選擇具有最高rating的時鐘源並將其設定為當前時鐘源(curr_clocksource指向當前使用的時鐘源)。使用者可以通過sysfs強制指定某個時鐘源,詳見使用者介面一節。extern int clocksource_register(struct clocksource*); static inline int clocksource_register_hz(struct clocksource *cs, u32 hz) static inline int clocksource_register_khz(struct clocksource *cs, u32 khz)
Clock Source Watchdog
核心選擇rating最高的時鐘源作為watchdog時鐘源監測其他時鐘源的誤差。如果新註冊的時鐘源的flags包含CLOCK_SOURCE_MUST_VERIFY,表示該時鐘源需要經過watchdog的監測。如果兩者之間在0.5s內的誤差大於0.0625秒,則新註冊的時鐘源被認為是unstable的。如果誤差小於該標準,且滿足下面的情況,則新註冊的時鐘源被標記為CLOCK_SOURCE_VALID_FOR_HRES,即高精度時鐘。 1. 新註冊的時鐘源的flags包含CLOCK_SOURCE_IS_CONTINUOUS。 2. watchdog時鐘源的flags包含CLOCK_SOURCE_VALID_FOR_HRES。時鐘源的其他API
下面的API用於suspend和resume所有註冊過的時鐘源。void clocksource_suspend(void)
void clocksource_resume(void)
下面的API用於將時鐘源標記為unstable
void clocksource_mark_unstable(struct clocksource *cs)
核心啟動過程與時鐘源
clocksource_done_booting執行前
核心完成如下工作:1. 各種時鐘源的註冊。 2. 時鐘源watchdog對需要監測的時鐘源進行檢測。 3. 對於不符合標準的時鐘源,在clocksource_watchdog中該時鐘源被mark成unstable。由於此時finished_booting=0,因此不會啟動核心執行緒clocksource_watchdog_kthread。該執行緒的作用將在後面描述。
clocksource_done_booting執行中
在該函式中finished_booting被標記為1。直接執行clocksource_watchdog_kthread,該函式將所有unstable的時鐘源的rating設定為0,並重新呼叫clocksource_select選擇當前使用的時鐘源。
clocksource_done_booting執行後
clocksource_done_booting函式被標記為fs_initcall,表示該函式將在subsys_initcall之後,device_initcall執行之前被執行。此時finished_booting已經被標記為1,當任何時鐘源被標記為unstable時,將啟動核心執行緒clocksource_watchdog_kthread,如前所述,函式將重新設定時鐘源的rating並選擇當前的時鐘源。
sysfs介面
當前可用的時鐘源 /sys/devices/system/clocksource/clocksource0/available_clocksource當前所用的時鐘源 /sys/devices/system/clocksource/clocksource0/current_clocksource