diff options
author | kaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk> | 2003-10-28 13:09:07 +0000 |
---|---|---|
committer | kaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk> | 2003-10-28 13:09:07 +0000 |
commit | 5bafd427fd5105f50b0d79dc54e1f7f35163396c (patch) | |
tree | 65d26ed3b3c331ceb0e6c680087a930cde5e3089 | |
parent | 80e8211171990dc4cdb0e76a43a8cc6ee36a21df (diff) | |
download | xen-5bafd427fd5105f50b0d79dc54e1f7f35163396c.tar.gz xen-5bafd427fd5105f50b0d79dc54e1f7f35163396c.tar.bz2 xen-5bafd427fd5105f50b0d79dc54e1f7f35163396c.zip |
bitkeeper revision 1.533 (3f9e6a73y_so5j_vqiY6UPUJof-DFQ)
time.c:
Fix up interpolation of time so that, under normal use, we will never see time go backwards.
-rw-r--r-- | xen/arch/i386/time.c | 22 | ||||
-rw-r--r-- | xenolinux-2.4.22-sparse/arch/xeno/kernel/time.c | 66 |
2 files changed, 68 insertions, 20 deletions
diff --git a/xen/arch/i386/time.c b/xen/arch/i386/time.c index 395b15b68f..ddacbca63d 100644 --- a/xen/arch/i386/time.c +++ b/xen/arch/i386/time.c @@ -258,9 +258,21 @@ s_time_t get_s_time(void) { s_time_t now; unsigned long flags; + read_lock_irqsave(&xtime_lock, flags); + now = stime_irq + get_time_delta(); + + /* Ensure that the returned system time is monotonically increasing. */ + { + static s_time_t prev_now = 0; + if ( unlikely(now < prev_now) ) + now = prev_now; + prev_now = now; + } + read_unlock_irqrestore(&xtime_lock, flags); + return now; } @@ -335,16 +347,6 @@ int __init init_xeno_time() for ( rdtsc_bitshift = 0; cpu_ghz != 0; rdtsc_bitshift++, cpu_ghz >>= 1 ) continue; - /* - * We actually adjust cpu_freq to be 0.001% slower than the real - * frequenecy. This makes time run a little bit slower when interpolating - * the passage of time between periodic interrupts, so we expect a little - * jump in time whenever an interrupt comes in (roughly 100ns every 10ms). - * However, this should avoid us considtently running too fast and jumping - * _backwards_ on each interrupt, which would be much worse! - */ - cpu_freq = cpu_freq - (cpu_freq / 100000ULL); - scale = 1000000000LL << (32 + rdtsc_bitshift); scale /= cpu_freq; st_scale_f = scale & 0xffffffff; diff --git a/xenolinux-2.4.22-sparse/arch/xeno/kernel/time.c b/xenolinux-2.4.22-sparse/arch/xeno/kernel/time.c index 5b31e7fcf5..a26238de82 100644 --- a/xenolinux-2.4.22-sparse/arch/xeno/kernel/time.c +++ b/xenolinux-2.4.22-sparse/arch/xeno/kernel/time.c @@ -79,11 +79,20 @@ static s64 shadow_system_time; static u32 shadow_time_version; static struct timeval shadow_tv; +/* + * We use this to ensure that gettimeofday() is monotonically increasing. We + * only break this guarantee if the wall clock jumps backwards "a long way". + */ +static struct timeval last_seen_tv = {0,0}; + #ifdef CONFIG_XENO_PRIV -/* Periodically propagate synchronised time to the RTC and to Xen. */ -static long last_rtc_update, last_xen_update; +/* Periodically propagate synchronised time base to the RTC and to Xen. */ +static long last_update_to_rtc, last_update_to_xen; #endif +/* Periodically take synchronised time base from Xen, if we need it. */ +static long last_update_from_xen; + static u64 processed_system_time; #define HANDLE_USEC_UNDERFLOW(_tv) \ @@ -232,11 +241,13 @@ void do_gettimeofday(struct timeval *tv) again: read_lock_irqsave(&xtime_lock, flags); + _tv.tv_usec = get_time_delta_usecs(); if ( (lost = (jiffies - wall_jiffies)) != 0 ) _tv.tv_usec += lost * (1000000 / HZ); _tv.tv_sec = xtime.tv_sec; _tv.tv_usec += xtime.tv_usec; + if ( unlikely(!TIME_VALUES_UP_TO_DATE) ) { /* @@ -250,10 +261,18 @@ void do_gettimeofday(struct timeval *tv) write_unlock_irqrestore(&xtime_lock, flags); goto again; } - read_unlock_irqrestore(&xtime_lock, flags); HANDLE_USEC_OVERFLOW(_tv); + /* Ensure that time-of-day is monotonically increasing. */ + if ( (_tv.tv_sec < last_seen_tv.tv_sec) || + ((_tv.tv_sec == last_seen_tv.tv_sec) && + (_tv.tv_usec < last_seen_tv.tv_usec)) ) + _tv = last_seen_tv; + last_seen_tv = _tv; + + read_unlock_irqrestore(&xtime_lock, flags); + *tv = _tv; } @@ -292,11 +311,15 @@ void do_settimeofday(struct timeval *tv) time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; + /* Reset all our running time counts. They make no sense now. */ + last_seen_tv.tv_sec = 0; + last_update_from_xen = 0; + #ifdef CONFIG_XENO_PRIV if ( start_info.dom_id == 0 ) { dom0_op_t op; - last_rtc_update = last_xen_update = 0; + last_update_to_rtc = last_update_to_xen = 0; op.cmd = DOM0_SETTIME; op.u.settime.secs = newtv.tv_sec; op.u.settime.usecs = newtv.tv_usec; @@ -335,6 +358,7 @@ static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { s64 delta; + long sec_diff; get_time_values_from_xen(); @@ -351,21 +375,43 @@ static inline void do_timer_interrupt(int irq, void *dev_id, processed_system_time += NS_PER_TICK; } - if ( !independent_wallclock && ((time_status & STA_UNSYNC) != 0) ) + /* + * Take synchronised time from Xen once a minute if we're not + * synchronised ourselves, and we haven't chosen to keep an independent + * time base. + */ + if ( !independent_wallclock && + ((time_status & STA_UNSYNC) != 0) && + (xtime.tv_sec > (last_update_from_xen + 60)) ) { /* Adjust shadow timeval for jiffies that haven't updated xtime yet. */ shadow_tv.tv_usec -= (jiffies - wall_jiffies) * (1000000/HZ); HANDLE_USEC_UNDERFLOW(shadow_tv); + /* + * Reset our running time counts if they are invalidated by a warp + * backwards of more than 500ms. + */ + sec_diff = xtime.tv_sec - shadow_tv.tv_sec; + if ( unlikely(abs(sec_diff) > 1) || + unlikely(((sec_diff * 1000000) + + xtime.tv_usec - shadow_tv.tv_usec) > 500000) ) + { + last_update_to_rtc = last_update_to_xen = 0; + last_seen_tv.tv_sec = 0; + } + /* Update our unsynchronised xtime appropriately. */ xtime = shadow_tv; + + last_update_from_xen = xtime.tv_sec; } #ifdef CONFIG_XENO_PRIV if ( (start_info.dom_id == 0) && ((time_status & STA_UNSYNC) == 0) ) { /* Send synchronised time to Xen approximately every minute. */ - if ( xtime.tv_sec > (last_xen_update + 60) ) + if ( xtime.tv_sec > (last_update_to_xen + 60) ) { dom0_op_t op; struct timeval tv = xtime; @@ -379,7 +425,7 @@ static inline void do_timer_interrupt(int irq, void *dev_id, op.u.settime.system_time = shadow_system_time; HYPERVISOR_dom0_op(&op); - last_xen_update = xtime.tv_sec; + last_update_to_xen = xtime.tv_sec; } /* @@ -387,14 +433,14 @@ static inline void do_timer_interrupt(int irq, void *dev_id, * clock accordingly every ~11 minutes. Set_rtc_mmss() has to be called * as close as possible to 500 ms before the new second starts. */ - if ( (xtime.tv_sec > (last_rtc_update + 660)) && + if ( (xtime.tv_sec > (last_update_to_rtc + 660)) && (xtime.tv_usec >= (500000 - ((unsigned) tick) / 2)) && (xtime.tv_usec <= (500000 + ((unsigned) tick) / 2)) ) { if ( set_rtc_mmss(xtime.tv_sec) == 0 ) - last_rtc_update = xtime.tv_sec; + last_update_to_rtc = xtime.tv_sec; else - last_rtc_update = xtime.tv_sec - 600; + last_update_to_rtc = xtime.tv_sec - 600; } } #endif |