(patch) Re: pmtimer and nanouptime

Matthew Dillon dillon at apollo.backplane.com
Tue Jul 20 12:07:15 PDT 2004


    Please try this patch.

					-Matt

Index: i386/isa/clock.c
===================================================================
RCS file: /cvs/src/sys/i386/isa/clock.c,v
retrieving revision 1.15
diff -u -r1.15 clock.c
--- i386/isa/clock.c	20 Jul 2004 04:12:08 -0000	1.15
+++ i386/isa/clock.c	20 Jul 2004 19:02:13 -0000
@@ -596,17 +596,21 @@
 }
 
 /*
- * Restore all the timers non-atomically (XXX: should be atomically).
+ * Restore all the timers.
  *
- * This function is called from apm_default_resume() to restore all the timers.
- * This should not be necessary, but there are broken laptops that do not
- * restore all the timers on resume.
+ * This function is called from apm_default_resume() / pmtimer to restore
+ * all the timers.  We also have to restore our timebases, especially on
+ * MP systems, because cputimer_count() counter's delta may have grown
+ * too large for nanouptime() and friends to handle.
  */
 void
 timer_restore(void)
 {
+	crit_enter();
 	i8254_restore();		/* restore timer_freq and hz */
 	rtc_restore();			/* reenable RTC interrupts */
+	restoreclocks();
+	crit_exit();
 }
 
 /*
Index: kern/kern_clock.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_clock.c,v
retrieving revision 1.21
diff -u -r1.21 kern_clock.c
--- kern/kern_clock.c	16 Jul 2004 05:51:09 -0000	1.21
+++ kern/kern_clock.c	20 Jul 2004 19:05:49 -0000
@@ -196,6 +196,36 @@
 }
 
 /*
+ * Resynchronize gd_cpuclock_base after the system has been woken up from 
+ * a sleep.  It is absolutely essential that all the cpus be properly
+ * synchronized.  Resynching is required because nanouptime() and friends
+ * will overflow intermediate multiplications if more then 2 seconds
+ * worth of cputimer_cont() delta has built up.
+ */
+#ifdef SMP
+
+static
+void
+restoreclocks_remote(lwkt_cpusync_t poll)
+{
+	mycpu->gd_cpuclock_base = *(sysclock_t *)poll->cs_data;
+	mycpu->gd_time_seconds = globaldata_find(0)->gd_time_seconds;
+}
+
+#endif
+
+void
+restoreclocks(void)
+{
+	sysclock_t base = cputimer_count();
+#ifdef SMP
+	lwkt_cpusync_simple(-1, restoreclocks_remote, &base);
+#else
+	mycpu->gd_cpuclock_base = base;
+#endif
+}
+
+/*
  * This sets the current real time of day.  Timespecs are in seconds and
  * nanoseconds.  We do not mess with gd_time_seconds and gd_cpuclock_base,
  * instead we adjust basetime so basetime + gd_* results in the current
Index: sys/time.h
===================================================================
RCS file: /cvs/src/sys/sys/time.h,v
retrieving revision 1.8
diff -u -r1.8 time.h
--- sys/time.h	30 Jan 2004 05:42:18 -0000	1.8
+++ sys/time.h	20 Jul 2004 19:02:43 -0000
@@ -192,6 +192,7 @@
 extern time_t	time_second;
 
 void	initclocks_pcpu(void);
+void	restoreclocks(void);
 void	getmicrouptime (struct timeval *tv);
 void	getmicrotime (struct timeval *tv);
 void	getnanouptime (struct timespec *tv);





More information about the Bugs mailing list