openKylin论坛

 找回密码

linux时间子系统(三) [复制链接]

本帖最后由 kylinmarket 于 2018-4-17 17:08 编辑

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


楼主
发表于 2018-4-17 17:07:34
回复

使用道具 举报

openKylin

GMT+8, 2024-5-17 15:09 , Processed in 0.019411 second(s), 17 queries , Gzip On.

Copyright ©2022 openKylin. All Rights Reserved .

ICP No. 15002470-12 Tianjin

快速回复 返回顶部 返回列表