| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #include "absl/synchronization/internal/kernel_timeout.h" |
|
|
| #ifndef _WIN32 |
| #include <sys/types.h> |
| #endif |
|
|
| #include <algorithm> |
| #include <chrono> |
| #include <cstdint> |
| #include <cstdlib> |
| #include <cstring> |
| #include <ctime> |
| #include <limits> |
|
|
| #include "absl/base/attributes.h" |
| #include "absl/base/call_once.h" |
| #include "absl/base/config.h" |
| #include "absl/time/time.h" |
|
|
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace synchronization_internal { |
|
|
| #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL |
| constexpr uint64_t KernelTimeout::kNoTimeout; |
| constexpr int64_t KernelTimeout::kMaxNanos; |
| #endif |
|
|
| int64_t KernelTimeout::SteadyClockNow() { |
| if (!SupportsSteadyClock()) { |
| return absl::GetCurrentTimeNanos(); |
| } |
| return std::chrono::duration_cast<std::chrono::nanoseconds>( |
| std::chrono::steady_clock::now().time_since_epoch()) |
| .count(); |
| } |
|
|
| KernelTimeout::KernelTimeout(absl::Time t) { |
| |
| |
| if (t == absl::InfiniteFuture()) { |
| rep_ = kNoTimeout; |
| return; |
| } |
|
|
| int64_t unix_nanos = absl::ToUnixNanos(t); |
|
|
| |
| |
| if (unix_nanos < 0) { |
| unix_nanos = 0; |
| } |
|
|
| |
| if (unix_nanos >= kMaxNanos) { |
| rep_ = kNoTimeout; |
| return; |
| } |
|
|
| rep_ = static_cast<uint64_t>(unix_nanos) << 1; |
| } |
|
|
| KernelTimeout::KernelTimeout(absl::Duration d) { |
| |
| |
| if (d == absl::InfiniteDuration()) { |
| rep_ = kNoTimeout; |
| return; |
| } |
|
|
| int64_t nanos = absl::ToInt64Nanoseconds(d); |
|
|
| |
| |
| if (nanos < 0) { |
| nanos = 0; |
| } |
|
|
| int64_t now = SteadyClockNow(); |
| if (nanos > kMaxNanos - now) { |
| |
| rep_ = kNoTimeout; |
| return; |
| } |
|
|
| nanos += now; |
| rep_ = (static_cast<uint64_t>(nanos) << 1) | uint64_t{1}; |
| } |
|
|
| int64_t KernelTimeout::MakeAbsNanos() const { |
| if (!has_timeout()) { |
| return kMaxNanos; |
| } |
|
|
| int64_t nanos = RawAbsNanos(); |
|
|
| if (is_relative_timeout()) { |
| |
| |
| nanos = std::max<int64_t>(nanos - SteadyClockNow(), 0); |
| int64_t now = absl::GetCurrentTimeNanos(); |
| if (nanos > kMaxNanos - now) { |
| |
| nanos = kMaxNanos; |
| } else { |
| nanos += now; |
| } |
| } else if (nanos == 0) { |
| |
| |
| nanos = 1; |
| } |
|
|
| return nanos; |
| } |
|
|
| int64_t KernelTimeout::InNanosecondsFromNow() const { |
| if (!has_timeout()) { |
| return kMaxNanos; |
| } |
|
|
| int64_t nanos = RawAbsNanos(); |
| if (is_absolute_timeout()) { |
| return std::max<int64_t>(nanos - absl::GetCurrentTimeNanos(), 0); |
| } |
| return std::max<int64_t>(nanos - SteadyClockNow(), 0); |
| } |
|
|
| struct timespec KernelTimeout::MakeAbsTimespec() const { |
| return absl::ToTimespec(absl::Nanoseconds(MakeAbsNanos())); |
| } |
|
|
| struct timespec KernelTimeout::MakeRelativeTimespec() const { |
| return absl::ToTimespec(absl::Nanoseconds(InNanosecondsFromNow())); |
| } |
|
|
| #ifndef _WIN32 |
| struct timespec KernelTimeout::MakeClockAbsoluteTimespec(clockid_t c) const { |
| if (!has_timeout()) { |
| return absl::ToTimespec(absl::Nanoseconds(kMaxNanos)); |
| } |
|
|
| int64_t nanos = RawAbsNanos(); |
| if (is_absolute_timeout()) { |
| nanos -= absl::GetCurrentTimeNanos(); |
| } else { |
| nanos -= SteadyClockNow(); |
| } |
|
|
| struct timespec now; |
| ABSL_RAW_CHECK(clock_gettime(c, &now) == 0, "clock_gettime() failed"); |
| absl::Duration from_clock_epoch = |
| absl::DurationFromTimespec(now) + absl::Nanoseconds(nanos); |
| if (from_clock_epoch <= absl::ZeroDuration()) { |
| |
| |
| |
| return absl::ToTimespec(absl::Nanoseconds(1)); |
| } |
| return absl::ToTimespec(from_clock_epoch); |
| } |
| #endif |
|
|
| KernelTimeout::DWord KernelTimeout::InMillisecondsFromNow() const { |
| constexpr DWord kInfinite = std::numeric_limits<DWord>::max(); |
|
|
| if (!has_timeout()) { |
| return kInfinite; |
| } |
|
|
| constexpr uint64_t kNanosInMillis = uint64_t{1'000'000}; |
| constexpr uint64_t kMaxValueNanos = |
| std::numeric_limits<int64_t>::max() - kNanosInMillis + 1; |
|
|
| uint64_t ns_from_now = static_cast<uint64_t>(InNanosecondsFromNow()); |
| if (ns_from_now >= kMaxValueNanos) { |
| |
| return kInfinite; |
| } |
| |
| uint64_t ms_from_now = (ns_from_now + kNanosInMillis - 1) / kNanosInMillis; |
| if (ms_from_now > kInfinite) { |
| return kInfinite; |
| } |
| return static_cast<DWord>(ms_from_now); |
| } |
|
|
| std::chrono::time_point<std::chrono::system_clock> |
| KernelTimeout::ToChronoTimePoint() const { |
| if (!has_timeout()) { |
| return std::chrono::time_point<std::chrono::system_clock>::max(); |
| } |
|
|
| |
| |
| |
| auto micros = std::chrono::duration_cast<std::chrono::microseconds>( |
| std::chrono::nanoseconds(MakeAbsNanos())); |
| return std::chrono::system_clock::from_time_t(0) + micros; |
| } |
|
|
| std::chrono::nanoseconds KernelTimeout::ToChronoDuration() const { |
| if (!has_timeout()) { |
| return std::chrono::nanoseconds::max(); |
| } |
| return std::chrono::nanoseconds(InNanosecondsFromNow()); |
| } |
|
|
| } |
| ABSL_NAMESPACE_END |
| } |
|
|