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.
This commit is contained in:
Bruce Evans 1994-12-12 11:58:46 +00:00
parent d2ee1a1856
commit 6976af69e8
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=5081
3 changed files with 126 additions and 48 deletions

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}