Move the clock details over to the Time.h portability header
authorChristopher Dykes <cdykes@fb.com>
Wed, 23 Mar 2016 17:10:36 +0000 (10:10 -0700)
committerFacebook Github Bot 2 <facebook-github-bot-2-bot@fb.com>
Wed, 23 Mar 2016 17:20:24 +0000 (10:20 -0700)
Summary: Because things belong places.

Reviewed By: mzlee

Differential Revision: D3077737

fb-gh-sync-id: 966f37df722ae737481d776ff1c9b0d5132b7a58
shipit-source-id: 966f37df722ae737481d776ff1c9b0d5132b7a58

folly/Makefile.am
folly/Portability.h
folly/detail/Clock.cpp [deleted file]
folly/detail/Clock.h [deleted file]
folly/portability/Time.cpp
folly/portability/Time.h

index f9906987164ddc47147b23d25087aaaec24a5423..83d623a84078ee97ef147c050c8d590c40a89e55 100644 (file)
@@ -53,7 +53,6 @@ nobase_follyinclude_HEADERS = \
        detail/BitsDetail.h \
        detail/CacheLocality.h \
        detail/ChecksumDetail.h \
-       detail/Clock.h \
        detail/DiscriminatedPtrDetail.h \
        detail/ExceptionWrapper.h \
        detail/FileUtilDetail.h \
@@ -456,10 +455,6 @@ libfolly_la_SOURCES += \
        experimental/io/HugePages.cpp
 endif
 
-if !HAVE_LINUX
-libfollybase_la_SOURCES += detail/Clock.cpp
-endif
-
 if !HAVE_WEAK_SYMBOLS
 libfollybase_la_SOURCES += detail/MallocImpl.cpp
 endif
index 363fe3041018aaf9ee493130e88dbdad7be52a05..1da837e883c9b1df6a6ee6a6591197e53ec78e84 100644 (file)
@@ -246,14 +246,6 @@ namespace std { typedef ::max_align_t max_align_t; }
 # define FOLLY_GLIBCXX_NAMESPACE_CXX11_END
 #endif
 
-// Some platforms lack clock_gettime(2) and clock_getres(2). Inject our own
-// versions of these into the global namespace.
-#if FOLLY_HAVE_CLOCK_GETTIME
-#include <time.h>
-#else
-#include <folly/detail/Clock.h>
-#endif
-
 // Provide our own std::__throw_* wrappers for platforms that don't have them
 #if FOLLY_HAVE_BITS_FUNCTEXCEPT_H
 #include <bits/functexcept.h>
diff --git a/folly/detail/Clock.cpp b/folly/detail/Clock.cpp
deleted file mode 100644 (file)
index d861d88..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright 2016 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <folly/detail/Clock.h>
-
-#if __MACH__
-#include <errno.h>
-#include <mach/mach_time.h>
-
-namespace {
-
-const mach_timebase_info_data_t* tbInfo() {
-  static auto info = [] {
-    static mach_timebase_info_data_t info;
-    return (mach_timebase_info(&info) == KERN_SUCCESS) ? &info : nullptr;
-  }();
-  return info;
-};
-
-}  // anonymous namespace
-
-int clock_gettime(clockid_t clk_id, struct timespec* ts) {
-  auto tb_info = tbInfo();
-  if (tb_info == nullptr) {
-    errno = EINVAL;
-    return -1;
-  }
-
-  uint64_t now_ticks = mach_absolute_time();
-  uint64_t now_ns = (now_ticks * tb_info->numer) / tb_info->denom;
-  ts->tv_sec = now_ns / 1000000000;
-  ts->tv_nsec = now_ns % 1000000000;
-
-  return 0;
-}
-
-int clock_getres(clockid_t clk_id, struct timespec* ts) {
-  auto tb_info = tbInfo();
-  if (tb_info == nullptr) {
-    errno = EINVAL;
-    return -1;
-  }
-
-  ts->tv_sec = 0;
-  ts->tv_nsec = tb_info->numer / tb_info->denom;
-
-  return 0;
-}
-#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
-#else
-#error No clock_gettime(2) compatibility wrapper available for this platform.
-#endif
diff --git a/folly/detail/Clock.h b/folly/detail/Clock.h
deleted file mode 100644 (file)
index d7da926..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2016 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef FOLLY_DETAIL_CLOCK_H_
-#define FOLLY_DETAIL_CLOCK_H_
-
-#include <ctime>
-#include <cstdint>
-
-#include <folly/Portability.h>
-
-#if FOLLY_HAVE_CLOCK_GETTIME
-#error This should only be used as a workaround for platforms \
-          that do not support clock_gettime(2).
-#endif
-
-/* For windows, we'll use pthread's time implementations */
-#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);
-#endif
-
-#endif /* FOLLY_DETAIL_CLOCK_H_ */
index 0a06abdbe09d92bea935fb77fd1274053d783a9d..56bfb79a8566b7b6e42d1ea49497d79c97d8754c 100755 (executable)
 
 #include <folly/portability/Time.h>
 
+#if !FOLLY_HAVE_CLOCK_GETTIME
+#if __MACH__
+#include <errno.h>
+#include <mach/mach_time.h>
+
+static const mach_timebase_info_data_t* tbInfo() {
+  static auto info = [] {
+    static mach_timebase_info_data_t info;
+    return (mach_timebase_info(&info) == KERN_SUCCESS) ? &info : nullptr;
+  }();
+  return info;
+}
+
+int clock_gettime(clockid_t clk_id, struct timespec* ts) {
+  auto tb_info = tbInfo();
+  if (tb_info == nullptr) {
+    errno = EINVAL;
+    return -1;
+  }
+
+  uint64_t now_ticks = mach_absolute_time();
+  uint64_t now_ns = (now_ticks * tb_info->numer) / tb_info->denom;
+  ts->tv_sec = now_ns / 1000000000;
+  ts->tv_nsec = now_ns % 1000000000;
+
+  return 0;
+}
+
+int clock_getres(clockid_t clk_id, struct timespec* ts) {
+  auto tb_info = tbInfo();
+  if (tb_info == nullptr) {
+    errno = EINVAL;
+    return -1;
+  }
+
+  ts->tv_sec = 0;
+  ts->tv_nsec = tb_info->numer / tb_info->denom;
+
+  return 0;
+}
+#elif defined(_WIN32)
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <folly/portability/Windows.h>
+
+static constexpr size_t kNsPerSec = 1000000000;
+
+extern "C" int clock_getres(clockid_t clock_id, struct timespec* res) {
+  if (!res) {
+    errno = EFAULT;
+    return -1;
+  }
+
+  switch (clock_id) {
+    case CLOCK_MONOTONIC: {
+      LARGE_INTEGER freq;
+      if (!QueryPerformanceFrequency(&freq)) {
+        errno = EINVAL;
+        return -1;
+      }
+
+      res->tv_sec = 0;
+      res->tv_nsec = (long)((kNsPerSec + (freq.QuadPart >> 1)) / freq.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 adj, timeIncrement;
+      BOOL adjDisabled;
+      if (!GetSystemTimeAdjustment(&adj, &timeIncrement, &adjDisabled)) {
+        errno = EINVAL;
+        return -1;
+      }
+
+      res->tv_sec = 0;
+      res->tv_nsec = timeIncrement * 100;
+      return 0;
+    }
+
+    default:
+      errno = EINVAL;
+      return -1;
+  }
+}
+
+extern "C" int clock_gettime(clockid_t clock_id, struct timespec* tp) {
+  if (!tp) {
+    errno = EFAULT;
+    return -1;
+  }
+
+  const auto ftToUint = [](FILETIME ft) -> uint64_t {
+    ULARGE_INTEGER i;
+    i.HighPart = ft.dwHighDateTime;
+    i.LowPart = ft.dwLowDateTime;
+    return i.QuadPart;
+  };
+  const auto timeToTimespec = [](timespec* tp, uint64_t t) -> int {
+    constexpr size_t k100NsPerSec = kNsPerSec / 100;
+
+    // The filetimes t is based on are represented in
+    // 100ns's. (ie. a value of 4 is 400ns)
+    tp->tv_sec = t / k100NsPerSec;
+    tp->tv_nsec = ((long)(t % k100NsPerSec)) * 100;
+    return 0;
+  };
+
+  FILETIME createTime, exitTime, kernalTime, userTime;
+  switch (clock_id) {
+    case CLOCK_REALTIME: {
+      constexpr size_t kDeltaEpochIn100NS = 116444736000000000ULL;
+
+      GetSystemTimeAsFileTime(&createTime);
+      return timeToTimespec(tp, ftToUint(createTime) - kDeltaEpochIn100NS);
+    }
+    case CLOCK_PROCESS_CPUTIME_ID: {
+      if (!GetProcessTimes(
+              GetCurrentProcess(),
+              &createTime,
+              &exitTime,
+              &kernalTime,
+              &userTime)) {
+        errno = EINVAL;
+        return -1;
+      }
+
+      return timeToTimespec(tp, ftToUint(kernalTime) + ftToUint(userTime));
+    }
+    case CLOCK_THREAD_CPUTIME_ID: {
+      if (!GetThreadTimes(
+              GetCurrentThread(),
+              &createTime,
+              &exitTime,
+              &kernalTime,
+              &userTime)) {
+        errno = EINVAL;
+        return -1;
+      }
+
+      return timeToTimespec(tp, ftToUint(kernalTime) + ftToUint(userTime));
+    }
+    case CLOCK_MONOTONIC: {
+      LARGE_INTEGER fl, cl;
+      if (!QueryPerformanceFrequency(&fl) || !QueryPerformanceCounter(&cl)) {
+        errno = EINVAL;
+        return -1;
+      }
+
+      int64_t freq = fl.QuadPart;
+      int64_t counter = cl.QuadPart;
+      tp->tv_sec = counter / freq;
+      tp->tv_nsec = (long)(((counter % freq) * kNsPerSec + (freq >> 1)) / freq);
+      if (tp->tv_nsec >= kNsPerSec) {
+        tp->tv_sec++;
+        tp->tv_nsec -= kNsPerSec;
+      }
+
+      return 0;
+    }
+
+    default:
+      errno = EINVAL;
+      return -1;
+  }
+}
+#else
+#error No clock_gettime(3) compatibility wrapper available for this platform.
+#endif
+#endif
+
 #ifdef _WIN32
 #include <iomanip>
 #include <sstream>
 
-#include <Windows.h>
+#include <folly/portability/Windows.h>
 
 extern "C" {
 char* asctime_r(const tm* tm, char* buf) {
index 0a35b23fd88d0eba6a37c8d6071466f66c584c78..1980377f92b05f20eb973900ab72996e012e7f16 100755 (executable)
 
 #include <time.h>
 
+#include <folly/portability/Config.h>
+
+// These aren't generic implementations, so we can only declare them on
+// platforms we support.
+#if !FOLLY_HAVE_CLOCK_GETTIME && (defined(__MACH__) || defined(_WIN32))
+#define CLOCK_REALTIME 0
+// The Windows implementation supports a few other
+// clock types as well.
+#ifdef _WIN32
+# define CLOCK_MONOTONIC 1
+# define CLOCK_PROCESS_CPUTIME_ID 2
+# define CLOCK_THREAD_CPUTIME_ID 3
+#endif
+
+typedef uint8_t clockid_t;
+extern "C" int clock_gettime(clockid_t clk_id, struct timespec* ts);
+extern "C" int clock_getres(clockid_t clk_id, struct timespec* ts);
+#endif
+
 #ifdef _WIN32
 #define TM_YEAR_BASE (1900)