Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
WaitableEvent.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include "Common.h"
5
6#if qExecution_WaitableEvent_SupportWaitForMultipleObjects
7#include "Finally.h"
8#include "Thread.h"
9#endif
10
12
13 /*
14 ********************************************************************************
15 ********************** Execution::WaitableEvent::WE_ ***************************
16 ********************************************************************************
17 */
18 inline void WaitableEvent::WE_::Reset ()
19 {
20 /*
21 * NOTE: this code does NOT do a fConditionVariable.MutateDataNotifyAll () - because we dont want anyone to WAKE to discover new data. Resetting the waitable event
22 * is meant to be like destroying it and starting over.
23 */
24 typename ConditionVariable<>::QuickLockType critSection{fConditionVariable.fMutex};
25 fTriggered = false;
26 }
27 inline bool WaitableEvent::WE_::GetIsSet () const noexcept
28 {
29 typename ConditionVariable<>::QuickLockType critSection{fConditionVariable.fMutex};
30 return fTriggered;
31 }
32 inline bool WaitableEvent::WE_::PeekIsSet () const noexcept
33 {
34 return fTriggered;
35 }
36 inline void WaitableEvent::WE_::Set ()
37 {
38 fConditionVariable.MutateDataNotifyAll ([this] () { fTriggered = true; });
39 }
40
41 /*
42 ********************************************************************************
43 *************************** Execution::WaitableEvent ***************************
44 ********************************************************************************
45 */
46 inline WaitableEvent::WaitableEvent ()
47 : fWE_{}
48 {
49 }
50 inline void WaitableEvent::Reset ()
51 {
52 //Debug::TraceContextBumper ctx{"WaitableEvent::Reset"};
53 fWE_.Reset ();
54 }
55 inline bool WaitableEvent::GetIsSet () const noexcept
56 {
57 return fWE_.GetIsSet ();
58 }
59 inline bool WaitableEvent::PeekIsSet () const noexcept
60 {
61 return fWE_.PeekIsSet ();
62 }
63 inline void WaitableEvent::Wait (Time::DurationSeconds timeout)
64 {
65 fWE_.WaitUntil (timeout + Time::GetTickCount ());
66 }
67 inline auto WaitableEvent::WaitQuietly (Time::DurationSeconds timeout) -> WaitStatus
68 {
69 return fWE_.WaitUntilQuietly (timeout + Time::GetTickCount ());
70 }
71 inline void WaitableEvent::WaitUntil (Time::TimePointSeconds timeoutAt)
72 {
73 fWE_.WaitUntil (timeoutAt);
74 }
75 inline auto WaitableEvent::WaitUntilQuietly (Time::TimePointSeconds timeoutAt) -> WaitStatus
76 {
77 return fWE_.WaitUntilQuietly (timeoutAt);
78 }
79 inline void WaitableEvent::WaitAndReset (Time::Duration timeout)
80 {
81 Wait (timeout);
82 //Require (fWE_.fTriggered); // This wait-and-reset approach only really works with a single waiter (else this is a race) - so caller must use that way
83 Reset ();
84 }
85 inline void WaitableEvent::WaitUntilAndReset (Time::TimePointSeconds timeoutAt)
86 {
87 WaitUntil (timeoutAt);
88 //Require (fWE_.fTriggered); // This wait-and-reset approach only really works with a single waiter (else this is a race) - so caller must use that way
89 Reset ();
90 }
91 inline auto WaitableEvent::WaitQuietlyAndReset (const Time::Duration& timeout) -> WaitStatus
92 {
93 auto r = WaitQuietly (timeout);
94 // Require (fWE_.fTriggered); // This wait-and-reset approach only really works with a single waiter (else this is a race) - so caller must use that way
95 Reset ();
96 return r;
97 }
98 inline auto WaitableEvent::WaitUntilQuietlyAndReset (Time::TimePointSeconds timeoutAt) -> WaitStatus
99 {
100 auto r = WaitUntilQuietly (timeoutAt);
101 // Require (fWE_.fTriggered); // This wait-and-reset approach only really works with a single waiter (else this is a race) - so caller must use that way
102 Reset ();
103 return r;
104 }
105#if qExecution_WaitableEvent_SupportWaitForMultipleObjects
106 template <typename CONTAINER_OF_WAITABLE_EVENTS, typename SET_OF_WAITABLE_EVENTS_RESULT>
107 inline SET_OF_WAITABLE_EVENTS_RESULT WaitableEvent::WaitForAny (CONTAINER_OF_WAITABLE_EVENTS waitableEvents, Time::DurationSeconds timeout)
108 {
109 return WaitForAnyUntil (waitableEvents, timeout + Time::GetTickCount ());
110 }
111 template <typename ITERATOR_OF_WAITABLE_EVENTS, typename SET_OF_WAITABLE_EVENTS_RESULT>
112 inline SET_OF_WAITABLE_EVENTS_RESULT WaitableEvent::WaitForAny (ITERATOR_OF_WAITABLE_EVENTS waitableEventsStart,
113 ITERATOR_OF_WAITABLE_EVENTS waitableEventsEnd, Time::DurationSeconds timeout)
114 {
115 return WaitForAnyUntil (waitableEventsStart, waitableEventsEnd, timeout + Time::GetTickCount ());
116 }
117 template <typename CONTAINER_OF_WAITABLE_EVENTS, typename SET_OF_WAITABLE_EVENTS_RESULT>
118 inline SET_OF_WAITABLE_EVENTS_RESULT WaitableEvent::WaitForAnyUntil (CONTAINER_OF_WAITABLE_EVENTS waitableEvents, Time::TimePointSeconds timeoutAt)
119 {
120 return WaitForAnyUntil (begin (waitableEvents), end (waitableEvents), timeoutAt);
121 }
122 template <typename ITERATOR_OF_WAITABLE_EVENTS, typename SET_OF_WAITABLE_EVENTS_RESULT>
123 SET_OF_WAITABLE_EVENTS_RESULT WaitableEvent::WaitForAnyUntil (ITERATOR_OF_WAITABLE_EVENTS waitableEventsStart,
124 ITERATOR_OF_WAITABLE_EVENTS waitableEventsEnd, Time::TimePointSeconds timeoutAt)
125 {
126 SET_OF_WAITABLE_EVENTS_RESULT result;
127 /*
128 * Create another WE as shared.
129 * Stick it onto the list for each waitablevent
130 * Wait on 'new private fake' enevt (and if it succeeeds, then check orig events and return right now)
131 * Either way - undo additions
132 *
133 * <<< @todo DOCUMENT AND EXPLAIN MUTEX >>>
134 */
135 shared_ptr<WE_> we = make_shared<WE_> (eAutoReset);
136 [[maybe_unused]] auto&& cleanup = Finally ([we, waitableEventsStart, waitableEventsEnd] () noexcept {
137 Thread::SuppressInterruptionInContext suppressThreadInterrupts;
138 [[maybe_unused]] auto&& critSec = lock_guard{sExtraWaitableEventsMutex_};
139 for (ITERATOR_OF_WAITABLE_EVENTS i = waitableEventsStart; i != waitableEventsEnd; ++i) {
140 (*i)->fExtraWaitableEvents_.remove (we);
141 }
142 });
143 {
144 [[maybe_unused]] lock_guard critSec{sExtraWaitableEventsMutex_};
145 for (ITERATOR_OF_WAITABLE_EVENTS i = waitableEventsStart; i != waitableEventsEnd; ++i) {
146 (*i)->fExtraWaitableEvents_.push_front (we);
147 }
148 }
149 while (result.empty ()) {
150 we->WaitUntil (timeoutAt);
151 for (ITERATOR_OF_WAITABLE_EVENTS i = waitableEventsStart; i != waitableEventsEnd; ++i) {
152 WaitableEvent* we2Test = *i;
153 if (we2Test->fWE_.PeekIsSet ()) {
154 if (we2Test->fWE_.fResetType == eAutoReset) {
155 we2Test->fWE_.Reset ();
156 }
157 result.insert (we2Test);
158 }
159 }
160 }
161 return result;
162 }
163 template <typename CONTAINER_OF_WAITABLE_EVENTS>
164 inline void WaitableEvent::WaitForAll (CONTAINER_OF_WAITABLE_EVENTS waitableEvents, Time::DurationSeconds timeout)
165 {
166 WaitForAllUntil (waitableEvents, timeout + Time::GetTickCount ());
167 }
168 template <typename ITERATOR_OF_WAITABLE_EVENTS>
169 inline void WaitableEvent::WaitForAll (ITERATOR_OF_WAITABLE_EVENTS waitableEventsStart, ITERATOR_OF_WAITABLE_EVENTS waitableEventsEnd,
170 Time::DurationSeconds timeout)
171 {
172 WaitForAllUntil (waitableEventsStart, waitableEventsEnd, timeout + Time::GetTickCount ());
173 }
174 template <typename CONTAINER_OF_WAITABLE_EVENTS>
175 inline void WaitableEvent::WaitForAllUntil (CONTAINER_OF_WAITABLE_EVENTS waitableEvents, Time::TimePointSeconds timeoutAt)
176 {
177 WaitForAllUntil (begin (waitableEvents), end (waitableEvents), timeoutAt);
178 }
179 template <typename ITERATOR_OF_WAITABLE_EVENTS>
180 void WaitableEvent::WaitForAllUntil (ITERATOR_OF_WAITABLE_EVENTS waitableEventsStart, ITERATOR_OF_WAITABLE_EVENTS waitableEventsEnd,
181 Time::TimePointSeconds timeoutAt)
182 {
183 /*
184 * Create another WE as shared.
185 * Stick it onto the list for each waitablevent
186 * Wait on 'new private fake' enevt (and if it succeeeds, then check orig events and return right now)
187 * Either way - undo additions
188 *
189 * <<< @todo DOCUMENT AND EXPLAIN MUTEX >>>
190 */
191 shared_ptr<WE_> we = make_shared<WE_> (eAutoReset);
192 [[maybe_unused]] auto&& cleanup = Finally ([we, waitableEventsStart, waitableEventsEnd] () noexcept {
193 Thread::SuppressInterruptionInContext suppressThreadInterrupts;
194 [[maybe_unused]] auto&& critSec = lock_guard{sExtraWaitableEventsMutex_};
195 for (ITERATOR_OF_WAITABLE_EVENTS i = waitableEventsStart; i != waitableEventsEnd; ++i) {
196 (*i)->fExtraWaitableEvents_.remove (we);
197 }
198 });
199 {
200 [[maybe_unused]] lock_guard critSec{sExtraWaitableEventsMutex_};
201 for (ITERATOR_OF_WAITABLE_EVENTS i = waitableEventsStart; i != waitableEventsEnd; ++i) {
202 (*i)->fExtraWaitableEvents_.push_front (we);
203 }
204 }
205 while (true) {
206 we->WaitUntil (timeoutAt);
207 bool anyStillWaiting = false;
208 for (ITERATOR_OF_WAITABLE_EVENTS i = waitableEventsStart; i != waitableEventsEnd; ++i) {
209 WaitableEvent* we2Test = *i;
210 RequireNotNull (we2Test);
211 if (not we2Test->fWE_.PeekIsSet ()) {
212 anyStillWaiting = true;
213 }
214 }
215 if (anyStillWaiting) {
216 continue;
217 }
218 else {
219 for (ITERATOR_OF_WAITABLE_EVENTS i = waitableEventsStart; i != waitableEventsEnd; ++i) {
220 WaitableEvent* we2Test = *i;
221 RequireNotNull (we2Test);
222 if (we2Test->fWE_.fResetType == eAutoReset) {
223 Assert (we2Test->fWE_.PeekIsSet ()); // we probably need some mechanism to assure this is true but we currently have no enforcement of this!
224 we2Test->fWE_.Reset ();
225 }
226 }
227 return; // success
228 }
229 }
230 }
231#endif
232}
233
235 DISABLE_COMPILER_MSC_WARNING_START (4996);
236 DISABLE_COMPILER_GCC_WARNING_START ("GCC diagnostic ignored \"-Wdeprecated-declarations\"");
237 DISABLE_COMPILER_CLANG_WARNING_START ("clang diagnostic ignored \"-Wdeprecated-declarations\"");
238 template <>
239 constexpr EnumNames<Execution::WaitableEvent::ResetType> DefaultNames<Execution::WaitableEvent::ResetType>::k{{{
240 {Execution::WaitableEvent::ResetType::eAutoReset, L"AutoReset"},
241 {Execution::WaitableEvent::ResetType::eManualReset, L"ManualReset"},
242 }}};
243 DISABLE_COMPILER_MSC_WARNING_END (4996);
244 DISABLE_COMPILER_GCC_WARNING_END ("GCC diagnostic ignored \"-Wdeprecated-declarations\"");
245 DISABLE_COMPILER_CLANG_WARNING_END ("clang diagnostic ignored \"-Wdeprecated-declarations\"");
246 template <>
247 constexpr EnumNames<Execution::WaitableEvent::WaitStatus> DefaultNames<Execution::WaitableEvent::WaitStatus>::k{{{
248 {Execution::WaitableEvent::WaitStatus::eTimeout, L"Timeout"},
249 {Execution::WaitableEvent::WaitStatus::eTriggered, L"Triggered"},
250 }}};
251}
#define RequireNotNull(p)
Definition Assertions.h:347
time_point< RealtimeClock, DurationSeconds > TimePointSeconds
TimePointSeconds is a simpler approach to chrono::time_point, which doesn't require using templates e...
Definition Realtime.h:82
chrono::duration< double > DurationSeconds
chrono::duration<double> - a time span (length of time) measured in seconds, but high precision.
Definition Realtime.h:57
Duration is a chrono::duration<double> (=.
Definition Duration.h:96
auto Finally(FUNCTION &&f) -> Private_::FinallySentry< FUNCTION >
Definition Finally.inl:31