linux時間子系統(三)

kylinos_123發表於2018-04-17

2.2.3 timekeeper初始化 

void __init timekeeping_init(void)

{

        struct clocksource *clock;

        unsigned long flags;

        struct timespec now, boot;

 

        read_persistent_clock(&now);

        read_boot_clock(&boot);

 

        raw_spin_lock_irqsave(&xtime_lock, flags);

        write_seqcount_begin(&xtime_seq);

 

        ntp_init();

 

        clock = clocksource_default_clock();

        if (clock->enable)

                clock->enable(clock);

        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;

        if (boot.tv_sec == 0 && boot.tv_nsec == 0) {

                boot.tv_sec = xtime.tv_sec;

                boot.tv_nsec = xtime.tv_nsec;

        }

        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_seqcount_end(&xtime_seq);

        raw_spin_unlock_irqrestore(&xtime_lock, flags);

}

   從初始化函式中可以看到,核心首先通過read_persistent_clock函式,從RTC硬體中獲取RTC time。如果不存在RTC硬體,則RTC time被初始化為0。之後,初始化xtime,raw_time,wall_to_monotonic和total_sleep_time。

2.2.4 時間更新 

2.2.4.1 xtime和raw_time更新 

static void timekeeping_forward_now(void)

{

        cycle_t cycle_now, cycle_delta;

        struct clocksource *clock;

        s64 nsec;

 

        clock = timekeeper.clock;

        cycle_now = clock->read(clock);

        cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;

        clock->cycle_last = cycle_now;

 

        nsec = clocksource_cyc2ns(cycle_delta, timekeeper.mult,

                                  timekeeper.shift);

 

        /* If arch requires, add in gettimeoffset() */

        nsec += arch_gettimeoffset();

 

        timespec_add_ns(&xtime, nsec);

 

        nsec = clocksource_cyc2ns(cycle_delta, clock->mult, clock->shift);

        timespec_add_ns(&raw_time, nsec);

} 

  在本函式中,首先計算當前時刻與上一次呼叫read回撥函式時刻clocksoure計數值的差值,記為cycle_delta。之後,在計算xtime的調整時長時,使用的是timekeeper結構中的mult和shift欄位,而在計算raw_time的調整時長時,使用的是clocksource的mult和shift欄位。因timekeeper的mult欄位會被ntp調整,所以說xtime受ntp調整的影響而raw_time不受ntp調整的影響。

2.2.4.2 total_sleep_time/monotonic time

static void __timekeeping_inject_sleeptime(struct timespec *delta)

{

        xtime = timespec_add(xtime, *delta);

        wall_to_monotonic = timespec_sub(wall_to_monotonic, *delta);

        total_sleep_time = timespec_add(total_sleep_time, *delta);

}

   在休眠結束時會呼叫__timekeeping_inject_sleeptime來調整時間。由於xtime是牆上時間,所以必須加上休眠時間。monotonic time不受休眠時間的影響,所以需要在wall_to_monotonic中減去相應的休眠時間,這樣xtime與wall_to_monotonic的和所表示的monotonic time的值就沒有發生跳變。在最後,更新total_sleep_time的值。

  由於monotonic time的值是xtime與wall_to_monotonic之和,所以除了休眠時間和使用do_settimeofday調整時間時需要調整wall_to_monotonic外,其他時候,monotonic time隨xtime增長而增長。所以大部分時間我們不需要調整wall_to_monotonic變數的值。


相關文章