summaryrefslogtreecommitdiff
path: root/sys/kern/kern_clock.c
diff options
context:
space:
mode:
authorPaul Janzen <pjanzen@cvs.openbsd.org>2000-07-05 08:10:58 +0000
committerPaul Janzen <pjanzen@cvs.openbsd.org>2000-07-05 08:10:58 +0000
commit774226a6c3e57416cc12265b1389f352dcab842a (patch)
treeef95bbec13457b028a526ab8180015e82182ca5c /sys/kern/kern_clock.c
parentf536be0b9b86b35f93b37316f9d93a7c60265601 (diff)
Stop sleeps from returning early (by up to a clock tick).
From FreeBSD: eventually, we should replace hzto() with something like tvtohz() as well.
Diffstat (limited to 'sys/kern/kern_clock.c')
-rw-r--r--sys/kern/kern_clock.c60
1 files changed, 39 insertions, 21 deletions
diff --git a/sys/kern/kern_clock.c b/sys/kern/kern_clock.c
index 51e23c61f26..fbf1192b99b 100644
--- a/sys/kern/kern_clock.c
+++ b/sys/kern/kern_clock.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_clock.c,v 1.23 2000/03/23 11:20:45 art Exp $ */
+/* $OpenBSD: kern_clock.c,v 1.24 2000/07/05 08:10:56 pjanzen Exp $ */
/* $NetBSD: kern_clock.c,v 1.34 1996/06/09 04:51:03 briggs Exp $ */
/*-
@@ -55,6 +55,7 @@
#include <sys/sched.h>
#include <machine/cpu.h>
+#include <machine/limits.h>
#ifdef GPROF
#include <sys/gmon.h>
@@ -696,34 +697,51 @@ int
hzto(tv)
struct timeval *tv;
{
- register long ticks, sec;
+ register unsigned long ticks;
+ register long sec, usec;
int s;
/*
- * If number of microseconds will fit in 32 bit arithmetic,
- * then compute number of microseconds to time and scale to
- * ticks. Otherwise just compute number of hz in time, rounding
- * times greater than representible to maximum value. (We must
- * compute in microseconds, because hz can be greater than 1000,
- * and thus tick can be less than one millisecond).
+ * If the number of usecs in the whole seconds part of the time
+ * difference fits in a long, then the total number of usecs will
+ * fit in an unsigned long. Compute the total and convert it to
+ * ticks, rounding up and adding 1 to allow for the current tick
+ * to expire. Rounding also depends on unsigned long arithmetic
+ * to avoid overflow.
*
- * Delta times less than 14 hours can be computed ``exactly''.
- * (Note that if hz would yeild a non-integral number of us per
- * tick, i.e. tickfix is nonzero, timouts can be a tick longer
- * than they should be.) Maximum value for any timeout in 10ms
- * ticks is 250 days.
+ * Otherwise, if the number of ticks in the whole seconds part of
+ * the time difference fits in a long, then convert the parts to
+ * ticks separately and add, using similar rounding methods and
+ * overflow avoidance. This method would work in the previous
+ * case but it is slightly slower and assumes that hz is integral.
+ *
+ * Otherwise, round the time difference down to the maximum
+ * representable value.
+ *
+ * If ints have 32 bits, then the maximum value for any timeout in
+ * 10ms ticks is 248 days.
*/
s = splhigh();
sec = tv->tv_sec - time.tv_sec;
- if (sec <= 0x7fffffff / 1000000 - 1)
- ticks = ((tv->tv_sec - time.tv_sec) * 1000000 +
- (tv->tv_usec - time.tv_usec)) / tick;
- else if (sec <= 0x7fffffff / hz)
- ticks = sec * hz;
- else
- ticks = 0x7fffffff;
+ usec = tv->tv_usec - time.tv_usec;
splx(s);
- return (ticks);
+ if (usec < 0) {
+ sec--;
+ usec += 1000000;
+ }
+ if (sec < 0) {
+ ticks = 1;
+ } else if (sec <= LONG_MAX / 1000000)
+ ticks = (sec * 1000000 + (unsigned long)usec + (tick - 1))
+ / tick + 1;
+ else if (sec <= LONG_MAX / hz)
+ ticks = sec * hz
+ + ((unsigned long)usec + (tick - 1)) / tick + 1;
+ else
+ ticks = LONG_MAX;
+ if (ticks > INT_MAX)
+ ticks = INT_MAX;
+ return ((int)ticks);
}
/*