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);


/* signal hrtimers about time change */
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;


/* Make sure we're fully resumed: */
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;


/* normally this loop will run just once, however in the
* case of lost or late ticks, it will accumulate correctly.
*/
while (offset >= clock->cycle_interval) {
/* accumulate one 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();
}


/* accumulate error between NTP and clock interval */
clock->error += tick_length;
clock->error -= clock->xtime_interval << (NTP_SCALE_SHIFT - clock->shift);
}


/* correct the clock when NTP error is too big */
clocksource_adjust(offset);


/* store full nanoseconds into xtime */
xtime.tv_nsec = (s64)clock->xtime_nsec >> clock->shift;
clock->xtime_nsec -= (s64)xtime.tv_nsec << clock->shift;


update_xtime_cache(cyc2ns(clock, offset));


/* check to see if there is a new clocksource to use */
change_clocksource();
update_vsyscall(&xtime, clock);
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值