linux时间子系统(三)

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变量的值。


猜你喜欢

转载自blog.csdn.net/kylinos_123/article/details/79978020