Initial commit
[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(pair.mutex);   // Prevents the wake from occuring in the middle of wait()'s critical section
47             pair.condVar.wakeAll();
48         }
49     }
50
51     bool isSignaled() const {
52         return m_state.load(turf::Relaxed) & Signaled;
53     }
54
55     void reset() {
56         TURF_ASSERT(0); // FIXME: implement it
57     }
58
59     void wait() {
60         u8 state = m_state.load(turf::Acquire);     // Synchronizes-with the fetchOr in signal (fast path)
61         if ((state & Signaled) == 0) {
62             ConditionPair& pair = JUNCTION_STRIPED_CONDITIONBANK_GET(this);
63             turf::LockGuard<turf::Mutex> guard(pair.mutex);
64             for (;;) {
65                 // FIXME: Implement reusable AdaptiveBackoff class and apply it here
66                 state = m_state.load(turf::Relaxed);
67                 if (state & Signaled)
68                     break;
69                 if (state != HasWaiters) {
70                     TURF_ASSERT(state == 0);
71                     if (!m_state.compareExchangeWeak(state, HasWaiters, turf::Relaxed, turf::Relaxed))
72                         continue;
73                 }
74                 // The lock ensures signal can't wakeAll between the load and the wait
75                 pair.condVar.wait(guard);
76             }
77         }
78     }
79 };
80
81 } // namespace striped
82 } // namespace junction
83
84 #else // JUNCTION_USE_STRIPING
85
86 //-----------------------------------
87 // Striping disabled
88 //-----------------------------------
89 #include <turf/ManualResetEvent.h>
90
91 namespace junction {
92 namespace striped {
93 typedef turf::ManualResetEvent ManualResetEvent;
94 } // namespace striped
95 } // namespace junction
96
97 #endif // JUNCTION_USE_STRIPING
98
99 #endif // JUNCTION_STRIPED_MANUALRESETEVENT_H