xref: /aosp_15_r20/external/abseil-cpp/absl/synchronization/internal/kernel_timeout.cc (revision 9356374a3709195abf420251b3e825997ff56c0f)
1*9356374aSAndroid Build Coastguard Worker // Copyright 2023 The Abseil Authors
2*9356374aSAndroid Build Coastguard Worker //
3*9356374aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*9356374aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*9356374aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*9356374aSAndroid Build Coastguard Worker //
7*9356374aSAndroid Build Coastguard Worker //     https://www.apache.org/licenses/LICENSE-2.0
8*9356374aSAndroid Build Coastguard Worker //
9*9356374aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*9356374aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*9356374aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9356374aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*9356374aSAndroid Build Coastguard Worker // limitations under the License.
14*9356374aSAndroid Build Coastguard Worker 
15*9356374aSAndroid Build Coastguard Worker #include "absl/synchronization/internal/kernel_timeout.h"
16*9356374aSAndroid Build Coastguard Worker 
17*9356374aSAndroid Build Coastguard Worker #ifndef _WIN32
18*9356374aSAndroid Build Coastguard Worker #include <sys/types.h>
19*9356374aSAndroid Build Coastguard Worker #endif
20*9356374aSAndroid Build Coastguard Worker 
21*9356374aSAndroid Build Coastguard Worker #include <algorithm>
22*9356374aSAndroid Build Coastguard Worker #include <chrono>  // NOLINT(build/c++11)
23*9356374aSAndroid Build Coastguard Worker #include <cstdint>
24*9356374aSAndroid Build Coastguard Worker #include <cstdlib>
25*9356374aSAndroid Build Coastguard Worker #include <cstring>
26*9356374aSAndroid Build Coastguard Worker #include <ctime>
27*9356374aSAndroid Build Coastguard Worker #include <limits>
28*9356374aSAndroid Build Coastguard Worker 
29*9356374aSAndroid Build Coastguard Worker #include "absl/base/attributes.h"
30*9356374aSAndroid Build Coastguard Worker #include "absl/base/call_once.h"
31*9356374aSAndroid Build Coastguard Worker #include "absl/base/config.h"
32*9356374aSAndroid Build Coastguard Worker #include "absl/time/time.h"
33*9356374aSAndroid Build Coastguard Worker 
34*9356374aSAndroid Build Coastguard Worker namespace absl {
35*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_BEGIN
36*9356374aSAndroid Build Coastguard Worker namespace synchronization_internal {
37*9356374aSAndroid Build Coastguard Worker 
38*9356374aSAndroid Build Coastguard Worker #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
39*9356374aSAndroid Build Coastguard Worker constexpr uint64_t KernelTimeout::kNoTimeout;
40*9356374aSAndroid Build Coastguard Worker constexpr int64_t KernelTimeout::kMaxNanos;
41*9356374aSAndroid Build Coastguard Worker #endif
42*9356374aSAndroid Build Coastguard Worker 
SteadyClockNow()43*9356374aSAndroid Build Coastguard Worker int64_t KernelTimeout::SteadyClockNow() {
44*9356374aSAndroid Build Coastguard Worker   if (!SupportsSteadyClock()) {
45*9356374aSAndroid Build Coastguard Worker     return absl::GetCurrentTimeNanos();
46*9356374aSAndroid Build Coastguard Worker   }
47*9356374aSAndroid Build Coastguard Worker   return std::chrono::duration_cast<std::chrono::nanoseconds>(
48*9356374aSAndroid Build Coastguard Worker              std::chrono::steady_clock::now().time_since_epoch())
49*9356374aSAndroid Build Coastguard Worker       .count();
50*9356374aSAndroid Build Coastguard Worker }
51*9356374aSAndroid Build Coastguard Worker 
KernelTimeout(absl::Time t)52*9356374aSAndroid Build Coastguard Worker KernelTimeout::KernelTimeout(absl::Time t) {
53*9356374aSAndroid Build Coastguard Worker   // `absl::InfiniteFuture()` is a common "no timeout" value and cheaper to
54*9356374aSAndroid Build Coastguard Worker   // compare than convert.
55*9356374aSAndroid Build Coastguard Worker   if (t == absl::InfiniteFuture()) {
56*9356374aSAndroid Build Coastguard Worker     rep_ = kNoTimeout;
57*9356374aSAndroid Build Coastguard Worker     return;
58*9356374aSAndroid Build Coastguard Worker   }
59*9356374aSAndroid Build Coastguard Worker 
60*9356374aSAndroid Build Coastguard Worker   int64_t unix_nanos = absl::ToUnixNanos(t);
61*9356374aSAndroid Build Coastguard Worker 
62*9356374aSAndroid Build Coastguard Worker   // A timeout that lands before the unix epoch is converted to 0.
63*9356374aSAndroid Build Coastguard Worker   // In theory implementations should expire these timeouts immediately.
64*9356374aSAndroid Build Coastguard Worker   if (unix_nanos < 0) {
65*9356374aSAndroid Build Coastguard Worker     unix_nanos = 0;
66*9356374aSAndroid Build Coastguard Worker   }
67*9356374aSAndroid Build Coastguard Worker 
68*9356374aSAndroid Build Coastguard Worker   // Values greater than or equal to kMaxNanos are converted to infinite.
69*9356374aSAndroid Build Coastguard Worker   if (unix_nanos >= kMaxNanos) {
70*9356374aSAndroid Build Coastguard Worker     rep_ = kNoTimeout;
71*9356374aSAndroid Build Coastguard Worker     return;
72*9356374aSAndroid Build Coastguard Worker   }
73*9356374aSAndroid Build Coastguard Worker 
74*9356374aSAndroid Build Coastguard Worker   rep_ = static_cast<uint64_t>(unix_nanos) << 1;
75*9356374aSAndroid Build Coastguard Worker }
76*9356374aSAndroid Build Coastguard Worker 
KernelTimeout(absl::Duration d)77*9356374aSAndroid Build Coastguard Worker KernelTimeout::KernelTimeout(absl::Duration d) {
78*9356374aSAndroid Build Coastguard Worker   // `absl::InfiniteDuration()` is a common "no timeout" value and cheaper to
79*9356374aSAndroid Build Coastguard Worker   // compare than convert.
80*9356374aSAndroid Build Coastguard Worker   if (d == absl::InfiniteDuration()) {
81*9356374aSAndroid Build Coastguard Worker     rep_ = kNoTimeout;
82*9356374aSAndroid Build Coastguard Worker     return;
83*9356374aSAndroid Build Coastguard Worker   }
84*9356374aSAndroid Build Coastguard Worker 
85*9356374aSAndroid Build Coastguard Worker   int64_t nanos = absl::ToInt64Nanoseconds(d);
86*9356374aSAndroid Build Coastguard Worker 
87*9356374aSAndroid Build Coastguard Worker   // Negative durations are normalized to 0.
88*9356374aSAndroid Build Coastguard Worker   // In theory implementations should expire these timeouts immediately.
89*9356374aSAndroid Build Coastguard Worker   if (nanos < 0) {
90*9356374aSAndroid Build Coastguard Worker     nanos = 0;
91*9356374aSAndroid Build Coastguard Worker   }
92*9356374aSAndroid Build Coastguard Worker 
93*9356374aSAndroid Build Coastguard Worker   int64_t now = SteadyClockNow();
94*9356374aSAndroid Build Coastguard Worker   if (nanos > kMaxNanos - now) {
95*9356374aSAndroid Build Coastguard Worker     // Durations that would be greater than kMaxNanos are converted to infinite.
96*9356374aSAndroid Build Coastguard Worker     rep_ = kNoTimeout;
97*9356374aSAndroid Build Coastguard Worker     return;
98*9356374aSAndroid Build Coastguard Worker   }
99*9356374aSAndroid Build Coastguard Worker 
100*9356374aSAndroid Build Coastguard Worker   nanos += now;
101*9356374aSAndroid Build Coastguard Worker   rep_ = (static_cast<uint64_t>(nanos) << 1) | uint64_t{1};
102*9356374aSAndroid Build Coastguard Worker }
103*9356374aSAndroid Build Coastguard Worker 
MakeAbsNanos() const104*9356374aSAndroid Build Coastguard Worker int64_t KernelTimeout::MakeAbsNanos() const {
105*9356374aSAndroid Build Coastguard Worker   if (!has_timeout()) {
106*9356374aSAndroid Build Coastguard Worker     return kMaxNanos;
107*9356374aSAndroid Build Coastguard Worker   }
108*9356374aSAndroid Build Coastguard Worker 
109*9356374aSAndroid Build Coastguard Worker   int64_t nanos = RawAbsNanos();
110*9356374aSAndroid Build Coastguard Worker 
111*9356374aSAndroid Build Coastguard Worker   if (is_relative_timeout()) {
112*9356374aSAndroid Build Coastguard Worker     // We need to change epochs, because the relative timeout might be
113*9356374aSAndroid Build Coastguard Worker     // represented by an absolute timestamp from another clock.
114*9356374aSAndroid Build Coastguard Worker     nanos = std::max<int64_t>(nanos - SteadyClockNow(), 0);
115*9356374aSAndroid Build Coastguard Worker     int64_t now = absl::GetCurrentTimeNanos();
116*9356374aSAndroid Build Coastguard Worker     if (nanos > kMaxNanos - now) {
117*9356374aSAndroid Build Coastguard Worker       // Overflow.
118*9356374aSAndroid Build Coastguard Worker       nanos = kMaxNanos;
119*9356374aSAndroid Build Coastguard Worker     } else {
120*9356374aSAndroid Build Coastguard Worker       nanos += now;
121*9356374aSAndroid Build Coastguard Worker     }
122*9356374aSAndroid Build Coastguard Worker   } else if (nanos == 0) {
123*9356374aSAndroid Build Coastguard Worker     // Some callers have assumed that 0 means no timeout, so instead we return a
124*9356374aSAndroid Build Coastguard Worker     // time of 1 nanosecond after the epoch.
125*9356374aSAndroid Build Coastguard Worker     nanos = 1;
126*9356374aSAndroid Build Coastguard Worker   }
127*9356374aSAndroid Build Coastguard Worker 
128*9356374aSAndroid Build Coastguard Worker   return nanos;
129*9356374aSAndroid Build Coastguard Worker }
130*9356374aSAndroid Build Coastguard Worker 
InNanosecondsFromNow() const131*9356374aSAndroid Build Coastguard Worker int64_t KernelTimeout::InNanosecondsFromNow() const {
132*9356374aSAndroid Build Coastguard Worker   if (!has_timeout()) {
133*9356374aSAndroid Build Coastguard Worker     return kMaxNanos;
134*9356374aSAndroid Build Coastguard Worker   }
135*9356374aSAndroid Build Coastguard Worker 
136*9356374aSAndroid Build Coastguard Worker   int64_t nanos = RawAbsNanos();
137*9356374aSAndroid Build Coastguard Worker   if (is_absolute_timeout()) {
138*9356374aSAndroid Build Coastguard Worker     return std::max<int64_t>(nanos - absl::GetCurrentTimeNanos(), 0);
139*9356374aSAndroid Build Coastguard Worker   }
140*9356374aSAndroid Build Coastguard Worker   return std::max<int64_t>(nanos - SteadyClockNow(), 0);
141*9356374aSAndroid Build Coastguard Worker }
142*9356374aSAndroid Build Coastguard Worker 
MakeAbsTimespec() const143*9356374aSAndroid Build Coastguard Worker struct timespec KernelTimeout::MakeAbsTimespec() const {
144*9356374aSAndroid Build Coastguard Worker   return absl::ToTimespec(absl::Nanoseconds(MakeAbsNanos()));
145*9356374aSAndroid Build Coastguard Worker }
146*9356374aSAndroid Build Coastguard Worker 
MakeRelativeTimespec() const147*9356374aSAndroid Build Coastguard Worker struct timespec KernelTimeout::MakeRelativeTimespec() const {
148*9356374aSAndroid Build Coastguard Worker   return absl::ToTimespec(absl::Nanoseconds(InNanosecondsFromNow()));
149*9356374aSAndroid Build Coastguard Worker }
150*9356374aSAndroid Build Coastguard Worker 
151*9356374aSAndroid Build Coastguard Worker #ifndef _WIN32
MakeClockAbsoluteTimespec(clockid_t c) const152*9356374aSAndroid Build Coastguard Worker struct timespec KernelTimeout::MakeClockAbsoluteTimespec(clockid_t c) const {
153*9356374aSAndroid Build Coastguard Worker   if (!has_timeout()) {
154*9356374aSAndroid Build Coastguard Worker     return absl::ToTimespec(absl::Nanoseconds(kMaxNanos));
155*9356374aSAndroid Build Coastguard Worker   }
156*9356374aSAndroid Build Coastguard Worker 
157*9356374aSAndroid Build Coastguard Worker   int64_t nanos = RawAbsNanos();
158*9356374aSAndroid Build Coastguard Worker   if (is_absolute_timeout()) {
159*9356374aSAndroid Build Coastguard Worker     nanos -= absl::GetCurrentTimeNanos();
160*9356374aSAndroid Build Coastguard Worker   } else {
161*9356374aSAndroid Build Coastguard Worker     nanos -= SteadyClockNow();
162*9356374aSAndroid Build Coastguard Worker   }
163*9356374aSAndroid Build Coastguard Worker 
164*9356374aSAndroid Build Coastguard Worker   struct timespec now;
165*9356374aSAndroid Build Coastguard Worker   ABSL_RAW_CHECK(clock_gettime(c, &now) == 0, "clock_gettime() failed");
166*9356374aSAndroid Build Coastguard Worker   absl::Duration from_clock_epoch =
167*9356374aSAndroid Build Coastguard Worker       absl::DurationFromTimespec(now) + absl::Nanoseconds(nanos);
168*9356374aSAndroid Build Coastguard Worker   if (from_clock_epoch <= absl::ZeroDuration()) {
169*9356374aSAndroid Build Coastguard Worker     // Some callers have assumed that 0 means no timeout, so instead we return a
170*9356374aSAndroid Build Coastguard Worker     // time of 1 nanosecond after the epoch. For safety we also do not return
171*9356374aSAndroid Build Coastguard Worker     // negative values.
172*9356374aSAndroid Build Coastguard Worker     return absl::ToTimespec(absl::Nanoseconds(1));
173*9356374aSAndroid Build Coastguard Worker   }
174*9356374aSAndroid Build Coastguard Worker   return absl::ToTimespec(from_clock_epoch);
175*9356374aSAndroid Build Coastguard Worker }
176*9356374aSAndroid Build Coastguard Worker #endif
177*9356374aSAndroid Build Coastguard Worker 
InMillisecondsFromNow() const178*9356374aSAndroid Build Coastguard Worker KernelTimeout::DWord KernelTimeout::InMillisecondsFromNow() const {
179*9356374aSAndroid Build Coastguard Worker   constexpr DWord kInfinite = std::numeric_limits<DWord>::max();
180*9356374aSAndroid Build Coastguard Worker 
181*9356374aSAndroid Build Coastguard Worker   if (!has_timeout()) {
182*9356374aSAndroid Build Coastguard Worker     return kInfinite;
183*9356374aSAndroid Build Coastguard Worker   }
184*9356374aSAndroid Build Coastguard Worker 
185*9356374aSAndroid Build Coastguard Worker   constexpr uint64_t kNanosInMillis = uint64_t{1'000'000};
186*9356374aSAndroid Build Coastguard Worker   constexpr uint64_t kMaxValueNanos =
187*9356374aSAndroid Build Coastguard Worker       std::numeric_limits<int64_t>::max() - kNanosInMillis + 1;
188*9356374aSAndroid Build Coastguard Worker 
189*9356374aSAndroid Build Coastguard Worker   uint64_t ns_from_now = static_cast<uint64_t>(InNanosecondsFromNow());
190*9356374aSAndroid Build Coastguard Worker   if (ns_from_now >= kMaxValueNanos) {
191*9356374aSAndroid Build Coastguard Worker     // Rounding up would overflow.
192*9356374aSAndroid Build Coastguard Worker     return kInfinite;
193*9356374aSAndroid Build Coastguard Worker   }
194*9356374aSAndroid Build Coastguard Worker   // Convert to milliseconds, always rounding up.
195*9356374aSAndroid Build Coastguard Worker   uint64_t ms_from_now = (ns_from_now + kNanosInMillis - 1) / kNanosInMillis;
196*9356374aSAndroid Build Coastguard Worker   if (ms_from_now > kInfinite) {
197*9356374aSAndroid Build Coastguard Worker     return kInfinite;
198*9356374aSAndroid Build Coastguard Worker   }
199*9356374aSAndroid Build Coastguard Worker   return static_cast<DWord>(ms_from_now);
200*9356374aSAndroid Build Coastguard Worker }
201*9356374aSAndroid Build Coastguard Worker 
202*9356374aSAndroid Build Coastguard Worker std::chrono::time_point<std::chrono::system_clock>
ToChronoTimePoint() const203*9356374aSAndroid Build Coastguard Worker KernelTimeout::ToChronoTimePoint() const {
204*9356374aSAndroid Build Coastguard Worker   if (!has_timeout()) {
205*9356374aSAndroid Build Coastguard Worker     return std::chrono::time_point<std::chrono::system_clock>::max();
206*9356374aSAndroid Build Coastguard Worker   }
207*9356374aSAndroid Build Coastguard Worker 
208*9356374aSAndroid Build Coastguard Worker   // The cast to std::microseconds is because (on some platforms) the
209*9356374aSAndroid Build Coastguard Worker   // std::ratio used by std::chrono::steady_clock doesn't convert to
210*9356374aSAndroid Build Coastguard Worker   // std::nanoseconds, so it doesn't compile.
211*9356374aSAndroid Build Coastguard Worker   auto micros = std::chrono::duration_cast<std::chrono::microseconds>(
212*9356374aSAndroid Build Coastguard Worker       std::chrono::nanoseconds(MakeAbsNanos()));
213*9356374aSAndroid Build Coastguard Worker   return std::chrono::system_clock::from_time_t(0) + micros;
214*9356374aSAndroid Build Coastguard Worker }
215*9356374aSAndroid Build Coastguard Worker 
ToChronoDuration() const216*9356374aSAndroid Build Coastguard Worker std::chrono::nanoseconds KernelTimeout::ToChronoDuration() const {
217*9356374aSAndroid Build Coastguard Worker   if (!has_timeout()) {
218*9356374aSAndroid Build Coastguard Worker     return std::chrono::nanoseconds::max();
219*9356374aSAndroid Build Coastguard Worker   }
220*9356374aSAndroid Build Coastguard Worker   return std::chrono::nanoseconds(InNanosecondsFromNow());
221*9356374aSAndroid Build Coastguard Worker }
222*9356374aSAndroid Build Coastguard Worker 
223*9356374aSAndroid Build Coastguard Worker }  // namespace synchronization_internal
224*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_END
225*9356374aSAndroid Build Coastguard Worker }  // namespace absl
226