Skip to content

Commit

Permalink
windows/timer: fix uv_hrtime discontinuity
Browse files Browse the repository at this point in the history
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 joyent#850
  • Loading branch information
piscisaureus committed Nov 30, 2013
1 parent 5812e19 commit 44ecaa7
Showing 1 changed file with 14 additions and 11 deletions.
25 changes: 14 additions & 11 deletions src/win/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}


Expand Down Expand Up @@ -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;
}
Expand All @@ -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_);
}


Expand Down

0 comments on commit 44ecaa7

Please sign in to comment.