SuperTinyKernel™ RTOS 1.06.x
Lightweight, high-performance, deterministic, bare-metal C++ RTOS for resource-constrained embedded systems. MIT Open Source License.
Loading...
Searching...
No Matches
stk_sync_eventflags.h
Go to the documentation of this file.
1/*
2 * SuperTinyKernel(TM) RTOS: Lightweight High-Performance Deterministic C++ RTOS for Embedded Systems.
3 *
4 * Source: https://github.com/SuperTinyKernel-RTOS
5 *
6 * Copyright (c) 2022-2026 Neutron Code Limited <stk@neutroncode.com>. All Rights Reserved.
7 * License: MIT License, see LICENSE for a full text.
8 */
9
10#ifndef STK_SYNC_EVENT_FLAGS_H_
11#define STK_SYNC_EVENT_FLAGS_H_
12
13#include "stk_sync_cv.h"
14
18
19namespace stk {
20namespace sync {
21
75class EventFlags final : public ITraceable
76{
77public:
78
79 // -----------------------------------------------------------------------
80 // Options constants (bitmask, passed to Wait())
81 // -----------------------------------------------------------------------
82
84 static const uint32_t OPT_WAIT_ANY = 0x00000000U;
85
87 static const uint32_t OPT_WAIT_ALL = 0x00000001U;
88
90 static const uint32_t OPT_NO_CLEAR = 0x00000002U;
91
92 // -----------------------------------------------------------------------
93 // Return-value error sentinels (bit 31 is the error indicator)
94 // -----------------------------------------------------------------------
95
97 static const uint32_t ERROR_PARAMETER = 0x80000001U;
98
100 static const uint32_t ERROR_TIMEOUT = 0x80000002U;
101
103 static const uint32_t ERROR_ISR = 0x80000004U;
104
106 static const uint32_t ERROR_MASK = 0x80000000U;
107
108 // -----------------------------------------------------------------------
109 // Validation helpers
110 // -----------------------------------------------------------------------
111
115 static bool IsError(uint32_t result) { return ((result & ERROR_MASK) != 0U); }
116
117 // -----------------------------------------------------------------------
118 // Construction / destruction
119 // -----------------------------------------------------------------------
120
125 explicit EventFlags(uint32_t initial_flags = 0U) : m_flags(initial_flags)
126 {
127 STK_ASSERT((initial_flags & ERROR_MASK) == 0U); // API contract: bit 31 must not be set
128 }
129
136
137 // -----------------------------------------------------------------------
138 // Flag manipulation
139 // -----------------------------------------------------------------------
140
150 uint32_t Set(uint32_t flags);
151
159 uint32_t Clear(uint32_t flags);
160
167 uint32_t Get() const;
168
169 // -----------------------------------------------------------------------
170 // Waiting
171 // -----------------------------------------------------------------------
172
195 uint32_t Wait(uint32_t flags, uint32_t options = OPT_WAIT_ANY, Timeout timeout_ticks = WAIT_INFINITE);
196
205 uint32_t TryWait(uint32_t flags, uint32_t options = OPT_WAIT_ANY)
206 {
207 return Wait(flags, options, NO_WAIT);
208 }
209
210private:
212
213 // Predicate: returns true when the wait condition for 'flags'/'options' is met.
214 // Must be called with m_mutex held.
215 bool IsSatisfied(uint32_t flags, uint32_t options) const
216 {
217 return ((options & OPT_WAIT_ALL) == OPT_WAIT_ALL) ? ((m_flags & flags) == flags) :
218 ((m_flags & flags) != 0U);
219 }
220
221 volatile uint32_t m_flags;
223};
224
225// ---------------------------------------------------------------------------
226// Set
227// ---------------------------------------------------------------------------
228
229inline uint32_t EventFlags::Set(uint32_t flags)
230{
231 uint32_t final_result = ERROR_PARAMETER;
232
233 if ((flags != 0U) && ((flags & ERROR_MASK) == 0U))
234 {
235 const ScopedCriticalSection cs_;
236
237 m_flags |= flags;
238 final_result = m_flags;
239
240 // wake all waiters: each task will re-evaluate its own predicate
241 m_cv.NotifyAll();
242 }
243
244 return final_result;
245}
246
247// ---------------------------------------------------------------------------
248// Clear
249// ---------------------------------------------------------------------------
250
251inline uint32_t EventFlags::Clear(uint32_t flags)
252{
253 uint32_t result = ERROR_PARAMETER;
254
255 if ((flags != 0U) && ((flags & ERROR_MASK) == 0U))
256 {
257 const ScopedCriticalSection cs_;
258
259 result = m_flags;
260 m_flags &= ~flags;
261 }
262
263 return result;
264}
265
266// ---------------------------------------------------------------------------
267// Get
268// ---------------------------------------------------------------------------
269
270inline uint32_t EventFlags::Get() const
271{
272 // atomic on 32-bit aligned targets, a critical section is not required for
273 // a single-word read, matching the approach used by Semaphore::GetCount()
274 return m_flags;
275}
276
277// ---------------------------------------------------------------------------
278// Wait
279// ---------------------------------------------------------------------------
280
281inline uint32_t EventFlags::Wait(uint32_t flags, uint32_t options, Timeout timeout_ticks)
282{
283 uint32_t final_result = 0U;
284
285 // validate: flags must be non-zero and must not have the error sentinel bit set
286 if ((flags == 0U) || ((flags & ERROR_MASK) != 0U))
287 {
288 final_result = ERROR_PARAMETER;
289 }
290 // ISR check: only NO_WAIT is permitted inside an ISR
291 else if (hw::IsInsideISR() && (timeout_ticks != NO_WAIT))
292 {
293 final_result = ERROR_ISR;
294 }
295 else
296 {
297 const bool timed_wait = (timeout_ticks != WAIT_INFINITE) && (timeout_ticks != NO_WAIT);
298
299 // capture an absolute deadline once, before entering the wait loop,
300 // this prevents the timeout from being silently restarted on each
301 // spurious wakeup (e.g. a partial Set() that does not satisfy WAIT_ALL)
302 const Timeout deadline = (timed_wait ?
303 static_cast<Timeout>(GetTicks() + timeout_ticks) : timeout_ticks);
304
306
307 // spin (with blocking) until the predicate is satisfied or we time out
308 while (!IsSatisfied(flags, options))
309 {
310 Timeout remaining = deadline;
311 if (timed_wait)
312 {
313 const Timeout now = static_cast<Timeout>(GetTicks());
314 remaining = (now >= deadline ? NO_WAIT : (deadline - now));
315 }
316
317 if (!m_cv.Wait(cs_, remaining))
318 {
319 // timeout: mark failure and flag the loop to terminate
320 final_result = ERROR_TIMEOUT;
321 break;
322 }
323 }
324
325 // If we didn't time out, the predicate was satisfied successfully
326 if (final_result != ERROR_TIMEOUT)
327 {
328 // predicate satisfied: determine which flags matched
329 final_result = (((options & OPT_WAIT_ALL) == OPT_WAIT_ALL) ? flags : (m_flags & flags));
330
331 // atomically clear the matched flags unless the caller opted out
332 if ((options & OPT_NO_CLEAR) == 0U)
333 {
334 m_flags &= ~final_result;
335 }
336 }
337 }
338
339 return final_result;
340}
341
342} // namespace sync
343} // namespace stk
344
345#endif /* STK_SYNC_EVENT_FLAGS_H_ */
#define STK_NONCOPYABLE_CLASS(TYPE)
Disables copy construction and assignment for a class.
Definition stk_defs.h:601
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
Definition stk_defs.h:409
#define STK_VIRT_DTOR
Makes destructors virtual and compliant to strict rules if STK_STRICT_COMPLIANCY=0.
Definition stk_defs.h:159
Implementation of synchronization primitive: stk::sync::ConditionVariable.
Namespace of STK package.
constexpr Timeout NO_WAIT
Timeout value: return immediately if the synchronization object is not yet signaled (non-blocking pol...
Definition stk_common.h:189
int32_t Timeout
Timeout time (ticks).
Definition stk_common.h:125
static Ticks GetTicks()
Get number of ticks elapsed since kernel start.
Definition stk_helper.h:319
constexpr Timeout WAIT_INFINITE
Timeout value: block indefinitely until the synchronization object is signaled.
Definition stk_common.h:183
bool IsInsideISR()
Check whether the CPU is currently executing inside a hardware interrupt service routine (ISR).
Synchronization primitives for task coordination and resource protection.
Traceable object.
Definition stk_common.h:393
RAII-style low-level synchronization primitive for atomic code execution. Used as building brick for ...
Definition stk_sync_cs.h:54
Condition Variable primitive for signaling between tasks based on specific predicates.
Definition stk_sync_cv.h:68
uint32_t Wait(uint32_t flags, uint32_t options=OPT_WAIT_ANY, Timeout timeout_ticks=WAIT_INFINITE)
Wait for one or more flags to be set.
uint32_t Get() const
Read the current flags word without modifying it.
ConditionVariable m_cv
woken by Set() to re-evaluate waiting tasks
~EventFlags()=default
Destructor.
volatile uint32_t m_flags
32-bit flags word (bit 31 is reserved for errors)
uint32_t TryWait(uint32_t flags, uint32_t options=OPT_WAIT_ANY)
Non-blocking flag poll.
static const uint32_t ERROR_ISR
Return sentinel: called from an ISR with a blocking timeout.
static const uint32_t ERROR_TIMEOUT
Return sentinel: wait timed out before the flags condition was met.
static bool IsError(uint32_t result)
Checks if a return value from Set(), Clear(), or Wait() is an error.
static const uint32_t OPT_NO_CLEAR
Do not clear matched flags after a successful wait.
static const uint32_t ERROR_PARAMETER
Return sentinel: invalid flags argument (bit 31 set).
static const uint32_t OPT_WAIT_ALL
Wait for ALL of the specified flags to be set simultaneously (AND semantics).
bool IsSatisfied(uint32_t flags, uint32_t options) const
EventFlags(uint32_t initial_flags=0U)
Constructor.
uint32_t Clear(uint32_t flags)
Clear one or more flags.
static const uint32_t OPT_WAIT_ANY
Wait for ANY of the specified flags to be set (OR semantics, default).
uint32_t Set(uint32_t flags)
Set one or more flags.
static const uint32_t ERROR_MASK
Reserved error mask. Any return value with bit 31 set is an error.