diff options
author | bde <bde@FreeBSD.org> | 1994-12-12 11:58:46 +0000 |
---|---|---|
committer | bde <bde@FreeBSD.org> | 1994-12-12 11:58:46 +0000 |
commit | 0d848d17c5da0a5c3ca6784b9e8ac2eb63a1e04e (patch) | |
tree | 3f63f28660d7050f5a12f0fe1a17607dc2b10b61 /sys | |
parent | 3097328edf0de7ed793760a43fe341b9a3c1175c (diff) | |
download | FreeBSD-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')
-rw-r--r-- | sys/kern/kern_clock.c | 58 | ||||
-rw-r--r-- | sys/kern/kern_tc.c | 58 | ||||
-rw-r--r-- | sys/kern/kern_timeout.c | 58 |
3 files changed, 126 insertions, 48 deletions
diff --git a/sys/kern/kern_clock.c b/sys/kern/kern_clock.c index 35e119b..c1ff1bd 100644 --- a/sys/kern/kern_clock.c +++ b/sys/kern/kern_clock.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); } diff --git a/sys/kern/kern_tc.c b/sys/kern/kern_tc.c index 35e119b..c1ff1bd 100644 --- a/sys/kern/kern_tc.c +++ b/sys/kern/kern_tc.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); } 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); } |