From a974659504b5d0797e62d2d115812be17a1ea5a0 Mon Sep 17 00:00:00 2001 From: Tim Mayberry Date: Fri, 11 Sep 2015 21:48:26 +1000 Subject: [PATCH] Check return value of windows timer functions and handle errors Change return type of utils::get_microseconds to signed int and return -1 when failing to read timer --- libs/backends/portaudio/win_utils.cc | 43 +++++++++++++++++++++------- libs/backends/portaudio/win_utils.h | 10 ++++++- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/libs/backends/portaudio/win_utils.cc b/libs/backends/portaudio/win_utils.cc index 3b985820b7..dc0f8d5270 100644 --- a/libs/backends/portaudio/win_utils.cc +++ b/libs/backends/portaudio/win_utils.cc @@ -27,14 +27,26 @@ namespace { -LARGE_INTEGER -get_frequency () +bool& +qpc_frequency_success () { - LARGE_INTEGER freq; - QueryPerformanceFrequency(&freq); - return freq; + static bool success = false; + return success; } +LARGE_INTEGER +qpc_frequency () +{ + LARGE_INTEGER freq; + if (QueryPerformanceFrequency(&freq) == 0) { + DEBUG_TIMING ("Failed to determine frequency of QPC\n"); + qpc_frequency_success() = false; + } else { + qpc_frequency_success() = true; + } + + return freq; +} UINT& old_timer_resolution () @@ -86,15 +98,26 @@ reset_timer_resolution () return true; } -uint64_t get_microseconds () +int64_t +get_microseconds () { - static LARGE_INTEGER frequency = get_frequency (); + static LARGE_INTEGER frequency = qpc_frequency (); LARGE_INTEGER current_val; - QueryPerformanceCounter (¤t_val); + if (qpc_frequency_success()) { - return (uint64_t)(((double)current_val.QuadPart) / - ((double)frequency.QuadPart) * 1000000.0); + // MS docs say this will always succeed for systems >= XP but it may + // not return a monotonic value with non-invariant TSC's etc + if (QueryPerformanceCounter(¤t_val) != 0) { + return (int64_t)(((double)current_val.QuadPart) / + ((double)frequency.QuadPart) * 1000000.0); + } else { + DEBUG_TIMING ("Could not get QPC timer\n"); + } + return -1; + } + // For XP systems that don't support a high-res performance counter + return g_get_monotonic_time (); } } // namespace utils diff --git a/libs/backends/portaudio/win_utils.h b/libs/backends/portaudio/win_utils.h index 1b85eb04fd..072ce1f0b0 100644 --- a/libs/backends/portaudio/win_utils.h +++ b/libs/backends/portaudio/win_utils.h @@ -27,7 +27,15 @@ bool set_min_timer_resolution (); bool reset_timer_resolution (); -uint64_t get_microseconds (); +/** The highest resolution timer source provided by the system. On Vista and + * above this is the value returned by QueryPerformanceCounter(QPC). On XP, + * this will QPC if supported or otherwise g_get_monotonic_time will be used. + * + * @return A timer value in microseconds or -1 in the event that the reading + * the timer source fails, but the MS docs say that this won't occur for + * systems >= XP + */ +int64_t get_microseconds (); }