1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <sys/time.h>
6 
7 #include <cstdint>
8 #include <ctime>
9 
10 #include "build/build_config.h"
11 #include "partition_alloc/partition_alloc_base/time/time.h"
12 #if BUILDFLAG(IS_ANDROID) && !defined(__LP64__)
13 #include <time64.h>
14 #endif
15 #include <unistd.h>
16 
17 #include "partition_alloc/partition_alloc_base/check.h"
18 #include "partition_alloc/partition_alloc_base/notreached.h"
19 #include "partition_alloc/partition_alloc_base/numerics/safe_math.h"
20 #include "partition_alloc/partition_alloc_base/time/time_override.h"
21 
22 // Ensure the Fuchsia and Mac builds do not include this module. Instead,
23 // non-POSIX implementation is used for sampling the system clocks.
24 #if BUILDFLAG(IS_FUCHSIA) || BUILDFLAG(IS_APPLE)
25 #error "This implementation is for POSIX platforms other than Fuchsia or Mac."
26 #endif
27 
28 namespace partition_alloc::internal::base {
29 
30 namespace {
31 
ConvertTimespecToMicros(const struct timespec & ts)32 int64_t ConvertTimespecToMicros(const struct timespec& ts) {
33   // On 32-bit systems, the calculation cannot overflow int64_t.
34   // 2**32 * 1000000 + 2**64 / 1000 < 2**63
35   if (sizeof(ts.tv_sec) <= 4 && sizeof(ts.tv_nsec) <= 8) {
36     int64_t result = ts.tv_sec;
37     result *= Time::kMicrosecondsPerSecond;
38     result += (ts.tv_nsec / Time::kNanosecondsPerMicrosecond);
39     return result;
40   }
41   CheckedNumeric<int64_t> result(ts.tv_sec);
42   result *= Time::kMicrosecondsPerSecond;
43   result += (ts.tv_nsec / Time::kNanosecondsPerMicrosecond);
44   return result.ValueOrDie();
45 }
46 
47 // Helper function to get results from clock_gettime() and convert to a
48 // microsecond timebase. Minimum requirement is MONOTONIC_CLOCK to be supported
49 // on the system. FreeBSD 6 has CLOCK_MONOTONIC but defines
50 // _POSIX_MONOTONIC_CLOCK to -1.
51 #if (BUILDFLAG(IS_POSIX) && defined(_POSIX_MONOTONIC_CLOCK) && \
52      _POSIX_MONOTONIC_CLOCK >= 0) ||                           \
53     BUILDFLAG(IS_BSD) || BUILDFLAG(IS_ANDROID)
ClockNow(clockid_t clk_id)54 int64_t ClockNow(clockid_t clk_id) {
55   struct timespec ts;
56   PA_BASE_CHECK(clock_gettime(clk_id, &ts) == 0);
57   return ConvertTimespecToMicros(ts);
58 }
59 #else  // _POSIX_MONOTONIC_CLOCK
60 #error No usable tick clock function on this platform.
61 #endif  // _POSIX_MONOTONIC_CLOCK
62 
63 }  // namespace
64 
65 // Time -----------------------------------------------------------------------
66 
67 namespace subtle {
TimeNowIgnoringOverride()68 Time TimeNowIgnoringOverride() {
69   struct timeval tv;
70   struct timezone tz = {0, 0};  // UTC
71   PA_BASE_CHECK(gettimeofday(&tv, &tz) == 0);
72   // Combine seconds and microseconds in a 64-bit field containing microseconds
73   // since the epoch.  That's enough for nearly 600 centuries.  Adjust from
74   // Unix (1970) to Windows (1601) epoch.
75   return Time() +
76          Microseconds((tv.tv_sec * Time::kMicrosecondsPerSecond + tv.tv_usec) +
77                       Time::kTimeTToMicrosecondsOffset);
78 }
79 
TimeNowFromSystemTimeIgnoringOverride()80 Time TimeNowFromSystemTimeIgnoringOverride() {
81   // Just use TimeNowIgnoringOverride() because it returns the system time.
82   return TimeNowIgnoringOverride();
83 }
84 }  // namespace subtle
85 
86 // TimeTicks ------------------------------------------------------------------
87 
88 namespace subtle {
TimeTicksNowIgnoringOverride()89 TimeTicks TimeTicksNowIgnoringOverride() {
90   return TimeTicks() + Microseconds(ClockNow(CLOCK_MONOTONIC));
91 }
92 }  // namespace subtle
93 
94 // static
GetClock()95 TimeTicks::Clock TimeTicks::GetClock() {
96   return Clock::LINUX_CLOCK_MONOTONIC;
97 }
98 
99 // static
IsHighResolution()100 bool TimeTicks::IsHighResolution() {
101   return true;
102 }
103 
104 // static
IsConsistentAcrossProcesses()105 bool TimeTicks::IsConsistentAcrossProcesses() {
106   return true;
107 }
108 
109 // ThreadTicks ----------------------------------------------------------------
110 
111 namespace subtle {
ThreadTicksNowIgnoringOverride()112 ThreadTicks ThreadTicksNowIgnoringOverride() {
113 #if (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \
114     BUILDFLAG(IS_ANDROID)
115   return ThreadTicks() + Microseconds(ClockNow(CLOCK_THREAD_CPUTIME_ID));
116 #else
117   PA_NOTREACHED();
118 #endif
119 }
120 }  // namespace subtle
121 
122 }  // namespace partition_alloc::internal::base
123