天天看點

linux時間更新

time_t time (time t *result )是庫函數,最終會引起系統調用:

kernel\time\timekeeping.c

asmlinkage long sys_time(time_t __user * tloc)

{

time_t i = get_seconds();

if (tloc) {

if (put_user(i,tloc))

i = -EFAULT;

}

return i;

}

unsigned long get_seconds(void)

{

return xtime_cache.tv_sec;

}

xtime_cache和xtime變量也在這個檔案裡 .

xtime_cache是xtime變量的緩沖,更新xtime變量的時候,也會更新xtime_cache.

xtime變量在系統啟動的時候,通過讀rtc的值來初始化.在系統tick中斷的時候,會更新.

kernel\time\timekeeping.c

//phy3250沒有實作這個函數,是以有預設的函數,傳回0.

unsigned long __attribute__((weak)) read_persistent_clock(void)

{

return 0;

}

void __init timekeeping_init(void)

{

unsigned long flags;

unsigned long sec = read_persistent_clock(); 

write_seqlock_irqsave(&xtime_lock, flags);

ntp_init();

clock = clocksource_get_next();

clocksource_calculate_interval(clock, NTP_INTERVAL_LENGTH);

clock->cycle_last = clocksource_read(clock);

xtime.tv_sec = sec;

xtime.tv_nsec = 0;

set_normalized_timespec(&wall_to_monotonic,

-xtime.tv_sec, -xtime.tv_nsec);

update_xtime_cache(0);

total_sleep_time = 0;

write_sequnlock_irqrestore(&xtime_lock, flags);

}

xtime初始化為0.

系統啟動的時候,會調用函數:

drivers\rtc\hctosys.c

static int __init rtc_hctosys(void)

{

int err;

struct rtc_time tm;

struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);

if (rtc == NULL) {

printk("%s: unable to open rtc device (%s)\n",

__FILE__, CONFIG_RTC_HCTOSYS_DEVICE);

return -ENODEV;

}

err = rtc_read_time(rtc, &tm);

if (err == 0) {

err = rtc_valid_tm(&tm);

if (err == 0) {

struct timespec tv;

tv.tv_nsec = NSEC_PER_SEC >> 1;

rtc_tm_to_time(&tm, &tv.tv_sec);

do_settimeofday(&tv);

dev_info(rtc->dev.parent,

"setting system clock to "

"%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n",

tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,

tm.tm_hour, tm.tm_min, tm.tm_sec,

(unsigned int) tv.tv_sec);

}

else

dev_err(rtc->dev.parent,

"hctosys: invalid date/time\n");

}

else

dev_err(rtc->dev.parent,

"hctosys: unable to read the hardware clock\n");

rtc_class_close(rtc);

return 0;

}

從rtc讀了時間之後,do_settimeofday函數又設定了xtime變量,同時也更新了xtime_cache.

int do_settimeofday(struct timespec *tv)

{

unsigned long flags;

time_t wtm_sec, sec = tv->tv_sec;

long wtm_nsec, nsec = tv->tv_nsec;

if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)

return -EINVAL;

write_seqlock_irqsave(&xtime_lock, flags);

nsec -= __get_nsec_offset();

wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);

wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);

set_normalized_timespec(&xtime, sec, nsec);

set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);

update_xtime_cache(0);

clock->error = 0;

ntp_clear();

update_vsyscall(&xtime, clock);

write_sequnlock_irqrestore(&xtime_lock, flags);

clock_was_set();

return 0;

}

void update_xtime_cache(u64 nsec)

{

xtime_cache = xtime;

timespec_add_ns(&xtime_cache, nsec);

}

kernel\time.c

void set_normalized_timespec(struct timespec *ts, time_t sec, long nsec)

{

while (nsec >= NSEC_PER_SEC) {

nsec -= NSEC_PER_SEC;

++sec;

}

while (nsec < 0) {

nsec += NSEC_PER_SEC;

--sec;

}

ts->tv_sec = sec;

ts->tv_nsec = nsec;

}

tick中斷的時候調用do_timer更新

kernel\timer.c

static inline void update_times(unsigned long ticks)

{

update_wall_time();

calc_load(ticks);

}

void do_timer(unsigned long ticks)

{

jiffies_64 += ticks;

update_times(ticks);

}

void update_wall_time(void)

{

cycle_t offset;

if (unlikely(timekeeping_suspended))

return;

#ifdef CONFIG_GENERIC_TIME

offset = (clocksource_read(clock) - clock->cycle_last) & clock->mask;

#else

offset = clock->cycle_interval;

#endif

clock->xtime_nsec += (s64)xtime.tv_nsec << clock->shift;

while (offset >= clock->cycle_interval) {

clock->xtime_nsec += clock->xtime_interval;

clock->cycle_last += clock->cycle_interval;

offset -= clock->cycle_interval;

if (clock->xtime_nsec >= (u64)NSEC_PER_SEC << clock->shift) {

clock->xtime_nsec -= (u64)NSEC_PER_SEC << clock->shift;

xtime.tv_sec++;

second_overflow();

}

clock->error += tick_length;

clock->error -= clock->xtime_interval << (NTP_SCALE_SHIFT - clock->shift);

}

clocksource_adjust(offset);

xtime.tv_nsec = (s64)clock->xtime_nsec >> clock->shift;

clock->xtime_nsec -= (s64)xtime.tv_nsec << clock->shift;

update_xtime_cache(cyc2ns(clock, offset));

change_clocksource();

update_vsyscall(&xtime, clock);

}

繼續閱讀