655
技術社區[雲棲]
時間子係統9_timekeeper初始化
//Timekeeping
// Timekeeping子係統負責更新xtime, 調整誤差, 及提供get/settimeofday接口.
//Times in Kernel
//kernel的time基本類型:
// 1) system time
// A monotonically increasing value that represents the amount of time the system has been running.
// 單調增長的係統運行時間, 可以通過time source, xtime及wall_to_monotonic計算出來.
// 2) wall time
// A value representing the the human time of day, as seen on a wrist-watch. Realtime時間: xtime.
// 3) time source
// A representation of a free running counter running at a known frequency, usually in hardware, e.g GPT.
// 可以通過clocksource->read()得到counter值
// 4) tick
// A periodic interrupt generated by a hardware-timer, typically with a fixed interval defined by HZ: jiffies
// 這些time之間互相關聯, 互相可以轉換:
// system_time = xtime + cyc2ns(clock->read() - clock->cycle_last) + wall_to_monotonic;
// real_time = xtime + cyc2ns(clock->read() - clock->cycle_last)
// 也就是說real time是從1970年開始到現在的nanosecond, 而system time是係統啟動到現在的nanosecond.
// 這兩個是最重要的時間, 由此hrtimer可以基於這兩個time來設置過期時間. 所以引入兩個clock base.
// 參考:https://blog.csdn.net/hongjiujing/article/details/7070746
// 全局timekeeper
1.1 struct timekeeper timekeeper;
// timekeeper框架初始化
// 初始化clocksource
// 調用路徑:start_kernel->timekeeping_init
// 函數任務:
// 1.使用默認時間源初始化全局timekeeper
// 2.初始化牆上時間xtime
// 3.初始化wall_to_monotonic,使其與xtime相加得到係統啟動以來的單調時間
// 注:
// Network Time Protocol(NTP)是用來使計算機時間同步化的一種協議,
// 它可以使計算機對其服務器或時鍾源(如石英鍾,GPS等等)做同步化,
// 它可以提供高精準度的時間校正(LAN上與標準間差小於1毫秒,WAN上幾十毫秒).
1.2 static void __init timekeeping_init(void)
{
struct clocksource *clock;
unsigned long flags;
struct timespec now, boot;
//通過cmos獲取當前時間
read_persistent_clock(&now);
//係統啟動時的時間
read_boot_clock(&boot);
write_seqlock_irqsave(&xtime_lock, flags);
//ntp初始化
ntp_init();
//x86架構下默認的時鍾源,jiffies_clocksource
clock = clocksource_default_clock();
//使能時鍾源
if (clock->enable)
clock->enable(clock);
//使用clocksource初始化全局timekeeper
timekeeper_setup_internals(clock);
//初始化牆上時間
xtime.tv_sec = now.tv_sec;
xtime.tv_nsec = now.tv_nsec;
raw_time.tv_sec = 0;
raw_time.tv_nsec = 0;
//如果體係結構沒有提供read_boot_clock,設置啟動時間為當前時間
if (boot.tv_sec == 0 && boot.tv_nsec == 0) {
boot.tv_sec = xtime.tv_sec;
boot.tv_nsec = xtime.tv_nsec;
}
//通過將wall_to_monotonic加到xtime,獲取係統啟動以來的單調時間
set_normalized_timespec(&wall_to_monotonic,
-boot.tv_sec, -boot.tv_nsec);
total_sleep_time.tv_sec = 0;
total_sleep_time.tv_nsec = 0;
write_sequnlock_irqrestore(&xtime_lock, flags);
}
// timekeeper初始化
// 函數任務:
// 1.綁定timekeeper到clocksource
// 2.換算NTP間隔為clocksource的cycle
// 調用路徑:timekeeping_init->timekeeper_setup_internals
// 注:
// 1.timekeeper.cycle_interval,一個NTP間隔對應的時鍾cycle
// 2.timekeeper.xtime_interval, 一個NTP間隔對應的時鍾cycle*mult
// 3.timekeeper.raw_interval, 一個NTP間隔(近似值)
1.3 static void timekeeper_setup_internals(struct clocksource *clock)
{
cycle_t interval;
u64 tmp;
//timekeeper使用提供的時鍾源
timekeeper.clock = clock;
clock->cycle_last = clock->read(clock);
//NTP_INTERVAL_LENGTH轉換為clocksource的cycle
tmp = NTP_INTERVAL_LENGTH;
tmp <<= clock->shift;
tmp += clock->mult/2;
do_div(tmp, clock->mult);
if (tmp == 0)
tmp = 1;
//一個NTP間隔對應的時鍾cycle
interval = (cycle_t) tmp;
timekeeper.cycle_interval = interval;
//一個NTP間隔對應的xtime間隔
timekeeper.xtime_interval = (u64) interval * clock->mult;
//
timekeeper.raw_interval =
((u64) interval * clock->mult) >> clock->shift;
timekeeper.xtime_nsec = 0;
//使用時鍾源的shift
timekeeper.shift = clock->shift;
//累積的時間相對於NTP的誤差
timekeeper.ntp_error = 0;
timekeeper.ntp_error_shift = NTP_SCALE_SHIFT - clock->shift;
timekeeper.mult = clock->mult;
}
最後更新:2017-04-03 14:54:25