| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 | // Copyright 2017 The Abseil Authors.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at////      https://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.//// An optional absolute timeout, with nanosecond granularity,// compatible with absl::Time. Suitable for in-register// parameter-passing (e.g. syscalls.)// Constructible from a absl::Time (for a timeout to be respected) or {}// (for "no timeout".)// This is a private low-level API for use by a handful of low-level// components that are friends of this class. Higher-level components// should build APIs based on absl::Time and absl::Duration.#ifndef ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_#define ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_#include <time.h>#include <algorithm>#include <limits>#include "absl/base/internal/raw_logging.h"#include "absl/time/clock.h"#include "absl/time/time.h"namespace absl {ABSL_NAMESPACE_BEGINnamespace synchronization_internal {class Futex;class Waiter;class KernelTimeout { public:  // A timeout that should expire at <t>.  Any value, in the full  // InfinitePast() to InfiniteFuture() range, is valid here and will be  // respected.  explicit KernelTimeout(absl::Time t) : ns_(MakeNs(t)) {}  // No timeout.  KernelTimeout() : ns_(0) {}  // A more explicit factory for those who prefer it.  Equivalent to {}.  static KernelTimeout Never() { return {}; }  // We explicitly do not support other custom formats: timespec, int64_t nanos.  // Unify on this and absl::Time, please.  bool has_timeout() const { return ns_ != 0; }  // Convert to parameter for sem_timedwait/futex/similar.  Only for approved  // users.  Do not call if !has_timeout.  struct timespec MakeAbsTimespec(); private:  // internal rep, not user visible: ns after unix epoch.  // zero = no timeout.  // Negative we treat as an unlikely (and certainly expired!) but valid  // timeout.  int64_t ns_;  static int64_t MakeNs(absl::Time t) {    // optimization--InfiniteFuture is common "no timeout" value    // and cheaper to compare than convert.    if (t == absl::InfiniteFuture()) return 0;    int64_t x = ToUnixNanos(t);    // A timeout that lands exactly on the epoch (x=0) needs to be respected,    // so we alter it unnoticably to 1.  Negative timeouts are in    // theory supported, but handled poorly by the kernel (long    // delays) so push them forward too; since all such times have    // already passed, it's indistinguishable.    if (x <= 0) x = 1;    // A time larger than what can be represented to the kernel is treated    // as no timeout.    if (x == (std::numeric_limits<int64_t>::max)()) x = 0;    return x;  }#ifdef _WIN32  // Converts to milliseconds from now, or INFINITE when  // !has_timeout(). For use by SleepConditionVariableSRW on  // Windows. Callers should recognize that the return value is a  // relative duration (it should be recomputed by calling this method  // in the case of a spurious wakeup).  // This header file may be included transitively by public header files,  // so we define our own DWORD and INFINITE instead of getting them from  // <intsafe.h> and <WinBase.h>.  typedef unsigned long DWord;  // NOLINT  DWord InMillisecondsFromNow() const {    constexpr DWord kInfinite = (std::numeric_limits<DWord>::max)();    if (!has_timeout()) {      return kInfinite;    }    // The use of absl::Now() to convert from absolute time to    // relative time means that absl::Now() cannot use anything that    // depends on KernelTimeout (for example, Mutex) on Windows.    int64_t now = ToUnixNanos(absl::Now());    if (ns_ >= now) {      // Round up so that Now() + ms_from_now >= ns_.      constexpr uint64_t max_nanos =          (std::numeric_limits<int64_t>::max)() - 999999u;      uint64_t ms_from_now =          (std::min<uint64_t>(max_nanos, ns_ - now) + 999999u) / 1000000u;      if (ms_from_now > kInfinite) {        return kInfinite;      }      return static_cast<DWord>(ms_from_now);    }    return 0;  }#endif  friend class Futex;  friend class Waiter;};inline struct timespec KernelTimeout::MakeAbsTimespec() {  int64_t n = ns_;  static const int64_t kNanosPerSecond = 1000 * 1000 * 1000;  if (n == 0) {    ABSL_RAW_LOG(        ERROR, "Tried to create a timespec from a non-timeout; never do this.");    // But we'll try to continue sanely.  no-timeout ~= saturated timeout.    n = (std::numeric_limits<int64_t>::max)();  }  // Kernel APIs validate timespecs as being at or after the epoch,  // despite the kernel time type being signed.  However, no one can  // tell the difference between a timeout at or before the epoch (since  // all such timeouts have expired!)  if (n < 0) n = 0;  struct timespec abstime;  int64_t seconds = (std::min)(n / kNanosPerSecond,                               int64_t{(std::numeric_limits<time_t>::max)()});  abstime.tv_sec = static_cast<time_t>(seconds);  abstime.tv_nsec = static_cast<decltype(abstime.tv_nsec)>(n % kNanosPerSecond);  return abstime;}}  // namespace synchronization_internalABSL_NAMESPACE_END}  // namespace absl#endif  // ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_
 |