/src/abseil-cpp/absl/synchronization/internal/kernel_timeout.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2017 The Abseil Authors. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #ifndef ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_ |
16 | | #define ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_ |
17 | | |
18 | | #ifndef _WIN32 |
19 | | #include <sys/types.h> |
20 | | #endif |
21 | | |
22 | | #include <algorithm> |
23 | | #include <chrono> // NOLINT(build/c++11) |
24 | | #include <cstdint> |
25 | | #include <ctime> |
26 | | #include <limits> |
27 | | |
28 | | #include "absl/base/config.h" |
29 | | #include "absl/base/internal/raw_logging.h" |
30 | | #include "absl/time/clock.h" |
31 | | #include "absl/time/time.h" |
32 | | |
33 | | namespace absl { |
34 | | ABSL_NAMESPACE_BEGIN |
35 | | namespace synchronization_internal { |
36 | | |
37 | | // An optional timeout, with nanosecond granularity. |
38 | | // |
39 | | // This is a private low-level API for use by a handful of low-level |
40 | | // components. Higher-level components should build APIs based on |
41 | | // absl::Time and absl::Duration. |
42 | | class KernelTimeout { |
43 | | public: |
44 | | // Construct an absolute timeout that should expire at `t`. |
45 | | explicit KernelTimeout(absl::Time t); |
46 | | |
47 | | // Construct a relative timeout that should expire after `d`. |
48 | | explicit KernelTimeout(absl::Duration d); |
49 | | |
50 | | // Infinite timeout. |
51 | 0 | constexpr KernelTimeout() : rep_(kNoTimeout) {} |
52 | | |
53 | | // A more explicit factory for those who prefer it. |
54 | | // Equivalent to `KernelTimeout()`. |
55 | 0 | static constexpr KernelTimeout Never() { return KernelTimeout(); } |
56 | | |
57 | | // Returns true if there is a timeout that will eventually expire. |
58 | | // Returns false if the timeout is infinite. |
59 | 0 | bool has_timeout() const { return rep_ != kNoTimeout; } |
60 | | |
61 | | // If `has_timeout()` is true, returns true if the timeout was provided as an |
62 | | // `absl::Time`. The return value is undefined if `has_timeout()` is false |
63 | | // because all indefinite timeouts are equivalent. |
64 | 0 | bool is_absolute_timeout() const { return (rep_ & 1) == 0; } |
65 | | |
66 | | // If `has_timeout()` is true, returns true if the timeout was provided as an |
67 | | // `absl::Duration`. The return value is undefined if `has_timeout()` is false |
68 | | // because all indefinite timeouts are equivalent. |
69 | 0 | bool is_relative_timeout() const { return (rep_ & 1) == 1; } |
70 | | |
71 | | // Convert to `struct timespec` for interfaces that expect an absolute |
72 | | // timeout. If !has_timeout() or is_relative_timeout(), attempts to convert to |
73 | | // a reasonable absolute timeout, but callers should to test has_timeout() and |
74 | | // is_relative_timeout() and prefer to use a more appropriate interface. |
75 | | struct timespec MakeAbsTimespec() const; |
76 | | |
77 | | // Convert to `struct timespec` for interfaces that expect a relative |
78 | | // timeout. If !has_timeout() or is_absolute_timeout(), attempts to convert to |
79 | | // a reasonable relative timeout, but callers should to test has_timeout() and |
80 | | // is_absolute_timeout() and prefer to use a more appropriate interface. Since |
81 | | // the return value is a relative duration, it should be recomputed by calling |
82 | | // this method in the case of a spurious wakeup. |
83 | | struct timespec MakeRelativeTimespec() const; |
84 | | |
85 | | #ifndef _WIN32 |
86 | | // Convert to `struct timespec` for interfaces that expect an absolute timeout |
87 | | // on a specific clock `c`. This is similar to `MakeAbsTimespec()`, but |
88 | | // callers usually want to use this method with `CLOCK_MONOTONIC` when |
89 | | // relative timeouts are requested, and when the appropriate interface expects |
90 | | // an absolute timeout relative to a specific clock (for example, |
91 | | // pthread_cond_clockwait() or sem_clockwait()). If !has_timeout(), attempts |
92 | | // to convert to a reasonable absolute timeout, but callers should to test |
93 | | // has_timeout() prefer to use a more appropriate interface. |
94 | | struct timespec MakeClockAbsoluteTimespec(clockid_t c) const; |
95 | | #endif |
96 | | |
97 | | // Convert to unix epoch nanos for interfaces that expect an absolute timeout |
98 | | // in nanoseconds. If !has_timeout() or is_relative_timeout(), attempts to |
99 | | // convert to a reasonable absolute timeout, but callers should to test |
100 | | // has_timeout() and is_relative_timeout() and prefer to use a more |
101 | | // appropriate interface. |
102 | | int64_t MakeAbsNanos() const; |
103 | | |
104 | | // Converts to milliseconds from now, or INFINITE when |
105 | | // !has_timeout(). For use by SleepConditionVariableSRW on |
106 | | // Windows. Callers should recognize that the return value is a |
107 | | // relative duration (it should be recomputed by calling this method |
108 | | // in the case of a spurious wakeup). |
109 | | // This header file may be included transitively by public header files, |
110 | | // so we define our own DWORD and INFINITE instead of getting them from |
111 | | // <intsafe.h> and <WinBase.h>. |
112 | | typedef unsigned long DWord; // NOLINT |
113 | | DWord InMillisecondsFromNow() const; |
114 | | |
115 | | // Convert to std::chrono::time_point for interfaces that expect an absolute |
116 | | // timeout, like std::condition_variable::wait_until(). If !has_timeout() or |
117 | | // is_relative_timeout(), attempts to convert to a reasonable absolute |
118 | | // timeout, but callers should test has_timeout() and is_relative_timeout() |
119 | | // and prefer to use a more appropriate interface. |
120 | | std::chrono::time_point<std::chrono::system_clock> ToChronoTimePoint() const; |
121 | | |
122 | | // Convert to std::chrono::time_point for interfaces that expect a relative |
123 | | // timeout, like std::condition_variable::wait_for(). If !has_timeout() or |
124 | | // is_absolute_timeout(), attempts to convert to a reasonable relative |
125 | | // timeout, but callers should test has_timeout() and is_absolute_timeout() |
126 | | // and prefer to use a more appropriate interface. Since the return value is a |
127 | | // relative duration, it should be recomputed by calling this method in the |
128 | | // case of a spurious wakeup. |
129 | | std::chrono::nanoseconds ToChronoDuration() const; |
130 | | |
131 | | // Returns true if steady (aka monotonic) clocks are supported by the system. |
132 | | // This method exists because go/btm requires synchronized clocks, and |
133 | | // thus requires we use the system (aka walltime) clock. |
134 | 0 | static constexpr bool SupportsSteadyClock() { return true; } |
135 | | |
136 | | private: |
137 | | // Returns the current time, expressed as a count of nanoseconds since the |
138 | | // epoch used by an arbitrary clock. The implementation tries to use a steady |
139 | | // (monotonic) clock if one is available. |
140 | | static int64_t SteadyClockNow(); |
141 | | |
142 | | // Internal representation. |
143 | | // - If the value is kNoTimeout, then the timeout is infinite, and |
144 | | // has_timeout() will return true. |
145 | | // - If the low bit is 0, then the high 63 bits is the number of nanoseconds |
146 | | // after the unix epoch. |
147 | | // - If the low bit is 1, then the high 63 bits is the number of nanoseconds |
148 | | // after the epoch used by SteadyClockNow(). |
149 | | // |
150 | | // In all cases the time is stored as an absolute time, the only difference is |
151 | | // the clock epoch. The use of absolute times is important since in the case |
152 | | // of a relative timeout with a spurious wakeup, the program would have to |
153 | | // restart the wait, and thus needs a way of recomputing the remaining time. |
154 | | uint64_t rep_; |
155 | | |
156 | | // Returns the number of nanoseconds stored in the internal representation. |
157 | | // When combined with the clock epoch indicated by the low bit (which is |
158 | | // accessed through is_absolute_timeout() and is_relative_timeout()), the |
159 | | // return value is used to compute when the timeout should occur. |
160 | 0 | int64_t RawAbsNanos() const { return static_cast<int64_t>(rep_ >> 1); } |
161 | | |
162 | | // Converts to nanoseconds from now. Since the return value is a relative |
163 | | // duration, it should be recomputed by calling this method in the case of a |
164 | | // spurious wakeup. |
165 | | int64_t InNanosecondsFromNow() const; |
166 | | |
167 | | // A value that represents no timeout (or an infinite timeout). |
168 | | static constexpr uint64_t kNoTimeout = (std::numeric_limits<uint64_t>::max)(); |
169 | | |
170 | | // The maximum value that can be stored in the high 63 bits. |
171 | | static constexpr int64_t kMaxNanos = (std::numeric_limits<int64_t>::max)(); |
172 | | }; |
173 | | |
174 | | } // namespace synchronization_internal |
175 | | ABSL_NAMESPACE_END |
176 | | } // namespace absl |
177 | | |
178 | | #endif // ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_ |