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 timestatic 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变量的值。 |
linux时间子系统(三)
猜你喜欢
转载自blog.csdn.net/kylinos_123/article/details/79978020
今日推荐
周排行