detail/BitsDetail.h \
detail/CacheLocality.h \
detail/ChecksumDetail.h \
- detail/Clock.h \
detail/DiscriminatedPtrDetail.h \
detail/ExceptionWrapper.h \
detail/FileUtilDetail.h \
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
# 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>
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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_ */
#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) {
#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)