ConditionVariable.h (4588B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef threading_ConditionVariable_h 8 #define threading_ConditionVariable_h 9 10 #include "mozilla/PlatformConditionVariable.h" 11 #include "mozilla/TimeStamp.h" 12 13 #include <utility> 14 #if !defined(XP_WIN) && !defined(__wasi__) 15 # include <pthread.h> 16 #endif 17 18 #include "threading/LockGuard.h" 19 #include "threading/Mutex.h" 20 21 namespace js { 22 23 template <class T> 24 class ExclusiveData; 25 26 enum class CVStatus { NoTimeout, Timeout }; 27 28 template <typename T> 29 using UniqueLock = LockGuard<T>; 30 31 // A poly-fill for std::condition_variable. 32 class ConditionVariable { 33 public: 34 struct PlatformData; 35 36 ConditionVariable() = default; 37 ~ConditionVariable() = default; 38 39 // Wake one thread that is waiting on this condition. 40 void notify_one() { impl_.notify_one(); } 41 42 // Wake all threads that are waiting on this condition. 43 void notify_all() { impl_.notify_all(); } 44 45 // Block the current thread of execution until this condition variable is 46 // woken from another thread via notify_one or notify_all. 47 void wait(Mutex& lock) { 48 #ifdef DEBUG 49 lock.preUnlockChecks(); 50 #endif 51 impl_.wait(lock.impl_); 52 #ifdef DEBUG 53 lock.preLockChecks(); 54 lock.postLockChecks(); 55 #endif 56 } 57 void wait(UniqueLock<Mutex>& lock) { wait(lock.mutex); } 58 59 // As with |wait|, block the current thread of execution until woken from 60 // another thread. This method will resume waiting once woken until the given 61 // Predicate |pred| evaluates to true. 62 template <typename Predicate> 63 void wait(UniqueLock<Mutex>& lock, Predicate pred) { 64 while (!pred()) { 65 wait(lock); 66 } 67 } 68 69 // Block the current thread of execution until woken from another thread, or 70 // the given absolute time is reached. The given absolute time is evaluated 71 // when this method is called, so will wake up after (abs_time - now), 72 // independent of system clock changes. While insulated from clock changes, 73 // this API is succeptible to the issues discussed above wait_for. 74 CVStatus wait_until(UniqueLock<Mutex>& lock, 75 const mozilla::TimeStamp& abs_time) { 76 return wait_for(lock, abs_time - mozilla::TimeStamp::Now()); 77 } 78 79 // As with |wait_until|, block the current thread of execution until woken 80 // from another thread, or the given absolute time is reached. This method 81 // will resume waiting once woken until the given Predicate |pred| evaluates 82 // to true. 83 template <typename Predicate> 84 bool wait_until(UniqueLock<Mutex>& lock, const mozilla::TimeStamp& abs_time, 85 Predicate pred) { 86 while (!pred()) { 87 if (wait_until(lock, abs_time) == CVStatus::Timeout) { 88 return pred(); 89 } 90 } 91 return true; 92 } 93 94 // Block the current thread of execution until woken from another thread, or 95 // the given time duration has elapsed. Given that the system may be 96 // interrupted between the callee and the actual wait beginning, this call 97 // has a minimum granularity of the system's scheduling interval, and may 98 // encounter substantially longer delays, depending on system load. 99 CVStatus wait_for(UniqueLock<Mutex>& lock, 100 const mozilla::TimeDuration& rel_time) { 101 #ifdef DEBUG 102 lock.mutex.preUnlockChecks(); 103 #endif 104 CVStatus res = 105 impl_.wait_for(lock.mutex.impl_, rel_time) == mozilla::CVStatus::Timeout 106 ? CVStatus::Timeout 107 : CVStatus::NoTimeout; 108 #ifdef DEBUG 109 lock.mutex.preLockChecks(); 110 lock.mutex.postLockChecks(); 111 #endif 112 return res; 113 } 114 115 // As with |wait_for|, block the current thread of execution until woken from 116 // another thread or the given time duration has elapsed. This method will 117 // resume waiting once woken until the given Predicate |pred| evaluates to 118 // true. 119 template <typename Predicate> 120 bool wait_for(UniqueLock<Mutex>& lock, const mozilla::TimeDuration& rel_time, 121 Predicate pred) { 122 return wait_until(lock, mozilla::TimeStamp::Now() + rel_time, 123 std::move(pred)); 124 } 125 126 private: 127 ConditionVariable(const ConditionVariable&) = delete; 128 ConditionVariable& operator=(const ConditionVariable&) = delete; 129 template <class T> 130 friend class ExclusiveWaitableData; 131 132 mozilla::detail::ConditionVariableImpl impl_; 133 }; 134 135 } // namespace js 136 137 #endif // threading_ConditionVariable_h