Refactors test cases
[junction.git] / junction / striped / ManualResetEvent.h
1 /*------------------------------------------------------------------------
2   Junction: Concurrent data structures in C++
3   Copyright (c) 2016 Jeff Preshing
4
5   Distributed under the Simplified BSD License.
6   Original location: https://github.com/preshing/junction
7
8   This software is distributed WITHOUT ANY WARRANTY; without even the
9   implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10   See the LICENSE file for more information.
11 ------------------------------------------------------------------------*/
12
13 #ifndef JUNCTION_STRIPED_MANUALRESETEVENT_H
14 #define JUNCTION_STRIPED_MANUALRESETEVENT_H
15
16 #include <junction/Core.h>
17
18 #if JUNCTION_USE_STRIPING
19
20 //-----------------------------------
21 // Striping enabled
22 //-----------------------------------
23 #include <junction/striped/ConditionBank.h>
24
25 namespace junction {
26 namespace striped {
27
28 class ManualResetEvent {
29 private:
30     JUNCTION_STRIPED_CONDITIONBANK_DEFINE_MEMBER()
31     static const u8 Signaled = 1;
32     static const u8 HasWaiters = 2;
33     turf::Atomic<u8> m_state;
34
35 public:
36     ManualResetEvent(bool initialState = false) : m_state(initialState ? Signaled : 0) {
37     }
38
39     ~ManualResetEvent() {
40     }
41
42     void signal() {
43         u8 prevState = m_state.fetchOr(Signaled, turf::Release); // Synchronizes-with the load in wait (fast path)
44         if (prevState & HasWaiters) {
45             ConditionPair& pair = JUNCTION_STRIPED_CONDITIONBANK_GET(this);
46             turf::LockGuard<turf::Mutex> guard(
47                 pair.mutex); // Prevents the wake from occuring in the middle of wait()'s critical section
48             pair.condVar.wakeAll();
49         }
50     }
51
52     bool isSignaled() const {
53         return m_state.load(turf::Relaxed) & Signaled;
54     }
55
56     void reset() {
57         TURF_ASSERT(0); // FIXME: implement it
58     }
59
60     void wait() {
61         u8 state = m_state.load(turf::Acquire); // Synchronizes-with the fetchOr in signal (fast path)
62         if ((state & Signaled) == 0) {
63             ConditionPair& pair = JUNCTION_STRIPED_CONDITIONBANK_GET(this);
64             turf::LockGuard<turf::Mutex> guard(pair.mutex);
65             for (;;) {
66                 // FIXME: Implement reusable AdaptiveBackoff class and apply it here
67                 state = m_state.load(turf::Relaxed);
68                 if (state & Signaled)
69                     break;
70                 if (state != HasWaiters) {
71                     TURF_ASSERT(state == 0);
72                     if (!m_state.compareExchangeWeak(state, HasWaiters, turf::Relaxed, turf::Relaxed))
73                         continue;
74                 }
75                 // The lock ensures signal can't wakeAll between the load and the wait
76                 pair.condVar.wait(guard);
77             }
78         }
79     }
80 };
81
82 } // namespace striped
83 } // namespace junction
84
85 #else // JUNCTION_USE_STRIPING
86
87 //-----------------------------------
88 // Striping disabled
89 //-----------------------------------
90 #include <turf/ManualResetEvent.h>
91
92 namespace junction {
93 namespace striped {
94 typedef turf::ManualResetEvent ManualResetEvent;
95 } // namespace striped
96 } // namespace junction
97
98 #endif // JUNCTION_USE_STRIPING
99
100 #endif // JUNCTION_STRIPED_MANUALRESETEVENT_H