00001 // Copyright 2017 The Abseil Authors. 00002 // 00003 // Licensed under the Apache License, Version 2.0 (the "License"); 00004 // you may not use this file except in compliance with the License. 00005 // You may obtain a copy of the License at 00006 // 00007 // https://www.apache.org/licenses/LICENSE-2.0 00008 // 00009 // Unless required by applicable law or agreed to in writing, software 00010 // distributed under the License is distributed on an "AS IS" BASIS, 00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00012 // See the License for the specific language governing permissions and 00013 // limitations under the License. 00014 // 00015 00016 // An optional absolute timeout, with nanosecond granularity, 00017 // compatible with absl::Time. Suitable for in-register 00018 // parameter-passing (e.g. syscalls.) 00019 // Constructible from a absl::Time (for a timeout to be respected) or {} 00020 // (for "no timeout".) 00021 // This is a private low-level API for use by a handful of low-level 00022 // components that are friends of this class. Higher-level components 00023 // should build APIs based on absl::Time and absl::Duration. 00024 00025 #ifndef ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_ 00026 #define ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_ 00027 00028 #include <time.h> 00029 #include <algorithm> 00030 #include <limits> 00031 00032 #include "absl/base/internal/raw_logging.h" 00033 #include "absl/time/clock.h" 00034 #include "absl/time/time.h" 00035 00036 namespace absl { 00037 namespace synchronization_internal { 00038 00039 class Futex; 00040 class Waiter; 00041 00042 class KernelTimeout { 00043 public: 00044 // A timeout that should expire at <t>. Any value, in the full 00045 // InfinitePast() to InfiniteFuture() range, is valid here and will be 00046 // respected. 00047 explicit KernelTimeout(absl::Time t) : ns_(MakeNs(t)) {} 00048 // No timeout. 00049 KernelTimeout() : ns_(0) {} 00050 00051 // A more explicit factory for those who prefer it. Equivalent to {}. 00052 static KernelTimeout Never() { return {}; } 00053 00054 // We explicitly do not support other custom formats: timespec, int64_t nanos. 00055 // Unify on this and absl::Time, please. 00056 00057 bool has_timeout() const { return ns_ != 0; } 00058 00059 private: 00060 // internal rep, not user visible: ns after unix epoch. 00061 // zero = no timeout. 00062 // Negative we treat as an unlikely (and certainly expired!) but valid 00063 // timeout. 00064 int64_t ns_; 00065 00066 static int64_t MakeNs(absl::Time t) { 00067 // optimization--InfiniteFuture is common "no timeout" value 00068 // and cheaper to compare than convert. 00069 if (t == absl::InfiniteFuture()) return 0; 00070 int64_t x = ToUnixNanos(t); 00071 00072 // A timeout that lands exactly on the epoch (x=0) needs to be respected, 00073 // so we alter it unnoticably to 1. Negative timeouts are in 00074 // theory supported, but handled poorly by the kernel (long 00075 // delays) so push them forward too; since all such times have 00076 // already passed, it's indistinguishable. 00077 if (x <= 0) x = 1; 00078 // A time larger than what can be represented to the kernel is treated 00079 // as no timeout. 00080 if (x == (std::numeric_limits<int64_t>::max)()) x = 0; 00081 return x; 00082 } 00083 00084 // Convert to parameter for sem_timedwait/futex/similar. Only for approved 00085 // users. Do not call if !has_timeout. 00086 struct timespec MakeAbsTimespec() { 00087 int64_t n = ns_; 00088 static const int64_t kNanosPerSecond = 1000 * 1000 * 1000; 00089 if (n == 0) { 00090 ABSL_RAW_LOG( 00091 ERROR, 00092 "Tried to create a timespec from a non-timeout; never do this."); 00093 // But we'll try to continue sanely. no-timeout ~= saturated timeout. 00094 n = (std::numeric_limits<int64_t>::max)(); 00095 } 00096 00097 // Kernel APIs validate timespecs as being at or after the epoch, 00098 // despite the kernel time type being signed. However, no one can 00099 // tell the difference between a timeout at or before the epoch (since 00100 // all such timeouts have expired!) 00101 if (n < 0) n = 0; 00102 00103 struct timespec abstime; 00104 int64_t seconds = (std::min)(n / kNanosPerSecond, 00105 int64_t{(std::numeric_limits<time_t>::max)()}); 00106 abstime.tv_sec = static_cast<time_t>(seconds); 00107 abstime.tv_nsec = 00108 static_cast<decltype(abstime.tv_nsec)>(n % kNanosPerSecond); 00109 return abstime; 00110 } 00111 00112 #ifdef _WIN32 00113 // Converts to milliseconds from now, or INFINITE when 00114 // !has_timeout(). For use by SleepConditionVariableSRW on 00115 // Windows. Callers should recognize that the return value is a 00116 // relative duration (it should be recomputed by calling this method 00117 // in the case of a spurious wakeup). 00118 // This header file may be included transitively by public header files, 00119 // so we define our own DWORD and INFINITE instead of getting them from 00120 // <intsafe.h> and <WinBase.h>. 00121 typedef unsigned long DWord; // NOLINT 00122 DWord InMillisecondsFromNow() const { 00123 constexpr DWord kInfinite = (std::numeric_limits<DWord>::max)(); 00124 if (!has_timeout()) { 00125 return kInfinite; 00126 } 00127 // The use of absl::Now() to convert from absolute time to 00128 // relative time means that absl::Now() cannot use anything that 00129 // depends on KernelTimeout (for example, Mutex) on Windows. 00130 int64_t now = ToUnixNanos(absl::Now()); 00131 if (ns_ >= now) { 00132 // Round up so that Now() + ms_from_now >= ns_. 00133 constexpr uint64_t max_nanos = 00134 (std::numeric_limits<int64_t>::max)() - 999999u; 00135 uint64_t ms_from_now = 00136 (std::min<uint64_t>(max_nanos, ns_ - now) + 999999u) / 1000000u; 00137 if (ms_from_now > kInfinite) { 00138 return kInfinite; 00139 } 00140 return static_cast<DWord>(ms_from_now); 00141 } 00142 return 0; 00143 } 00144 #endif 00145 00146 friend class Futex; 00147 friend class Waiter; 00148 }; 00149 00150 } // namespace synchronization_internal 00151 } // namespace absl 00152 00153 #endif // ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_