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