Handle max deadlines in Futex
[folly.git] / folly / detail / Futex.h
index 000bf1a62dcfad7ebfac2acdf1fc437307600498..aadddd03f32404989403917cfb70e8f67c5d30f2 100644 (file)
 #include <limits>
 #include <type_traits>
 
-#include <boost/noncopyable.hpp>
-
 #include <folly/portability/Unistd.h>
 
 namespace folly { namespace detail {
 
 enum class FutexResult {
-  VALUE_CHANGED, /* Futex value didn't match expected */
-  AWOKEN,        /* futex wait matched with a futex wake */
-  INTERRUPTED,   /* Spurious wake-up or signal caused futex wait failure */
-  TIMEDOUT,
+  VALUE_CHANGED, /* futex value didn't match expected */
+  AWOKEN,        /* wakeup by matching futex wake, or spurious wakeup */
+  INTERRUPTED,   /* wakeup by interrupting signal */
+  TIMEDOUT,      /* wakeup by expiring deadline */
 };
 
 /**
@@ -45,9 +43,8 @@ enum class FutexResult {
  * (and benchmarks to back you up).
  */
 template <template <typename> class Atom = std::atomic>
-struct Futex : Atom<uint32_t>, boost::noncopyable {
-
-  explicit constexpr Futex(uint32_t init = 0) : Atom<uint32_t>(init) {}
+struct Futex : Atom<uint32_t> {
+  using Atom<uint32_t>::Atom;
 
   /** Puts the thread to sleep if this->load() == expected.  Returns true when
    *  it is returning because it has consumed a wake() event, false for any
@@ -76,7 +73,9 @@ struct Futex : Atom<uint32_t>, boost::noncopyable {
         std::chrono::steady_clock,
         std::chrono::system_clock>::type;
     auto const converted = time_point_conv<Target>(deadline);
-    return futexWaitImpl(expected, converted, waitMask);
+    return converted == Target::time_point::max()
+        ? futexWaitImpl(expected, nullptr, nullptr, waitMask)
+        : futexWaitImpl(expected, converted, waitMask);
   }
 
   /** Wakens up to count waiters where (waitMask & wakeMask) !=
@@ -98,9 +97,12 @@ struct Futex : Atom<uint32_t>, boost::noncopyable {
   static typename TargetClock::time_point time_point_conv(
       std::chrono::time_point<Clock, Duration> const& time) {
     using std::chrono::duration_cast;
+    using TimePoint = std::chrono::time_point<Clock, Duration>;
     using TargetDuration = typename TargetClock::duration;
     using TargetTimePoint = typename TargetClock::time_point;
-    if (std::is_same<Clock, TargetClock>::value) {
+    if (time == TimePoint::max()) {
+      return TargetTimePoint::max();
+    } else if (std::is_same<Clock, TargetClock>::value) {
       // in place of time_point_cast, which cannot compile without if-constexpr
       auto const delta = time.time_since_epoch();
       return TargetTimePoint(duration_cast<TargetDuration>(delta));