Commit 703c7309c23aab1e5b1f4b1be5756c9b8cf6c0a5

Con Kolivas 2013-08-18T14:26:41

Make the cgsleep functions build on windows.

diff --git a/configure.ac b/configure.ac
index ddf5cae..938e589 100644
--- a/configure.ac
+++ b/configure.ac
@@ -88,6 +88,7 @@ case $target in
     DLOPEN_FLAGS=""
     WS2_LIBS="-lws2_32"
     MM_LIBS="-lwinmm"
+    RT_LIBS=""
     AC_DEFINE([_WIN32_WINNT], [0x0501], "WinNT version for XP+ support")
     ;;
   powerpc-*-darwin*)
diff --git a/util.c b/util.c
index a84d278..6537582 100644
--- a/util.c
+++ b/util.c
@@ -885,83 +885,111 @@ void timeraddspec(struct timespec *a, const struct timespec *b)
 
 /* These are cgminer specific sleep functions that use an absolute nanosecond
  * resolution timer to avoid pool usleep accuracy and overruns. */
-void cgsleep_ms(int ms)
+#ifdef CLOCK_MONOTONIC
+void cgsleep_prepare_r(struct timespec *ts_start)
+{
+	clock_gettime(CLOCK_MONOTONIC, ts_start);
+}
+
+static void nanosleep_abstime(struct timespec *ts_end)
 {
-	struct timespec ts_start, ts_end;
 	int ret;
 
-#ifdef WIN32
-	timeBeginPeriod(1);
-#endif
-	clock_gettime(CLOCK_MONOTONIC, &ts_start);
-	ms_to_timespec(&ts_end, ms);
-	timeraddspec(&ts_end, &ts_start);
 	do {
-		ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts_end, NULL);
+		ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, ts_end, NULL);
 	} while (ret == EINTR);
-#ifdef WIN32
-	timeEndPeriod(1);
-#endif
 }
-
-void cgsleep_us(int64_t us)
+#else
+void cgsleep_prepare_r(struct timespec *ts_start)
 {
-	struct timespec ts_start, ts_end;
-	int ret;
+	struct timeval tv_start;
 
 #ifdef WIN32
 	timeBeginPeriod(1);
 #endif
-	clock_gettime(CLOCK_MONOTONIC, &ts_start);
-	us_to_timespec(&ts_end, us);
-	timeraddspec(&ts_end, &ts_start);
-	do {
-		ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts_end, NULL);
-	} while (ret == EINTR);
+	gettimeofday(&tv_start, NULL);
+	timeval_to_spec(ts_start, &tv_start);
+}
+
+static uint64_t timespec_to_ns(struct timespec *ts)
+{
+	uint64_t ret;
+
+	ret = (uint64_t)ts->tv_sec * 1000000000;
+	ret += ts->tv_nsec;
+	return ret;
+}
+
+static uint64_t timeval_to_ns(struct timeval *tv)
+{
+	uint64_t ret;
+
+	ret = (uint64_t)tv->tv_sec * 1000000000;
+	ret += tv->tv_usec * 1000;
+	return ret;
+}
+
+static void ns_to_timespec(struct timespec *ts, uint64_t ns)
+{
+	ts->tv_sec = ns / 1000000000;
+	ts->tv_nsec = ns - ((uint64_t)ts->tv_sec * 1000000000ull);
+}
+
+static void nanosleep_abstime(struct timespec *ts_end)
+{
+	uint64_t now_ns, end_ns, diff_ns;
+	struct timespec ts_diff;
+	struct timeval now;
+
+	end_ns = timespec_to_ns(ts_end);
+	gettimeofday(&now, NULL);
+	now_ns = timeval_to_ns(&now);
+	if (unlikely(now_ns >= end_ns))
+		return;
+	diff_ns = end_ns - now_ns;
+	ns_to_timespec(&ts_diff, diff_ns);
+	nanosleep(&ts_diff, NULL);
 #ifdef WIN32
 	timeEndPeriod(1);
 #endif
 }
+#endif
 
 /* Reentrant version of cgsleep functions allow start time to be set separately
  * from the beginning of the actual sleep, allowing scheduling delays to be
  * counted in the sleep. */
-void cgsleep_prepare_r(struct timespec *ts_start)
-{
-#ifdef WIN32
-	timeBeginPeriod(1);
-#endif
-	clock_gettime(CLOCK_MONOTONIC, ts_start);
-}
-
 void cgsleep_ms_r(struct timespec *ts_start, int ms)
 {
 	struct timespec ts_end;
-	int ret;
 
 	ms_to_timespec(&ts_end, ms);
 	timeraddspec(&ts_end, ts_start);
-	do {
-		ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts_end, NULL);
-	} while (ret == EINTR);
-#ifdef WIN32
-	timeEndPeriod(1);
-#endif
+	nanosleep_abstime(&ts_end);
 }
 
 void cgsleep_us_r(struct timespec *ts_start, int us)
 {
 	struct timespec ts_end;
-	int ret;
 
 	us_to_timespec(&ts_end, us);
 	timeraddspec(&ts_end, ts_start);
-	do {
-		ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts_end, NULL);
-	} while (ret == EINTR);
-#ifdef WIN32
-	timeEndPeriod(1);
-#endif
+	nanosleep_abstime(&ts_end);
+}
+
+void cgsleep_ms(int ms)
+{
+	struct timespec ts_start;
+
+	cgsleep_prepare_r(&ts_start);
+	cgsleep_ms_r(&ts_start, ms);
+}
+
+void cgsleep_us(int64_t us)
+{
+	struct timespec ts_start;
+
+	cgsleep_prepare_r(&ts_start);
+	cgsleep_us_r(&ts_start, us);
 }
 
 /* Provide a ms based sleep that uses nanosleep to avoid poor usleep accuracy