diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3a4684f6c..f530f04c3 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -192,8 +192,10 @@ add_unit_test(dispatch_c99 NO_BSD_OVERLAY SOURCES dispatch_c99.c) add_unit_test(dispatch_plusplus SOURCES dispatch_plusplus.cpp) # test-specific link options -target_link_libraries(dispatch_group PRIVATE m) -target_link_libraries(dispatch_timer_short PRIVATE m) +if(NOT WIN32) + target_link_libraries(dispatch_group PRIVATE m) + target_link_libraries(dispatch_timer_short PRIVATE m) +endif() # test-specific compile options set_target_properties(dispatch_c99 PROPERTIES C_STANDARD 99) diff --git a/tests/dispatch_drift.c b/tests/dispatch_drift.c index e483f3666..0381cabe6 100644 --- a/tests/dispatch_drift.c +++ b/tests/dispatch_drift.c @@ -22,8 +22,8 @@ #include #endif #include -#include #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +#include #include #endif #include @@ -46,8 +46,13 @@ main(int argc __attribute__((unused)), char* argv[] __attribute__((unused))) __block uint32_t count = 0; __block double last_jitter = 0; __block double drift_sum = 0; +#if defined(_WIN32) + // 25 times a second (Windows timer resolution is poor) + uint64_t interval = 1000000000 / 25; +#else // 100 times a second uint64_t interval = 1000000000 / 100; +#endif double interval_d = interval / 1000000000.0; // for 25 seconds unsigned int target = (unsigned int)(25.0 / interval_d); diff --git a/tests/dispatch_timer_bit31.c b/tests/dispatch_timer_bit31.c index eed17aea7..a70c4f6d0 100644 --- a/tests/dispatch_timer_bit31.c +++ b/tests/dispatch_timer_bit31.c @@ -21,7 +21,9 @@ #include #include #include +#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) #include +#endif #include diff --git a/tests/dispatch_timer_bit63.c b/tests/dispatch_timer_bit63.c index 84868ca99..f01ca5183 100644 --- a/tests/dispatch_timer_bit63.c +++ b/tests/dispatch_timer_bit63.c @@ -21,7 +21,9 @@ #include #include #include +#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) #include +#endif #include diff --git a/tests/dispatch_timer_set_time.c b/tests/dispatch_timer_set_time.c index 5ffd63e5e..6f30b0c98 100644 --- a/tests/dispatch_timer_set_time.c +++ b/tests/dispatch_timer_set_time.c @@ -18,11 +18,12 @@ * @APPLE_APACHE_LICENSE_HEADER_END@ */ -#include #include #include #include +#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) #include +#endif #include diff --git a/tests/dispatch_timer_timeout.c b/tests/dispatch_timer_timeout.c index f43409e02..109bbff37 100644 --- a/tests/dispatch_timer_timeout.c +++ b/tests/dispatch_timer_timeout.c @@ -21,7 +21,9 @@ #include #include #include +#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) #include +#endif #include diff --git a/tests/generic_win_port.c b/tests/generic_win_port.c index d9a52f477..f84f9f9be 100644 --- a/tests/generic_win_port.c +++ b/tests/generic_win_port.c @@ -183,18 +183,50 @@ gettimeofday(struct timeval *tp, void *tzp) return 0; } +typedef void (WINAPI *QueryUnbiasedInterruptTimePreciseT)(PULONGLONG); +static QueryUnbiasedInterruptTimePreciseT QueryUnbiasedInterruptTimePrecisePtr; + +static BOOL +mach_absolute_time_init(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContext) +{ + // QueryUnbiasedInterruptTimePrecise() is declared in the Windows headers + // but it isn't available in any import libraries. We must manually load it + // from KernelBase.dll. + HMODULE kernelbase = LoadLibraryW(L"KernelBase.dll"); + if (!kernelbase) { + print_winapi_error("LoadLibraryW", GetLastError()); + abort(); + } + QueryUnbiasedInterruptTimePrecisePtr = + (QueryUnbiasedInterruptTimePreciseT)GetProcAddress(kernelbase, + "QueryUnbiasedInterruptTimePrecise"); + if (!QueryUnbiasedInterruptTimePrecisePtr) { + fprintf(stderr, "QueryUnbiasedInterruptTimePrecise is not available\n"); + abort(); + } + return TRUE; +} + +uint64_t +mach_absolute_time(void) +{ + static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; + if (!InitOnceExecuteOnce(&init_once, mach_absolute_time_init, NULL, NULL)) { + print_winapi_error("InitOnceExecuteOnce", GetLastError()); + abort(); + } + ULONGLONG result = 0; + QueryUnbiasedInterruptTimePrecisePtr(&result); + return result * 100; // Convert from 100ns units +} + void print_winapi_error(const char *function_name, DWORD error) { char *message = NULL; DWORD len = FormatMessageA( - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, - error, - 0, - (LPSTR)&message, - 0, - NULL); + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, + error, 0, (LPSTR)&message, 0, NULL); if (len > 0) { // Note: FormatMessage includes a newline at the end of the message fprintf(stderr, "%s: %s", function_name, message); @@ -214,10 +246,6 @@ sleep(unsigned int seconds) int usleep(unsigned int usec) { - DWORD ms = usec / 1000; - if (ms == 0 && usec != 0) { - ms = 1; - } - Sleep(ms); + Sleep((usec + 999) / 1000); return 0; } diff --git a/tests/generic_win_port.h b/tests/generic_win_port.h index cf96a21a0..41c076c68 100644 --- a/tests/generic_win_port.h +++ b/tests/generic_win_port.h @@ -12,6 +12,14 @@ typedef long long ssize_t; typedef long ssize_t; #endif +struct mach_timebase_info { + uint32_t numer; + uint32_t denom; +}; + +typedef struct mach_timebase_info *mach_timebase_info_t; +typedef struct mach_timebase_info mach_timebase_info_data_t; + static inline int32_t OSAtomicIncrement32(volatile int32_t *var) { @@ -45,6 +53,18 @@ getpid(void); int gettimeofday(struct timeval *tp, void *tzp); +uint64_t +mach_absolute_time(void); + +static inline +int +mach_timebase_info(mach_timebase_info_t tbi) +{ + tbi->numer = 1; + tbi->denom = 1; + return 0; +} + void print_winapi_error(const char *function_name, DWORD error);