summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_timeout.c
diff options
context:
space:
mode:
authorbde <bde@FreeBSD.org>1994-12-12 11:58:46 +0000
committerbde <bde@FreeBSD.org>1994-12-12 11:58:46 +0000
commit0d848d17c5da0a5c3ca6784b9e8ac2eb63a1e04e (patch)
tree3f63f28660d7050f5a12f0fe1a17607dc2b10b61 /sys/kern/kern_timeout.c
parent3097328edf0de7ed793760a43fe341b9a3c1175c (diff)
downloadFreeBSD-src-0d848d17c5da0a5c3ca6784b9e8ac2eb63a1e04e.zip
FreeBSD-src-0d848d17c5da0a5c3ca6784b9e8ac2eb63a1e04e.tar.gz
Obtained from: my old fix for 1.1.5
Improve hzto(): Round up instead of down and then add 1 tick. This fixes sleep(1) sometimes sleeping for < 1 second and usleep(10000) sometimes sleeping for as little as 1 usec + syscall time. Don't do all the calculations at splhigh(). Don't depend on `tick' being a multiple of 1000. Don't lose accuracy for `sec' between 0x7fffffff / 1000 - 1000 and 0x7fffffff / hz. Don't assume that longs are 32 bits or that ints have the same size as longs.
Diffstat (limited to 'sys/kern/kern_timeout.c')
-rw-r--r--sys/kern/kern_timeout.c58
1 files changed, 42 insertions, 16 deletions
diff --git a/sys/kern/kern_timeout.c b/sys/kern/kern_timeout.c
index 35e119b..c1ff1bd 100644
--- a/sys/kern/kern_timeout.c
+++ b/sys/kern/kern_timeout.c
@@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)kern_clock.c 8.5 (Berkeley) 1/21/94
- * $Id: kern_clock.c,v 1.9 1994/10/02 17:35:10 phk Exp $
+ * $Id: kern_clock.c,v 1.10 1994/10/16 03:52:12 wollman Exp $
*/
/* Portions of this software are covered by the following: */
@@ -748,28 +748,54 @@ int
hzto(tv)
struct timeval *tv;
{
- register long ticks, sec;
+ register unsigned long ticks;
+ register long sec, usec;
int s;
/*
- * If number of milliseconds will fit in 32 bit arithmetic,
- * then compute number of milliseconds to time and scale to
- * ticks. Otherwise just compute number of hz in time, rounding
- * times greater than representible to maximum value.
+ * 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 25 days can be computed ``exactly''.
- * 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();
+ s = splclock();
sec = tv->tv_sec - time.tv_sec;
- if (sec <= 0x7fffffff / 1000 - 1000)
- ticks = ((tv->tv_sec - time.tv_sec) * 1000 +
- (tv->tv_usec - time.tv_usec) / 1000) / (tick / 1000);
- else if (sec <= 0x7fffffff / hz)
- ticks = sec * hz;
- else
- ticks = 0x7fffffff;
+ usec = tv->tv_usec - time.tv_usec;
splx(s);
+ if (usec < 0) {
+ sec--;
+ usec += 1000000;
+ }
+ if (sec < 0) {
+#ifdef DIAGNOSTIC
+ printf("hzto: negative time difference %ld sec %ld usec\n",
+ sec, usec);
+#endif
+ 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 (ticks);
}
OpenPOWER on IntegriCloud