+#ifndef _WIN32
+
+/* Timing abstraction */
+
+struct time {
+ struct timeval tv;
+};
+
+struct timeout {
+ unsigned int ms;
+ struct time start, delta, now, end;
+ struct timeval delta_tv;
+ bool overflow;
+};
+
+#define TIME_ZERO {.tv = {0, 0}}
+#define TIME_MS(ms) {.tv = {ms / 1000, (ms % 1000) * 1000}}
+
+const struct time max_delta = TIME_MS(INT_MAX);
+
+static void time_get(struct time *time)
+{
+#ifdef HAVE_CLOCK_GETTIME
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
+ clock_gettime(CLOCK_REALTIME, &ts);
+ time->tv.tv_sec = ts.tv_sec;
+ time->tv.tv_usec = ts.tv_nsec / 1000;
+#elif defined(__APPLE__)
+ mach_timebase_info_data_t info;
+ mach_timebase_info(&info);
+ uint64_t ticks = mach_absolute_time();
+ uint64_t ns = (ticks * info.numer) / info.denom;
+ time->tv.tv_sec = ns / 1000000000;
+ time->tv.tv_usec = (ns % 1000000000) / 1000;
+#else
+ gettimeofday(&time->tv, NULL);
+#endif
+}
+
+static void time_set_ms(struct time *time, unsigned int ms)
+{
+ time->tv.tv_sec = ms / 1000;
+ time->tv.tv_usec = (ms % 1000) * 1000;
+}
+
+static void time_add(const struct time *a,
+ const struct time *b, struct time *result)
+{
+ timeradd(&a->tv, &b->tv, &result->tv);
+}
+
+static void time_sub(const struct time *a,
+ const struct time *b, struct time *result)
+{
+ timersub(&a->tv, &b->tv, &result->tv);
+}
+
+static bool time_greater(const struct time *a, const struct time *b)
+{
+ return timercmp(&a->tv, &b->tv, >);
+}
+
+static void time_as_timeval(const struct time *time, struct timeval *tv)
+{
+ *tv = time->tv;
+}
+
+static unsigned int time_as_ms(const struct time *time)
+{
+ return time->tv.tv_sec * 1000 + time->tv.tv_usec / 1000;
+}
+
+static void timeout_start(struct timeout *timeout, unsigned int timeout_ms)
+{
+ timeout->ms = timeout_ms;
+
+ timeout->overflow = (timeout->ms > INT_MAX);
+
+ /* Get time at start of operation. */
+ time_get(&timeout->start);
+ /* Define duration of timeout. */
+ time_set_ms(&timeout->delta, timeout_ms);
+ /* Calculate time at which we should give up. */
+ time_add(&timeout->start, &timeout->delta, &timeout->end);
+}
+
+static bool timeout_check(struct timeout *timeout)
+{
+ if (timeout->ms == 0)
+ return false;
+
+ time_get(&timeout->now);
+ time_sub(&timeout->end, &timeout->now, &timeout->delta);
+ if ((timeout->overflow = time_greater(&timeout->delta, &max_delta)))
+ timeout->delta = max_delta;
+
+ return time_greater(&timeout->now, &timeout->end);
+}
+
+static struct timeval *timeout_timeval(struct timeout *timeout)
+{
+ if (timeout->ms == 0)
+ return NULL;
+
+ time_as_timeval(&timeout->delta, &timeout->delta_tv);
+
+ return &timeout->delta_tv;
+}
+
+static unsigned int timeout_remaining_ms(struct timeout *timeout)
+{
+ if (timeout->ms == 0)
+ return -1;
+ else if (timeout->overflow)
+ return INT_MAX;
+ else
+ return time_as_ms(&timeout->delta);
+}
+
+#endif
+