static int windows_clock_gettime(int clk_id, struct timespec *tp) { struct timer_request request; #if !defined(_MSC_VER) || (_MSC_VER < 1900) FILETIME filetime; ULARGE_INTEGER rtime; #endif DWORD r; switch (clk_id) { case USBI_CLOCK_MONOTONIC: if (timer_thread) { request.tp = tp; request.event = CreateEvent(NULL, FALSE, FALSE, NULL); if (request.event == NULL) return LIBUSB_ERROR_NO_MEM; if (!pPostThreadMessageA(timer_thread_id, WM_TIMER_REQUEST, 0, (LPARAM)&request)) { usbi_err(NULL, "PostThreadMessage failed for timer thread: %s", windows_error_str(0)); CloseHandle(request.event); return LIBUSB_ERROR_OTHER; } do { r = WaitForSingleObject(request.event, TIMER_REQUEST_RETRY_MS); if (r == WAIT_TIMEOUT) usbi_dbg("could not obtain a timer value within reasonable timeframe - too much load?"); else if (r == WAIT_FAILED) usbi_err(NULL, "WaitForSingleObject failed: %s", windows_error_str(0)); } while (r == WAIT_TIMEOUT); CloseHandle(request.event); if (r == WAIT_OBJECT_0) return LIBUSB_SUCCESS; else return LIBUSB_ERROR_OTHER; } // Fall through and return real-time if monotonic was not detected @ timer init case USBI_CLOCK_REALTIME: #if defined(_MSC_VER) && (_MSC_VER >= 1900) timespec_get(tp, TIME_UTC); #else // We follow http://msdn.microsoft.com/en-us/library/ms724928%28VS.85%29.aspx // with a predef epoch time to have an epoch that starts at 1970.01.01 00:00 // Note however that our resolution is bounded by the Windows system time // functions and is at best of the order of 1 ms (or, usually, worse) GetSystemTimeAsFileTime(&filetime); rtime.LowPart = filetime.dwLowDateTime; rtime.HighPart = filetime.dwHighDateTime; rtime.QuadPart -= EPOCH_TIME; tp->tv_sec = (long)(rtime.QuadPart / 10000000); tp->tv_nsec = (long)((rtime.QuadPart % 10000000) * 100); #endif return LIBUSB_SUCCESS; default: return LIBUSB_ERROR_INVALID_PARAM; } }
void windows_destroy_clock(void) { if (timer_thread) { // actually the signal to quit the thread. if (!pPostThreadMessageA(timer_thread_id, WM_TIMER_EXIT, 0, 0) || (WaitForSingleObject(timer_thread, INFINITE) != WAIT_OBJECT_0)) { usbi_dbg("could not wait for timer thread to quit"); TerminateThread(timer_thread, 1); // shouldn't happen, but we're destroying // all objects it might have held anyway. } CloseHandle(timer_thread); timer_thread = NULL; timer_thread_id = 0; } }