時間子係統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