core: Split usbi_clock_gettime() into two separate functions

Most of the library only uses the monotonic clock. In fact, the only use
of the realtime clock is to implement the POSIX version of
usbi_cond_timedwait(). Now that Windows can no longer use the POSIX
thread abstraction, there is no need for Windows to implement a means of
reading the realtime clock.

This change replaces usbi_clock_gettime() with usbi_get_monotonic_time()
and usbi_get_real_time(). When clock_gettime() is available, both
functions are implemented as simple inline calls, otherwise the backend
must provide a definition for usbi_get_monotonic_time() *AND*
usbi_get_real_time() iff the platform is POSIX.

Reading the clocks is also never expected to fail. In practice, if it
ever did there would be much more than libusb that would not function
correctly. The new functions therefore have no return value, thus
allowing the callers to assume success and remove a bunch of error
handling code. The clock_gettime() wrappers have a simple error check
that is only enforced in debug builds.

This change also makes it unnecessary to check for and use
clock_gettime() on Windows, so remove it and always provide
usbi_get_monotonic_time().

Signed-off-by: Chris Dickens <christopher.a.dickens@gmail.com>
diff --git a/configure.ac b/configure.ac
index a5df4df..ef6927d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -197,13 +197,15 @@
 dnl headers not available on all platforms but required on others
 AC_CHECK_HEADERS([sys/time.h])
 
-dnl the clock_gettime() function needs certain clock IDs defined
-AC_CHECK_FUNCS([clock_gettime], [have_clock_gettime=yes], [have_clock_gettime=])
-if test "x$have_clock_gettime" = xyes; then
-	AC_CHECK_DECL([CLOCK_REALTIME], [], [AC_MSG_ERROR([C library headers missing definition for CLOCK_REALTIME])], [[#include <time.h>]])
-	AC_CHECK_DECL([CLOCK_MONOTONIC], [], [AC_MSG_ERROR([C library headers missing definition for CLOCK_MONOTONIC])], [[#include <time.h>]])
-elif test "x$backend" != xdarwin && test "x$backend" != xwindows; then
-	AC_MSG_ERROR([clock_gettime() is required on this platform])
+if test "x$platform" = xposix; then
+	dnl the clock_gettime() function needs certain clock IDs defined
+	AC_CHECK_FUNCS([clock_gettime], [have_clock_gettime=yes], [have_clock_gettime=])
+	if test "x$have_clock_gettime" = xyes; then
+		AC_CHECK_DECL([CLOCK_MONOTONIC], [], [AC_MSG_ERROR([C library headers missing definition for CLOCK_MONOTONIC])], [[#include <time.h>]])
+		AC_CHECK_DECL([CLOCK_REALTIME], [], [AC_MSG_ERROR([C library headers missing definition for CLOCK_REALTIME])], [[#include <time.h>]])
+	elif test "x$backend" != xdarwin; then
+		AC_MSG_ERROR([clock_gettime() is required on this platform])
+	fi
 fi
 
 dnl eventfd support
diff --git a/libusb/core.c b/libusb/core.c
index f106a68..a6b093b 100644
--- a/libusb/core.c
+++ b/libusb/core.c
@@ -2265,7 +2265,7 @@
 	usbi_mutex_static_lock(&default_context_lock);
 
 	if (!timestamp_origin.tv_sec)
-		usbi_clock_gettime(USBI_CLOCK_MONOTONIC, &timestamp_origin);
+		usbi_get_monotonic_time(&timestamp_origin);
 
 	if (!context && usbi_default_context) {
 		usbi_dbg("reusing default context");
@@ -2611,7 +2611,7 @@
 			log_str(LIBUSB_LOG_LEVEL_DEBUG, "--------------------------------------------------------------------------------" USBI_LOG_LINE_END);
 		}
 
-		usbi_clock_gettime(USBI_CLOCK_MONOTONIC, &timestamp);
+		usbi_get_monotonic_time(&timestamp);
 		TIMESPEC_SUB(&timestamp, &timestamp_origin, &timestamp);
 
 		header_len = snprintf(buf, sizeof(buf),
diff --git a/libusb/io.c b/libusb/io.c
index d565f89..bf6876e 100644
--- a/libusb/io.c
+++ b/libusb/io.c
@@ -24,8 +24,6 @@
 #include "libusbi.h"
 #include "hotplug.h"
 
-#include <errno.h>
-
 /**
  * \page libusb_io Synchronous and asynchronous device I/O
  *
@@ -1241,23 +1239,17 @@
 	free(ctx->event_data);
 }
 
-static int calculate_timeout(struct usbi_transfer *itransfer)
+static void calculate_timeout(struct usbi_transfer *itransfer)
 {
-	int r;
 	unsigned int timeout =
 		USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer)->timeout;
 
 	if (!timeout) {
 		TIMESPEC_CLEAR(&itransfer->timeout);
-		return 0;
+		return;
 	}
 
-	r = usbi_clock_gettime(USBI_CLOCK_MONOTONIC, &itransfer->timeout);
-	if (r < 0) {
-		usbi_err(ITRANSFER_CTX(itransfer),
-			"failed to read monotonic clock, errno=%d", errno);
-		return LIBUSB_ERROR_OTHER;
-	}
+	usbi_get_monotonic_time(&itransfer->timeout);
 
 	itransfer->timeout.tv_sec += timeout / 1000U;
 	itransfer->timeout.tv_nsec += (timeout % 1000U) * 1000000L;
@@ -1265,8 +1257,6 @@
 		++itransfer->timeout.tv_sec;
 		itransfer->timeout.tv_nsec -= NSEC_PER_SEC;
 	}
-
-	return 0;
 }
 
 /** \ingroup libusb_asyncio
@@ -1410,12 +1400,10 @@
 	struct usbi_transfer *cur;
 	struct timespec *timeout = &itransfer->timeout;
 	struct libusb_context *ctx = ITRANSFER_CTX(itransfer);
-	int r;
+	int r = 0;
 	int first = 1;
 
-	r = calculate_timeout(itransfer);
-	if (r)
-		return r;
+	calculate_timeout(itransfer);
 
 	/* if we have no other flying transfers, start the list with this one */
 	if (list_empty(&ctx->flying_transfers)) {
@@ -2038,24 +2026,19 @@
 		itransfer->timeout_flags |= USBI_TRANSFER_TIMED_OUT;
 	else
 		usbi_warn(TRANSFER_CTX(transfer),
-			"async cancel failed %d errno=%d", r, errno);
+			"async cancel failed %d", r);
 }
 
-static int handle_timeouts_locked(struct libusb_context *ctx)
+static void handle_timeouts_locked(struct libusb_context *ctx)
 {
-	int r;
 	struct timespec systime;
 	struct usbi_transfer *itransfer;
 
 	if (list_empty(&ctx->flying_transfers))
-		return 0;
+		return;
 
 	/* get current time */
-	r = usbi_clock_gettime(USBI_CLOCK_MONOTONIC, &systime);
-	if (r < 0) {
-		usbi_err(ctx, "failed to read monotonic clock, errno=%d", errno);
-		return LIBUSB_ERROR_OTHER;
-	}
+	usbi_get_monotonic_time(&systime);
 
 	/* iterate through flying transfers list, finding all transfers that
 	 * have expired timeouts */
@@ -2064,7 +2047,7 @@
 
 		/* if we've reached transfers of infinite timeout, we're all done */
 		if (!TIMESPEC_IS_SET(cur_ts))
-			return 0;
+			return;
 
 		/* ignore timeouts we've already handled */
 		if (itransfer->timeout_flags & (USBI_TRANSFER_TIMEOUT_HANDLED | USBI_TRANSFER_OS_HANDLES_TIMEOUT))
@@ -2072,23 +2055,19 @@
 
 		/* if transfer has non-expired timeout, nothing more to do */
 		if (TIMESPEC_CMP(cur_ts, &systime, >))
-			return 0;
+			return;
 
 		/* otherwise, we've got an expired timeout to handle */
 		handle_timeout(itransfer);
 	}
-	return 0;
 }
 
-static int handle_timeouts(struct libusb_context *ctx)
+static void handle_timeouts(struct libusb_context *ctx)
 {
-	int r;
-
 	ctx = usbi_get_context(ctx);
 	usbi_mutex_lock(&ctx->flying_transfers_lock);
-	r = handle_timeouts_locked(ctx);
+	handle_timeouts_locked(ctx);
 	usbi_mutex_unlock(&ctx->flying_transfers_lock);
-	return r;
 }
 
 static int handle_event_trigger(struct libusb_context *ctx)
@@ -2183,15 +2162,13 @@
 	usbi_mutex_lock(&ctx->flying_transfers_lock);
 
 	/* process the timeout that just happened */
-	r = handle_timeouts_locked(ctx);
-	if (r < 0)
-		goto out;
+	handle_timeouts_locked(ctx);
 
 	/* arm for next timeout */
 	r = arm_timer_for_next_timeout(ctx);
 
-out:
 	usbi_mutex_unlock(&ctx->flying_transfers_lock);
+
 	return r;
 }
 #endif
@@ -2246,8 +2223,10 @@
 
 	r = usbi_wait_for_events(ctx, &reported_events, timeout_ms);
 	if (r != LIBUSB_SUCCESS) {
-		if (r == LIBUSB_ERROR_TIMEOUT)
-			r = handle_timeouts(ctx);
+		if (r == LIBUSB_ERROR_TIMEOUT) {
+			handle_timeouts(ctx);
+			r = LIBUSB_SUCCESS;
+		}
 		goto done;
 	}
 
@@ -2350,7 +2329,8 @@
 	r = get_next_timeout(ctx, tv, &poll_timeout);
 	if (r) {
 		/* timeout already expired */
-		return handle_timeouts(ctx);
+		handle_timeouts(ctx);
+		return 0;
 	}
 
 retry:
@@ -2388,9 +2368,8 @@
 	if (r < 0)
 		return r;
 	else if (r == 1)
-		return handle_timeouts(ctx);
-	else
-		return 0;
+		handle_timeouts(ctx);
+	return 0;
 }
 
 /** \ingroup libusb_poll
@@ -2492,7 +2471,8 @@
 	r = get_next_timeout(ctx, tv, &poll_timeout);
 	if (r) {
 		/* timeout already expired */
-		return handle_timeouts(ctx);
+		handle_timeouts(ctx);
+		return 0;
 	}
 
 	return handle_events(ctx, &poll_timeout);
@@ -2566,7 +2546,6 @@
 	struct usbi_transfer *itransfer;
 	struct timespec systime;
 	struct timespec next_timeout = { 0, 0 };
-	int r;
 
 	ctx = usbi_get_context(ctx);
 	if (usbi_using_timer(ctx))
@@ -2598,11 +2577,7 @@
 		return 0;
 	}
 
-	r = usbi_clock_gettime(USBI_CLOCK_MONOTONIC, &systime);
-	if (r < 0) {
-		usbi_err(ctx, "failed to read monotonic clock, errno=%d", errno);
-		return 0;
-	}
+	usbi_get_monotonic_time(&systime);
 
 	if (!TIMESPEC_CMP(&systime, &next_timeout, <)) {
 		usbi_dbg("first timeout already expired");
diff --git a/libusb/libusbi.h b/libusb/libusbi.h
index 25b7e9a..1208274 100644
--- a/libusb/libusbi.h
+++ b/libusb/libusbi.h
@@ -488,22 +488,28 @@
 }
 
 #ifdef HAVE_CLOCK_GETTIME
-#define USBI_CLOCK_REALTIME	CLOCK_REALTIME
-#define USBI_CLOCK_MONOTONIC	CLOCK_MONOTONIC
-#define usbi_clock_gettime	clock_gettime
+static inline void usbi_get_monotonic_time(struct timespec *tp)
+{
+	int r = clock_gettime(CLOCK_MONOTONIC, tp);
+	assert(r == 0);
+}
+static inline void usbi_get_real_time(struct timespec *tp)
+{
+	int r = clock_gettime(CLOCK_REALTIME, tp);
+	assert(r == 0);
+}
 #else
 /* If the platform doesn't provide the clock_gettime() function, the backend
- * must provide its own implementation.  Two clocks must be supported by the
- * backend: USBI_CLOCK_REALTIME, and USBI_CLOCK_MONOTONIC.
+ * must provide its own clock implementations.  Two clock functions are
+ * required:
  *
- * Description of clocks:
- *   USBI_CLOCK_REALTIME:  clock returns time since system epoch.
- *   USBI_CLOCK_MONOTONIC: clock returns time since unspecified start time
- *			   (usually boot).
+ *   usbi_get_monotonic_time(): returns the time since an unspecified starting
+ *                              point (usually boot) that is monotonically
+ *                              increasing.
+ *   usbi_get_real_time(): returns the time since system epoch.
  */
-#define USBI_CLOCK_REALTIME	0
-#define USBI_CLOCK_MONOTONIC	1
-int usbi_clock_gettime(int clk_id, struct timespec *tp);
+void usbi_get_monotonic_time(struct timespec *tp);
+void usbi_get_real_time(struct timespec *tp);
 #endif
 
 /* in-memory transfer layout:
diff --git a/libusb/os/darwin_usb.c b/libusb/os/darwin_usb.c
index 13d7218..5251e8d 100644
--- a/libusb/os/darwin_usb.c
+++ b/libusb/os/darwin_usb.c
@@ -23,7 +23,6 @@
 #include <assert.h>
 #include <time.h>
 #include <ctype.h>
-#include <errno.h>
 #include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -2180,30 +2179,24 @@
 }
 
 #if !defined(HAVE_CLOCK_GETTIME)
-int usbi_clock_gettime(int clk_id, struct timespec *tp) {
+void usbi_get_monotonic_time(struct timespec *tp) {
   mach_timespec_t sys_time;
-  clock_serv_t clock_ref;
 
-  switch (clk_id) {
-  case USBI_CLOCK_REALTIME:
-    /* CLOCK_REALTIME represents time since the epoch */
-    clock_ref = clock_realtime;
-    break;
-  case USBI_CLOCK_MONOTONIC:
-    /* use system boot time as reference for the monotonic clock */
-    clock_ref = clock_monotonic;
-    break;
-  default:
-    errno = EINVAL;
-    return -1;
-  }
-
-  clock_get_time (clock_ref, &sys_time);
+  /* use system boot time as reference for the monotonic clock */
+  clock_get_time (clock_monotonic, &sys_time);
 
   tp->tv_sec  = sys_time.tv_sec;
   tp->tv_nsec = sys_time.tv_nsec;
+}
 
-  return 0;
+void usbi_get_real_time(struct timespec *tp) {
+  mach_timespec_t sys_time;
+
+  /* CLOCK_REALTIME represents time since the epoch */
+  clock_get_time (clock_realtime, &sys_time);
+
+  tp->tv_sec  = sys_time.tv_sec;
+  tp->tv_nsec = sys_time.tv_nsec;
 }
 #endif
 
diff --git a/libusb/os/events_windows.c b/libusb/os/events_windows.c
index 9f120bb..81d8b87 100644
--- a/libusb/os/events_windows.c
+++ b/libusb/os/events_windows.c
@@ -75,7 +75,6 @@
 	struct timespec systime, remaining;
 	FILETIME filetime;
 	LARGE_INTEGER dueTime;
-	int r;
 
 	/* Transfer timeouts are based on the monotonic clock and the waitable
 	 * timers on the system clock. This requires a conversion between the
@@ -85,11 +84,7 @@
 	 * be negative and thus an absolute system time in the past will be set.
 	 * This works just as intended because the timer becomes signalled
 	 * immediately. */
-	r = usbi_clock_gettime(USBI_CLOCK_MONOTONIC, &systime);
-	if (r < 0) {
-		usbi_err(NULL, "failed to read monotonic clock");
-		return LIBUSB_ERROR_OTHER;
-	}
+	usbi_get_monotonic_time(&systime);
 
 	TIMESPEC_SUB(timeout, &systime, &remaining);
 
diff --git a/libusb/os/threads_posix.c b/libusb/os/threads_posix.c
index b4199e6..c1745b3 100644
--- a/libusb/os/threads_posix.c
+++ b/libusb/os/threads_posix.c
@@ -45,9 +45,7 @@
 	struct timespec timeout;
 	int r;
 
-	r = usbi_clock_gettime(USBI_CLOCK_REALTIME, &timeout);
-	if (r < 0)
-		return r;
+	usbi_get_real_time(&timeout);
 
 	timeout.tv_sec += tv->tv_sec;
 	timeout.tv_nsec += tv->tv_usec * 1000L;
diff --git a/libusb/os/windows_common.c b/libusb/os/windows_common.c
index cf151a6..c72c4d2 100644
--- a/libusb/os/windows_common.c
+++ b/libusb/os/windows_common.c
@@ -24,7 +24,6 @@
 
 #include <config.h>
 
-#include <errno.h>
 #include <process.h>
 #include <stdio.h>
 
@@ -42,12 +41,6 @@
 static unsigned int init_count;
 static bool usbdk_available;
 
-#if !defined(HAVE_CLOCK_GETTIME)
-// Global variables for clock_gettime mechanism
-static uint64_t hires_ticks_to_ps;
-static uint64_t hires_frequency;
-#endif
-
 /*
 * Converts a windows error to human readable string
 * uses retval as errorcode, or, if 0, use GetLastError()
@@ -283,23 +276,6 @@
 	usbi_signal_transfer_completion(itransfer);
 }
 
-static void windows_init_clock(void)
-{
-#if !defined(HAVE_CLOCK_GETTIME)
-	LARGE_INTEGER li_frequency;
-
-	// Microsoft says that the QueryPerformanceFrequency() and
-	// QueryPerformanceCounter() functions always succeed on XP and later
-	QueryPerformanceFrequency(&li_frequency);
-
-	// The hires frequency can go as high as 4 GHz, so we'll use a conversion
-	// to picoseconds to compute the tv_nsecs part in clock_gettime
-	hires_frequency = li_frequency.QuadPart;
-	hires_ticks_to_ps = UINT64_C(1000000000000) / hires_frequency;
-	usbi_dbg("hires timer frequency: %"PRIu64" Hz", hires_frequency);
-#endif
-}
-
 /* Windows version detection */
 static BOOL is_x64(void)
 {
@@ -479,8 +455,6 @@
 			goto init_exit;
 		}
 
-		windows_init_clock();
-
 		if (!htab_create(ctx)) {
 			r = LIBUSB_ERROR_NO_MEM;
 			goto init_exit;
@@ -818,50 +792,30 @@
 		return usbi_handle_transfer_completion(itransfer, status);
 }
 
-#if !defined(HAVE_CLOCK_GETTIME)
-int usbi_clock_gettime(int clk_id, struct timespec *tp)
+void usbi_get_monotonic_time(struct timespec *tp)
 {
+	static LONG hires_counter_init;
+	static uint64_t hires_ticks_to_ps;
+	static uint64_t hires_frequency;
 	LARGE_INTEGER hires_counter;
-#if !defined(_MSC_VER) || (_MSC_VER < 1900)
-	FILETIME filetime;
-	ULARGE_INTEGER rtime;
-#endif
 
-	switch (clk_id) {
-	case USBI_CLOCK_MONOTONIC:
-		if (hires_frequency) {
-			QueryPerformanceCounter(&hires_counter);
-			tp->tv_sec = (long)(hires_counter.QuadPart / hires_frequency);
-			tp->tv_nsec = (long)(((hires_counter.QuadPart % hires_frequency) * hires_ticks_to_ps) / UINT64_C(1000));
-			return 0;
-		}
-		// Return real-time if monotonic was not detected @ timer init
-		// Fall through
-	case USBI_CLOCK_REALTIME:
-#if defined(_MSC_VER) && (_MSC_VER >= 1900)
-		if (!timespec_get(tp, TIME_UTC)) {
-			errno = EIO;
-			return -1;
-		}
-#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 0;
-	default:
-		errno = EINVAL;
-		return -1;
+	if (InterlockedExchange(&hires_counter_init, 1L) == 0L) {
+		LARGE_INTEGER li_frequency;
+
+		// Microsoft says that the QueryPerformanceFrequency() and
+		// QueryPerformanceCounter() functions always succeed on XP and later
+		QueryPerformanceFrequency(&li_frequency);
+
+		// The hires frequency can go as high as 4 GHz, so we'll use a conversion
+		// to picoseconds to compute the tv_nsecs part
+		hires_frequency = li_frequency.QuadPart;
+		hires_ticks_to_ps = UINT64_C(1000000000000) / hires_frequency;
 	}
+
+	QueryPerformanceCounter(&hires_counter);
+	tp->tv_sec = (long)(hires_counter.QuadPart / hires_frequency);
+	tp->tv_nsec = (long)(((hires_counter.QuadPart % hires_frequency) * hires_ticks_to_ps) / UINT64_C(1000));
 }
-#endif
 
 // NB: MSVC6 does not support named initializers.
 const struct usbi_os_backend usbi_backend = {
diff --git a/libusb/os/windows_winusb.c b/libusb/os/windows_winusb.c
index 97215e1..393525f 100644
--- a/libusb/os/windows_winusb.c
+++ b/libusb/os/windows_winusb.c
@@ -28,7 +28,6 @@
 #include <windows.h>
 #include <setupapi.h>
 #include <ctype.h>
-#include <errno.h>
 #include <fcntl.h>
 #include <process.h>
 #include <stdio.h>
diff --git a/libusb/version_nano.h b/libusb/version_nano.h
index 83c3072..2c1248a 100644
--- a/libusb/version_nano.h
+++ b/libusb/version_nano.h
@@ -1 +1 @@
-#define LIBUSB_NANO 11557
+#define LIBUSB_NANO 11558