Line data Source code
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/Attributes.h"
11 : #include "mozilla/Move.h"
12 : #include "mozilla/PlatformConditionVariable.h"
13 : #include "mozilla/TimeStamp.h"
14 :
15 : #include <stdint.h>
16 : #ifndef XP_WIN
17 : # include <pthread.h>
18 : #endif
19 :
20 : #include "threading/LockGuard.h"
21 : #include "threading/Mutex.h"
22 :
23 : namespace js {
24 :
25 : enum class CVStatus {
26 : NoTimeout,
27 : Timeout
28 : };
29 :
30 : template <typename T> using UniqueLock = LockGuard<T>;
31 :
32 : // A poly-fill for std::condition_variable.
33 : class ConditionVariable
34 : {
35 : public:
36 : struct PlatformData;
37 :
38 17 : ConditionVariable() = default;
39 0 : ~ConditionVariable() = default;
40 :
41 : // Wake one thread that is waiting on this condition.
42 55 : void notify_one() {
43 55 : impl_.notify_one();
44 55 : }
45 :
46 : // Wake all threads that are waiting on this condition.
47 70 : void notify_all() {
48 70 : impl_.notify_all();
49 70 : }
50 :
51 : // Block the current thread of execution until this condition variable is
52 : // woken from another thread via notify_one or notify_all.
53 0 : void wait(UniqueLock<Mutex>& lock) {
54 0 : impl_.wait(lock.lock);
55 0 : }
56 :
57 : // As with |wait|, block the current thread of execution until woken from
58 : // another thread. This method will resume waiting once woken until the given
59 : // Predicate |pred| evaluates to true.
60 : template <typename Predicate>
61 : void wait(UniqueLock<Mutex>& lock, Predicate pred) {
62 : while (!pred()) {
63 : wait(lock);
64 : }
65 : }
66 :
67 : // Block the current thread of execution until woken from another thread, or
68 : // the given absolute time is reached. The given absolute time is evaluated
69 : // when this method is called, so will wake up after (abs_time - now),
70 : // independent of system clock changes. While insulated from clock changes,
71 : // this API is succeptible to the issues discussed above wait_for.
72 0 : CVStatus wait_until(UniqueLock<Mutex>& lock,
73 : const mozilla::TimeStamp& abs_time) {
74 0 : return wait_for(lock, abs_time - mozilla::TimeStamp::Now());
75 : }
76 :
77 : // As with |wait_until|, block the current thread of execution until woken
78 : // from another thread, or the given absolute time is reached. This method
79 : // will resume waiting once woken until the given Predicate |pred| evaluates
80 : // to true.
81 : template <typename Predicate>
82 : bool wait_until(UniqueLock<Mutex>& lock, const mozilla::TimeStamp& abs_time,
83 : Predicate pred) {
84 : while (!pred()) {
85 : if (wait_until(lock, abs_time) == CVStatus::Timeout) {
86 : return pred();
87 : }
88 : }
89 : return true;
90 : }
91 :
92 : // Block the current thread of execution until woken from another thread, or
93 : // the given time duration has elapsed. Given that the system may be
94 : // interrupted between the callee and the actual wait beginning, this call
95 : // has a minimum granularity of the system's scheduling interval, and may
96 : // encounter substantially longer delays, depending on system load.
97 91 : CVStatus wait_for(UniqueLock<Mutex>& lock,
98 : const mozilla::TimeDuration& rel_time) {
99 91 : return impl_.wait_for(lock.lock, rel_time) == mozilla::detail::CVStatus::Timeout
100 56 : ? CVStatus::Timeout : CVStatus::NoTimeout;
101 : }
102 :
103 : // As with |wait_for|, block the current thread of execution until woken from
104 : // another thread or the given time duration has elapsed. This method will
105 : // resume waiting once woken until the given Predicate |pred| evaluates to
106 : // true.
107 : template <typename Predicate>
108 : bool wait_for(UniqueLock<Mutex>& lock, const mozilla::TimeDuration& rel_time,
109 : Predicate pred) {
110 : return wait_until(lock, mozilla::TimeStamp::Now() + rel_time,
111 : mozilla::Move(pred));
112 : }
113 :
114 :
115 : private:
116 : ConditionVariable(const ConditionVariable&) = delete;
117 : ConditionVariable& operator=(const ConditionVariable&) = delete;
118 :
119 : mozilla::detail::ConditionVariableImpl impl_;
120 : };
121 :
122 : } // namespace js
123 :
124 : #endif // threading_ConditionVariable_h
|