aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>2003-10-28 13:09:07 +0000
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>2003-10-28 13:09:07 +0000
commit5bafd427fd5105f50b0d79dc54e1f7f35163396c (patch)
tree65d26ed3b3c331ceb0e6c680087a930cde5e3089
parent80e8211171990dc4cdb0e76a43a8cc6ee36a21df (diff)
downloadxen-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.c22
-rw-r--r--xenolinux-2.4.22-sparse/arch/xeno/kernel/time.c66
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