From 44ecaa7c9821d41aa3d07e584ea19f60db57f448 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Fri, 29 Nov 2013 21:38:47 -0800 Subject: [PATCH] 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 --- src/win/util.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/win/util.c b/src/win/util.c index a8183438fa..266b881640 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -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_); }