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