tech-kern archive

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

Bug fix for PR 26470 for review



Hi all,
attached patch fixes a problem that settimeofday with short period
timers will loop in the kernel for a long time. The attached patch
differs from the version in the PR slightly as it will do the sanest
possible thing if the time ever goes back. I am not sure if that can
happen at that point, but better be correct.

Any comments?

Joerg
Index: kern_time.c
===================================================================
RCS file: /data/repo/netbsd/src/sys/kern/kern_time.c,v
retrieving revision 1.147
diff -u -p -r1.147 kern_time.c
--- kern_time.c 8 May 2008 18:56:58 -0000       1.147
+++ kern_time.c 24 May 2008 16:35:18 -0000
@@ -923,8 +923,10 @@ sys_timer_getoverrun(struct lwp *l, cons
 void
 realtimerexpire(void *arg)
 {
+       uint64_t last_val, next_val, interval, now_ms;
        struct timeval now;
        struct ptimer *pt;
+       int backwards;
 
        pt = arg;
 
@@ -936,24 +938,33 @@ realtimerexpire(void *arg)
                mutex_spin_exit(&timer_lock);
                return;
        }
-       for (;;) {
-               timeradd(&pt->pt_time.it_value,
-                   &pt->pt_time.it_interval, &pt->pt_time.it_value);
-               getmicrotime(&now);
-               if (timercmp(&pt->pt_time.it_value, &now, >)) {
-                       /*
-                        * Don't need to check hzto() return value, here.
-                        * callout_reset() does it for us.
-                        */
-                       callout_reset(&pt->pt_ch, hzto(&pt->pt_time.it_value),
-                           realtimerexpire, pt);
-                       mutex_spin_exit(&timer_lock);
-                       return;
-               }
-               mutex_spin_exit(&timer_lock);
-               pt->pt_overruns++;
-               mutex_spin_enter(&timer_lock);
-       }
+
+       getmicrotime(&now);
+       backwards = (timercmp(&pt->pt_time.it_value, &now, >));
+#define TV2MS(x) (((uint64_t)(x)->tv_sec) * 1000000 + (x)->tv_usec)
+       now_ms = TV2MS(&now);
+       last_val = TV2MS(&pt->pt_time.it_value);
+       interval = TV2MS(&pt->pt_time.it_interval);
+#undef TV2MS
+
+       next_val = now_ms +
+           (now_ms - last_val + interval - 1) % interval;
+
+       if (backwards)
+               next_val += interval;
+       else
+               pt->pt_overruns = (now_ms - last_val) / interval;
+
+       pt->pt_time.it_value.tv_sec = next_val / 1000000;
+       pt->pt_time.it_value.tv_usec = next_val % 1000000;
+
+       /*
+        * Don't need to check hzto() return value, here.
+        * callout_reset() does it for us.
+        */
+       callout_reset(&pt->pt_ch, hzto(&pt->pt_time.it_value),
+           realtimerexpire, pt);
+       mutex_spin_exit(&timer_lock);
 }
 
 /* BSD routine to get the value of an interval timer. */


Home | Main Index | Thread Index | Old Index