diff --git a/sys/kern/kern_clock.c b/sys/kern/kern_clock.c --- a/sys/kern/kern_clock.c +++ b/sys/kern/kern_clock.c @@ -556,60 +556,28 @@ } /* - * Compute number of ticks in the specified amount of time. + * Compute number of ticks representing the specified amount of time. */ int tvtohz(struct timeval *tv) { - unsigned long ticks; - long sec, usec; + int64_t retval; + int64_t usec; - /* - * 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. - * - * 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. - */ - sec = tv->tv_sec; - usec = tv->tv_usec; - if (usec < 0) { - sec--; - usec += 1000000; - } - if (sec < 0) { -#ifdef DIAGNOSTIC - if (usec > 0) { - sec++; - usec -= 1000000; - } - printf("tvotohz: negative time difference %ld sec %ld usec\n", - sec, usec); -#endif - ticks = 1; - } else if (sec <= LONG_MAX / 1000000) - ticks = howmany(sec * 1000000 + (unsigned long)usec, tick) + 1; - else if (sec <= LONG_MAX / hz) - ticks = sec * hz - + howmany((unsigned long)usec, tick) + 1; - else - ticks = LONG_MAX; - if (ticks > INT_MAX) - ticks = INT_MAX; - return ((int)ticks); + /* convert time to microseconds */ + usec = (int64_t)tv->tv_sec * 1000000LL + (int64_t)tv->tv_usec; + + /* convert to ticks */ + retval = __stime64_scale32_floor(usec, hz, 1000000); + + /* range check */ + if (__predict_false(retval < 0)) + retval = 0; + else if (__predict_false(retval > INT_MAX - 1)) + retval = INT_MAX - 1; + + /* add one additional tick */ + return ((int)retval + 1); } /*