kernel_timeout.cc 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. // Copyright 2023 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. #include "y_absl/synchronization/internal/kernel_timeout.h"
  15. #ifndef _WIN32
  16. #include <sys/types.h>
  17. #endif
  18. #include <algorithm>
  19. #include <chrono> // NOLINT(build/c++11)
  20. #include <cstdint>
  21. #include <cstdlib>
  22. #include <cstring>
  23. #include <ctime>
  24. #include <limits>
  25. #include "y_absl/base/attributes.h"
  26. #include "y_absl/base/call_once.h"
  27. #include "y_absl/base/config.h"
  28. #include "y_absl/time/time.h"
  29. namespace y_absl {
  30. Y_ABSL_NAMESPACE_BEGIN
  31. namespace synchronization_internal {
  32. #ifdef Y_ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
  33. constexpr uint64_t KernelTimeout::kNoTimeout;
  34. constexpr int64_t KernelTimeout::kMaxNanos;
  35. #endif
  36. int64_t KernelTimeout::SteadyClockNow() {
  37. if (!SupportsSteadyClock()) {
  38. return y_absl::GetCurrentTimeNanos();
  39. }
  40. return std::chrono::duration_cast<std::chrono::nanoseconds>(
  41. std::chrono::steady_clock::now().time_since_epoch())
  42. .count();
  43. }
  44. KernelTimeout::KernelTimeout(y_absl::Time t) {
  45. // `y_absl::InfiniteFuture()` is a common "no timeout" value and cheaper to
  46. // compare than convert.
  47. if (t == y_absl::InfiniteFuture()) {
  48. rep_ = kNoTimeout;
  49. return;
  50. }
  51. int64_t unix_nanos = y_absl::ToUnixNanos(t);
  52. // A timeout that lands before the unix epoch is converted to 0.
  53. // In theory implementations should expire these timeouts immediately.
  54. if (unix_nanos < 0) {
  55. unix_nanos = 0;
  56. }
  57. // Values greater than or equal to kMaxNanos are converted to infinite.
  58. if (unix_nanos >= kMaxNanos) {
  59. rep_ = kNoTimeout;
  60. return;
  61. }
  62. rep_ = static_cast<uint64_t>(unix_nanos) << 1;
  63. }
  64. KernelTimeout::KernelTimeout(y_absl::Duration d) {
  65. // `y_absl::InfiniteDuration()` is a common "no timeout" value and cheaper to
  66. // compare than convert.
  67. if (d == y_absl::InfiniteDuration()) {
  68. rep_ = kNoTimeout;
  69. return;
  70. }
  71. int64_t nanos = y_absl::ToInt64Nanoseconds(d);
  72. // Negative durations are normalized to 0.
  73. // In theory implementations should expire these timeouts immediately.
  74. if (nanos < 0) {
  75. nanos = 0;
  76. }
  77. int64_t now = SteadyClockNow();
  78. if (nanos > kMaxNanos - now) {
  79. // Durations that would be greater than kMaxNanos are converted to infinite.
  80. rep_ = kNoTimeout;
  81. return;
  82. }
  83. nanos += now;
  84. rep_ = (static_cast<uint64_t>(nanos) << 1) | uint64_t{1};
  85. }
  86. int64_t KernelTimeout::MakeAbsNanos() const {
  87. if (!has_timeout()) {
  88. return kMaxNanos;
  89. }
  90. int64_t nanos = RawAbsNanos();
  91. if (is_relative_timeout()) {
  92. // We need to change epochs, because the relative timeout might be
  93. // represented by an absolute timestamp from another clock.
  94. nanos = std::max<int64_t>(nanos - SteadyClockNow(), 0);
  95. int64_t now = y_absl::GetCurrentTimeNanos();
  96. if (nanos > kMaxNanos - now) {
  97. // Overflow.
  98. nanos = kMaxNanos;
  99. } else {
  100. nanos += now;
  101. }
  102. } else if (nanos == 0) {
  103. // Some callers have assumed that 0 means no timeout, so instead we return a
  104. // time of 1 nanosecond after the epoch.
  105. nanos = 1;
  106. }
  107. return nanos;
  108. }
  109. int64_t KernelTimeout::InNanosecondsFromNow() const {
  110. if (!has_timeout()) {
  111. return kMaxNanos;
  112. }
  113. int64_t nanos = RawAbsNanos();
  114. if (is_absolute_timeout()) {
  115. return std::max<int64_t>(nanos - y_absl::GetCurrentTimeNanos(), 0);
  116. }
  117. return std::max<int64_t>(nanos - SteadyClockNow(), 0);
  118. }
  119. struct timespec KernelTimeout::MakeAbsTimespec() const {
  120. return y_absl::ToTimespec(y_absl::Nanoseconds(MakeAbsNanos()));
  121. }
  122. struct timespec KernelTimeout::MakeRelativeTimespec() const {
  123. return y_absl::ToTimespec(y_absl::Nanoseconds(InNanosecondsFromNow()));
  124. }
  125. #ifndef _WIN32
  126. struct timespec KernelTimeout::MakeClockAbsoluteTimespec(clockid_t c) const {
  127. if (!has_timeout()) {
  128. return y_absl::ToTimespec(y_absl::Nanoseconds(kMaxNanos));
  129. }
  130. int64_t nanos = RawAbsNanos();
  131. if (is_absolute_timeout()) {
  132. nanos -= y_absl::GetCurrentTimeNanos();
  133. } else {
  134. nanos -= SteadyClockNow();
  135. }
  136. struct timespec now;
  137. Y_ABSL_RAW_CHECK(clock_gettime(c, &now) == 0, "clock_gettime() failed");
  138. y_absl::Duration from_clock_epoch =
  139. y_absl::DurationFromTimespec(now) + y_absl::Nanoseconds(nanos);
  140. if (from_clock_epoch <= y_absl::ZeroDuration()) {
  141. // Some callers have assumed that 0 means no timeout, so instead we return a
  142. // time of 1 nanosecond after the epoch. For safety we also do not return
  143. // negative values.
  144. return y_absl::ToTimespec(y_absl::Nanoseconds(1));
  145. }
  146. return y_absl::ToTimespec(from_clock_epoch);
  147. }
  148. #endif
  149. KernelTimeout::DWord KernelTimeout::InMillisecondsFromNow() const {
  150. constexpr DWord kInfinite = std::numeric_limits<DWord>::max();
  151. if (!has_timeout()) {
  152. return kInfinite;
  153. }
  154. constexpr uint64_t kNanosInMillis = uint64_t{1'000'000};
  155. constexpr uint64_t kMaxValueNanos =
  156. std::numeric_limits<int64_t>::max() - kNanosInMillis + 1;
  157. uint64_t ns_from_now = static_cast<uint64_t>(InNanosecondsFromNow());
  158. if (ns_from_now >= kMaxValueNanos) {
  159. // Rounding up would overflow.
  160. return kInfinite;
  161. }
  162. // Convert to milliseconds, always rounding up.
  163. uint64_t ms_from_now = (ns_from_now + kNanosInMillis - 1) / kNanosInMillis;
  164. if (ms_from_now > kInfinite) {
  165. return kInfinite;
  166. }
  167. return static_cast<DWord>(ms_from_now);
  168. }
  169. std::chrono::time_point<std::chrono::system_clock>
  170. KernelTimeout::ToChronoTimePoint() const {
  171. if (!has_timeout()) {
  172. return std::chrono::time_point<std::chrono::system_clock>::max();
  173. }
  174. // The cast to std::microseconds is because (on some platforms) the
  175. // std::ratio used by std::chrono::steady_clock doesn't convert to
  176. // std::nanoseconds, so it doesn't compile.
  177. auto micros = std::chrono::duration_cast<std::chrono::microseconds>(
  178. std::chrono::nanoseconds(MakeAbsNanos()));
  179. return std::chrono::system_clock::from_time_t(0) + micros;
  180. }
  181. std::chrono::nanoseconds KernelTimeout::ToChronoDuration() const {
  182. if (!has_timeout()) {
  183. return std::chrono::nanoseconds::max();
  184. }
  185. return std::chrono::nanoseconds(InNanosecondsFromNow());
  186. }
  187. } // namespace synchronization_internal
  188. Y_ABSL_NAMESPACE_END
  189. } // namespace y_absl