1 /*
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <folly/ClockGettimeWrappers.h>
18
19 #include <folly/CPortability.h>
20 #include <folly/Likely.h>
21 #include <folly/portability/Time.h>
22
23 #include <chrono>
24
25 #include <ctime>
26
27 #ifndef _WIN32
28 #define _GNU_SOURCE 1
29 #include <dlfcn.h>
30 #endif
31
32 namespace folly {
33 namespace chrono {
34
clock_gettime_ns_fallback(clockid_t clock)35 static int64_t clock_gettime_ns_fallback(clockid_t clock) {
36 struct timespec ts;
37 int r = clock_gettime(clock, &ts);
38 if (UNLIKELY(r != 0)) {
39 // Mimic what __clock_gettime_ns does (even though this can be a legit
40 // value).
41 return -1;
42 }
43 std::chrono::nanoseconds result =
44 std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec);
45 return result.count();
46 }
47
48 // Initialize with default behavior, which we might override on Linux hosts
49 // with VDSO support.
50 int (*clock_gettime)(clockid_t, timespec* ts) = &::clock_gettime;
51 int64_t (*clock_gettime_ns)(clockid_t) = &clock_gettime_ns_fallback;
52
53 // In MSAN mode use glibc's versions as they are intercepted by the MSAN
54 // runtime which properly tracks memory initialization.
55 #if defined(FOLLY_HAVE_LINUX_VDSO) && !defined(FOLLY_SANITIZE_MEMORY)
56
57 namespace {
58
59 struct VdsoInitializer {
VdsoInitializerfolly::chrono::__anon3af241700111::VdsoInitializer60 VdsoInitializer() {
61 m_handle = dlopen("linux-vdso.so.1", RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
62 if (!m_handle) {
63 return;
64 }
65
66 void* p = dlsym(m_handle, "__vdso_clock_gettime");
67 if (p) {
68 folly::chrono::clock_gettime = (int (*)(clockid_t, timespec*))p;
69 }
70 p = dlsym(m_handle, "__vdso_clock_gettime_ns");
71 if (p) {
72 folly::chrono::clock_gettime_ns = (int64_t(*)(clockid_t))p;
73 }
74 }
75
~VdsoInitializerfolly::chrono::__anon3af241700111::VdsoInitializer76 ~VdsoInitializer() {
77 if (m_handle) {
78 clock_gettime = &::clock_gettime;
79 clock_gettime_ns = &clock_gettime_ns_fallback;
80 dlclose(m_handle);
81 }
82 }
83
84 private:
85 void* m_handle;
86 };
87
88 const VdsoInitializer vdso_initializer;
89 } // namespace
90
91 #endif
92 } // namespace chrono
93 } // namespace folly
94