windows/timer: fix uv_hrtime discontinuity

Large performance counter frequency values would cause overflows, even
when 64-bit integers were used to do the multiplication with NANOSEC.
Fix this by using floating point math instead.

Fixes #850
This commit is contained in:
Bert Belder 2013-11-29 21:38:47 -08:00
parent 5812e19bf6
commit 44ecaa7c98

View File

@ -59,20 +59,24 @@
static char *process_title;
static CRITICAL_SECTION process_title_lock;
/* The tick frequency of the high-resolution clock. */
static uint64_t hrtime_frequency_ = 0;
/* Frequency (ticks per nanosecond) of the high-resolution clock. */
static double hrtime_frequency_ = 0;
/*
* One-time intialization code for functionality defined in util.c.
*/
void uv__util_init() {
LARGE_INTEGER perf_frequency;
/* Initialize process title access mutex. */
InitializeCriticalSection(&process_title_lock);
/* Retrieve high-resolution timer frequency. */
if (!QueryPerformanceFrequency((LARGE_INTEGER*) &hrtime_frequency_))
hrtime_frequency_ = 0;
if (QueryPerformanceFrequency(&perf_frequency))
hrtime_frequency_ = (double) perf_frequency.QuadPart / (double) NANOSEC;
else
hrtime_frequency_= 0;
}
@ -447,7 +451,7 @@ uint64_t uv_hrtime(void) {
uv__once_init();
/* If the performance frequency is zero, there's no support. */
if (!hrtime_frequency_) {
if (hrtime_frequency_ == 0) {
/* uv__set_sys_error(loop, ERROR_NOT_SUPPORTED); */
return 0;
}
@ -457,12 +461,11 @@ uint64_t uv_hrtime(void) {
return 0;
}
/* Because we have no guarantee about the order of magnitude of the */
/* performance counter frequency, and there may not be much headroom to */
/* multiply by NANOSEC without overflowing, we use 128-bit math instead. */
return ((uint64_t) counter.LowPart * NANOSEC / hrtime_frequency_) +
(((uint64_t) counter.HighPart * NANOSEC / hrtime_frequency_)
<< 32);
/* Because we have no guarantee about the order of magnitude of the
* performance counter frequency, integer math could cause this computation
* to overflow. Therefore we resort to floating point math.
*/
return (uint64_t) ((double) counter.QuadPart / hrtime_frequency_);
}