Use WordLock instead of std::mutex for Threading
[WebKit-https.git] / Source / WTF / wtf / Condition.h
index 80c0729..75c8ea5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #ifndef WTF_Condition_h
 #define WTF_Condition_h
 
-#include <chrono>
-#include <functional>
-#include <wtf/CurrentTime.h>
 #include <wtf/Noncopyable.h>
 #include <wtf/ParkingLot.h>
+#include <wtf/TimeWithDynamicClockType.h>
 
 namespace WTF {
 
 // This is a condition variable that is suitable for use with any lock-like object, including
 // our own WTF::Lock. It features standard wait()/notifyOne()/notifyAll() methods in addition to
 // a variety of wait-with-timeout methods. This includes methods that use WTF's own notion of
-// time, like wall-clock time (i.e. currentTime()) and monotonic time (i.e.
-// monotonicallyIncreasingTime()). This is a very efficient condition variable. It only requires
-// one byte of memory. notifyOne() and notifyAll() require just a load and branch for the fast
-// case where no thread is waiting. This condition variable, when used with WTF::Lock, can
-// outperform a system condition variable and lock by up to 58x.
-
-// This is a struct without a constructor or destructor so that it can be statically initialized.
-// Use Lock in instance variables.
-struct ConditionBase {
-    typedef ParkingLot::Clock Clock;
-    
+// time, like wall-clock time (i.e. WallTime) and monotonic time (i.e. MonotonicTime). This is
+// a very efficient condition variable. It only requires one byte of memory. notifyOne() and
+// notifyAll() require just a load and branch for the fast case where no thread is waiting.
+// This condition variable, when used with WTF::Lock, can outperform a system condition variable
+// and lock by up to 58x.
+class Condition {
+    WTF_MAKE_NONCOPYABLE(Condition);
+public:
+    // Condition will accept any kind of time and convert it internally, but this typedef tells
+    // you what kind of time Condition would be able to use without conversions. However, if you
+    // are unlikely to be affected by the cost of conversions, it is better to use MonotonicTime.
+    using Time = ParkingLot::Time;
+
+    constexpr Condition() = default;
+
     // Wait on a parking queue while releasing the given lock. It will unlock the lock just before
     // parking, and relock it upon wakeup. Returns true if we woke up due to some call to
     // notifyOne() or notifyAll(). Returns false if we woke up due to a timeout. Note that this form
@@ -64,10 +66,10 @@ struct ConditionBase {
     // which may not release the lock for past timeout. But, this behavior is consistent with OpenGroup
     // documentation for timedwait().
     template<typename LockType>
-    bool waitUntil(LockType& lock, Clock::time_point timeout)
+    bool waitUntil(LockType& lock, const TimeWithDynamicClockType& timeout)
     {
         bool result;
-        if (timeout < Clock::now()) {
+        if (timeout < timeout.nowWithSameClock()) {
             lock.unlock();
             result = false;
         } else {
@@ -80,7 +82,7 @@ struct ConditionBase {
                     return true;
                 },
                 [&lock] () { lock.unlock(); },
-                timeout);
+                timeout).wasUnparked;
         }
         lock.lock();
         return result;
@@ -89,7 +91,8 @@ struct ConditionBase {
     // Wait until the given predicate is satisfied. Returns true if it is satisfied in the end.
     // May return early due to timeout.
     template<typename LockType, typename Functor>
-    bool waitUntil(LockType& lock, Clock::time_point timeout, const Functor& predicate)
+    bool waitUntil(
+        LockType& lock, const TimeWithDynamicClockType& timeout, const Functor& predicate)
     {
         while (!predicate()) {
             if (!waitUntil(lock, timeout))
@@ -100,17 +103,23 @@ struct ConditionBase {
 
     // Wait until the given predicate is satisfied. Returns true if it is satisfied in the end.
     // May return early due to timeout.
-    template<typename LockType, typename DurationType, typename Functor>
+    template<typename LockType, typename Functor>
     bool waitFor(
-        LockType& lock, const DurationType& relativeTimeout, const Functor& predicate)
+        LockType& lock, Seconds relativeTimeout, const Functor& predicate)
+    {
+        return waitUntil(lock, MonotonicTime::now() + relativeTimeout, predicate);
+    }
+    
+    template<typename LockType>
+    bool waitFor(LockType& lock, Seconds relativeTimeout)
     {
-        return waitUntil(lock, absoluteFromRelative(relativeTimeout), predicate);
+        return waitUntil(lock, MonotonicTime::now() + relativeTimeout);
     }
 
     template<typename LockType>
     void wait(LockType& lock)
     {
-        waitUntil(lock, Clock::time_point::max());
+        waitUntil(lock, Time::infinity());
     }
 
     template<typename LockType, typename Functor>
@@ -120,45 +129,27 @@ struct ConditionBase {
             wait(lock);
     }
 
-    template<typename LockType, typename TimeType>
-    bool waitUntil(LockType& lock, const TimeType& timeout)
-    {
-        if (timeout == TimeType::max()) {
-            wait(lock);
-            return true;
-        }
-        return waitForImpl(lock, timeout - TimeType::clock::now());
-    }
-
-    template<typename LockType>
-    bool waitUntilWallClockSeconds(LockType& lock, double absoluteTimeoutSeconds)
-    {
-        return waitForSecondsImpl(lock, absoluteTimeoutSeconds - currentTime());
-    }
-
-    template<typename LockType>
-    bool waitUntilMonotonicClockSeconds(LockType& lock, double absoluteTimeoutSeconds)
-    {
-        return waitForSecondsImpl(lock, absoluteTimeoutSeconds - monotonicallyIncreasingTime());
-    }
-
     // Note that this method is extremely fast when nobody is waiting. It is not necessary to try to
-    // avoid calling this method.
-    void notifyOne()
+    // avoid calling this method. This returns true if someone was actually woken up.
+    bool notifyOne()
     {
         if (!m_hasWaiters.load()) {
             // At this exact instant, there is nobody waiting on this condition. The way to visualize
             // this is that if unparkOne() ran to completion without obstructions at this moment, it
             // wouldn't wake anyone up. Hence, we have nothing to do!
-            return;
+            return false;
         }
         
+        bool didNotifyThread = false;
         ParkingLot::unparkOne(
             &m_hasWaiters,
-            [this] (bool, bool mayHaveMoreThreads) {
-                if (!mayHaveMoreThreads)
+            [&] (ParkingLot::UnparkResult result) -> intptr_t {
+                if (!result.mayHaveMoreThreads)
                     m_hasWaiters.store(false);
+                didNotifyThread = result.didUnparkThread;
+                return 0;
             });
+        return didNotifyThread;
     }
     
     void notifyAll()
@@ -177,70 +168,11 @@ struct ConditionBase {
         ParkingLot::unparkAll(&m_hasWaiters);
     }
     
-protected:
-    template<typename LockType>
-    bool waitForSecondsImpl(LockType& lock, double relativeTimeoutSeconds)
-    {
-        double relativeTimeoutNanoseconds = relativeTimeoutSeconds * (1000.0 * 1000.0 * 1000.0);
-        
-        if (!(relativeTimeoutNanoseconds > 0)) {
-            // This handles insta-timeouts as well as NaN.
-            lock.unlock();
-            lock.lock();
-            return false;
-        }
-
-        if (relativeTimeoutNanoseconds > static_cast<double>(std::numeric_limits<int64_t>::max())) {
-            // If the timeout in nanoseconds cannot be expressed using a 64-bit integer, then we
-            // might as well wait forever.
-            wait(lock);
-            return true;
-        }
-        
-        auto relativeTimeout =
-            std::chrono::nanoseconds(static_cast<int64_t>(relativeTimeoutNanoseconds));
-
-        return waitForImpl(lock, relativeTimeout);
-    }
-    
-    template<typename LockType, typename DurationType>
-    bool waitForImpl(LockType& lock, const DurationType& relativeTimeout)
-    {
-        return waitUntil(lock, absoluteFromRelative(relativeTimeout));
-    }
-
-    template<typename DurationType>
-    Clock::time_point absoluteFromRelative(const DurationType& relativeTimeout)
-    {
-        if (relativeTimeout < DurationType::zero())
-            return Clock::time_point::min();
-
-        if (relativeTimeout > Clock::duration::max()) {
-            // This is highly unlikely. But if it happens, we want to not do anything dumb. Sleeping
-            // without a timeout seems sensible when the timeout duration is greater than what can be
-            // expressed using steady_clock.
-            return Clock::time_point::max();
-        }
-        
-        Clock::duration myRelativeTimeout =
-            std::chrono::duration_cast<Clock::duration>(relativeTimeout);
-
-        return Clock::now() + myRelativeTimeout;
-    }
-
-    Atomic<bool> m_hasWaiters;
-};    
-
-class Condition : public ConditionBase {
-    WTF_MAKE_NONCOPYABLE(Condition);
-public:
-    Condition()
-    {
-        m_hasWaiters.store(false);
-    }
+private:
+    Atomic<bool> m_hasWaiters { false };
 };
 
-typedef ConditionBase StaticCondition;
+using StaticCondition = Condition;
 
 } // namespace WTF