Implement clock_getres for Windows
authorOrvid King <blah38621@gmail.com>
Mon, 14 Sep 2015 22:53:54 +0000 (15:53 -0700)
committerfacebook-github-bot-1 <folly-bot@fb.com>
Mon, 14 Sep 2015 23:20:21 +0000 (16:20 -0700)
Summary: Because the windows version of pthread very definitely does not implement the clock. The Cygwin and MinGW headers might, so let them still fall back to the pthread includes.
Closes https://github.com/facebook/folly/pull/280

Reviewed By: @yfeldblum

Differential Revision: D2419067

Pulled By: @JoelMarcey

folly/detail/Clock.cpp
folly/detail/Clock.h

index d44a81c03e5b98d5eaca0eeb2b58cfaf4a33d5d3..855645c46fdede97de6c1ca197854f5281021ae7 100644 (file)
@@ -48,7 +48,136 @@ int clock_getres(clockid_t clk_id, struct timespec* ts) {
 
   return 0;
 }
-#elif _MSC_VER
+#elif defined(_MSC_VER)
+// The MSVC version has been extracted from the pthreads implemenation here:
+// https://github.com/songdongsheng/libpthread
+// Copyright(c) 2011, Dongsheng Song <songdongsheng@live.cn>
+//
+// It is under the Apache License Version 2.0, just as the rest of the file is.
+// It has been mostly stripped down to what we have.
+
+#include <WinSock2.h>
+
+#define DELTA_EPOCH_IN_100NS    INT64_C(116444736000000000)
+#define POW10_7     INT64_C(10000000)
+#define POW10_9     INT64_C(1000000000)
+
+int clock_getres(clockid_t clock_id, struct timespec *res)
+{
+  switch (clock_id) {
+    case CLOCK_MONOTONIC:
+    {
+      LARGE_INTEGER pf;
+
+      if (QueryPerformanceFrequency(&pf) == 0)
+        return -1;
+
+      res->tv_sec = 0;
+      res->tv_nsec = (int)((POW10_9 + (pf.QuadPart >> 1)) / pf.QuadPart);
+      if (res->tv_nsec < 1)
+        res->tv_nsec = 1;
+
+      return 0;
+    }
+
+    case CLOCK_REALTIME:
+    case CLOCK_PROCESS_CPUTIME_ID:
+    case CLOCK_THREAD_CPUTIME_ID:
+    {
+      DWORD   timeAdjustment, timeIncrement;
+      BOOL    isTimeAdjustmentDisabled;
+
+      (void)GetSystemTimeAdjustment(
+        &timeAdjustment,
+        &timeIncrement,
+        &isTimeAdjustmentDisabled
+      );
+      res->tv_sec = 0;
+      res->tv_nsec = timeIncrement * 100;
+
+      return 0;
+    }
+    default:
+      break;
+  }
+
+  return -1;
+}
+
+int clock_gettime(clockid_t clock_id, struct timespec *tp)
+{
+  unsigned __int64 t;
+  LARGE_INTEGER pf, pc;
+  union {
+    unsigned __int64 u64;
+    FILETIME ft;
+  }  ct, et, kt, ut;
+
+  switch (clock_id) {
+    case CLOCK_REALTIME:
+    {
+      GetSystemTimeAsFileTime(&ct.ft);
+      t = ct.u64 - DELTA_EPOCH_IN_100NS;
+      tp->tv_sec = t / POW10_7;
+      tp->tv_nsec = ((int)(t % POW10_7)) * 100;
+
+      return 0;
+    }
+
+    case CLOCK_MONOTONIC:
+    {
+      if (QueryPerformanceFrequency(&pf) == 0)
+        return -1;
+
+      if (QueryPerformanceCounter(&pc) == 0)
+        return -1;
+
+      tp->tv_sec = pc.QuadPart / pf.QuadPart;
+      tp->tv_nsec = (int)(
+        ((pc.QuadPart % pf.QuadPart) * POW10_9 + (pf.QuadPart >> 1)) /
+        pf.QuadPart
+      );
+      if (tp->tv_nsec >= POW10_9) {
+        tp->tv_sec++;
+        tp->tv_nsec -= POW10_9;
+      }
+
+      return 0;
+    }
+
+    case CLOCK_PROCESS_CPUTIME_ID:
+    {
+      if (0 == GetProcessTimes(GetCurrentProcess(),
+                               &ct.ft, &et.ft, &kt.ft, &ut.ft)) {
+        return -1;
+      }
+      t = kt.u64 + ut.u64;
+      tp->tv_sec = t / POW10_7;
+      tp->tv_nsec = ((int)(t % POW10_7)) * 100;
+
+      return 0;
+    }
+
+    case CLOCK_THREAD_CPUTIME_ID:
+    {
+      if (0 == GetThreadTimes(GetCurrentThread(),
+                              &ct.ft, &et.ft, &kt.ft, &ut.ft)) {
+        return -1;
+      }
+      t = kt.u64 + ut.u64;
+      tp->tv_sec = t / POW10_7;
+      tp->tv_nsec = ((int)(t % POW10_7)) * 100;
+
+      return 0;
+    }
+
+    default:
+      break;
+  }
+
+  return -1;
+}
+#elif defined(__CYGWIN__) || defined(__MINGW__)
 // using winpthreads from mingw-w64
 // <pthreads_time.h> has clock_gettime and friends
 // make sure to include <pthread.h> as well for typedefs of timespec/etc
index de7130d363851903153cc1b97a61e447185e5aa5..a090b66b20f40236b4f0406b2726900dfe84a4fc 100644 (file)
 #endif
 
 /* For windows, we'll use pthread's time implementations */
-#ifdef _MSC_VER
+#if defined(__CYGWIN__) || defined(__MINGW__)
 #include <pthread.h>
 #include <pthread_time.h>
 #else
 typedef uint8_t clockid_t;
 #define CLOCK_REALTIME 0
+#ifdef _MSC_VER
+#define CLOCK_MONOTONIC 1
+#define CLOCK_PROCESS_CPUTIME_ID 2
+#define CLOCK_THREAD_CPUTIME_ID 3
+#endif
 
 int clock_gettime(clockid_t clk_id, struct timespec* ts);
 int clock_getres(clockid_t clk_id, struct timespec* ts);