tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

yet another WARNING: negative runtime; monotonic clock has gone backwards



My machine rather frequently warns that negative runtime on boot.  The
reason was tc_delta() returns a bit larger value than usual and
th->th_scale * tc_delta() overflows.  As a result, binuptime() returns
smaller time or the first tc_windup() after clock is enabled sets
smaller th_offset.

Appended patch tries to adjust th->th_counter_offset just before
enabling clock interrupt so that tc_delta() returns reasonably small
value before the first tc_windup() call after interrupt enabled.

Comments?

enami.

Index: kern/kern_clock.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_clock.c,v
retrieving revision 1.126
diff -u -r1.126 kern_clock.c
--- kern/kern_clock.c   5 Oct 2008 21:57:20 -0000       1.126
+++ kern/kern_clock.c   12 Feb 2009 14:22:15 -0000
@@ -168,6 +168,15 @@
         */
        intr_timecounter.tc_frequency = hz;
        tc_init(&intr_timecounter);
+
+       /*
+        * At this point, the selected counter may run far away.
+        * Reset the th->th_counter_offset so that tc_delta() to
+        * return a value small enough to keep the result of
+        * `th->th_scale * tc_delta()' fits in 64-bit.
+        */
+       tc_ticktock();
+
        cpu_initclocks();
 
        /*
@@ -183,7 +192,6 @@
                if (hardscheddiv <= 0)
                        panic("hardscheddiv");
        }
-
 }
 
 /*
Index: kern/kern_tc.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_tc.c,v
retrieving revision 1.38
diff -u -r1.38 kern_tc.c
--- kern/kern_tc.c      11 Jan 2009 02:45:52 -0000      1.38
+++ kern/kern_tc.c      12 Feb 2009 14:22:30 -0000
@@ -937,15 +937,15 @@
  */
 
 static int tc_tick;
+static int tc_count;
 
 void
 tc_ticktock(void)
 {
-       static int count;
 
-       if (++count < tc_tick)
+       if (--tc_count > 0)
                return;
-       count = 0;
+       tc_count = tc_tick;
        mutex_spin_enter(&timecounter_lock);
        if (timecounter_bad != 0) {
                /* An existing timecounter has gone bad, pick a new one. */
@@ -980,6 +980,7 @@
        p = (tc_tick * 1000000) / hz;
        aprint_verbose("timecounter: Timecounters tick every %d.%03u msec\n",
            p / 1000, p % 1000);
+       tc_count = tc_tick;
 
        /* warm up new timecounter (again) and get rolling. */
        (void)timecounter->tc_get_timecount(timecounter);


Home | Main Index | Thread Index | Old Index