SuperTinyKernel™ RTOS 1.05.3
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 : 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 // API contract: must not be destroyed while tasks are waiting
138 // (checked inside Mutex/ConditionVariable destructors via their own assertions)
139 }
140
141 // -----------------------------------------------------------------------
142 // Flag manipulation
143 // -----------------------------------------------------------------------
144
154 uint32_t Set(uint32_t flags);
155
163 uint32_t Clear(uint32_t flags);
164
171 uint32_t Get() const;
172
173 // -----------------------------------------------------------------------
174 // Waiting
175 // -----------------------------------------------------------------------
176
199 uint32_t Wait(uint32_t flags, uint32_t options = OPT_WAIT_ANY, Timeout timeout = WAIT_INFINITE);
200
209 uint32_t TryWait(uint32_t flags, uint32_t options = OPT_WAIT_ANY)
210 {
211 return Wait(flags, options, NO_WAIT);
212 }
213
214private:
216
217 // Predicate: returns true when the wait condition for 'flags'/'options' is met.
218 // Must be called with m_mutex held.
219 bool IsSatisfied(uint32_t flags, uint32_t options) const
220 {
221 if (options & OPT_WAIT_ALL)
222 return ((m_flags & flags) == flags);
223 else
224 return ((m_flags & flags) != 0U);
225 }
226
227 volatile uint32_t m_flags;
229};
230
231// ---------------------------------------------------------------------------
232// Set
233// ---------------------------------------------------------------------------
234
235inline uint32_t EventFlags::Set(uint32_t flags)
236{
237 if ((flags == 0U) || ((flags & ERROR_MASK) != 0U))
238 return ERROR_PARAMETER;
239
241
242 m_flags |= flags;
243 const uint32_t result = m_flags;
244
245 // wake all waiters: each task will re-evaluate its own predicate
246 m_cv.NotifyAll();
247
248 return result;
249}
250
251// ---------------------------------------------------------------------------
252// Clear
253// ---------------------------------------------------------------------------
254
255inline uint32_t EventFlags::Clear(uint32_t flags)
256{
257 if ((flags == 0U) || ((flags & ERROR_MASK) != 0U))
258 return ERROR_PARAMETER;
259
261
262 const uint32_t prev = m_flags;
263 m_flags &= ~flags;
264
265 return prev;
266}
267
268// ---------------------------------------------------------------------------
269// Get
270// ---------------------------------------------------------------------------
271
272inline uint32_t EventFlags::Get() const
273{
274 // atomic on 32-bit aligned targets, a critical section is not required for
275 // a single-word read, matching the approach used by Semaphore::GetCount()
276 return m_flags;
277}
278
279// ---------------------------------------------------------------------------
280// Wait
281// ---------------------------------------------------------------------------
282
283inline uint32_t EventFlags::Wait(uint32_t flags, uint32_t options, Timeout timeout)
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 return ERROR_PARAMETER;
288
289 // ISR check: only NO_WAIT is permitted inside an ISR
290 if (hw::IsInsideISR() && (timeout != NO_WAIT))
291 return ERROR_ISR;
292
293 const bool timed_wait = (timeout != WAIT_INFINITE) && (timeout != NO_WAIT);
294
295 // capture an absolute deadline once, before entering the wait loop,
296 // this prevents the timeout from being silently restarted on each
297 // spurious wakeup (e.g. a partial Set() that does not satisfy WAIT_ALL)
298 const Timeout deadline = (timed_wait ? static_cast<Timeout>(GetTicks() + timeout) : timeout);
299
301
302 // spin (with blocking) until the predicate is satisfied or we time out
303 while (!IsSatisfied(flags, options))
304 {
305 Timeout remaining = deadline;
306 if (timed_wait)
307 {
308 const Timeout now = static_cast<Timeout>(GetTicks());
309 remaining = (now >= deadline ? NO_WAIT : (deadline - now));
310 }
311
312 if (!m_cv.Wait(cs_, remaining))
313 {
314 // timeout: release the mutex and report failure
315 return ERROR_TIMEOUT;
316 }
317 }
318
319 // predicate satisfied: determine which flags matched
320 const uint32_t matched = (options & OPT_WAIT_ALL ? flags : (m_flags & flags));
321
322 // atomically clear the matched flags unless the caller opted out
323 if ((options & OPT_NO_CLEAR) == 0U)
324 m_flags &= ~matched;
325
326 return matched;
327}
328
329} // namespace sync
330} // namespace stk
331
332#endif /* STK_SYNC_EVENT_FLAGS_H_ */
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
Definition stk_defs.h:330
Implementation of synchronization primitive: stk::sync::ConditionVariable.
Namespace of STK package.
const Timeout WAIT_INFINITE
Timeout value: block indefinitely until the synchronization object is signaled.
Definition stk_common.h:139
Ticks GetTicks()
Get number of ticks elapsed since kernel start.
Definition stk_helper.h:248
int32_t Timeout
Timeout time (ticks).
Definition stk_common.h:133
const Timeout NO_WAIT
Timeout value: return immediately if the synchronization object is not yet signaled (non-blocking pol...
Definition stk_common.h:145
bool IsInsideISR()
Check whether the CPU is currently executing inside a hardware interrupt service routine (ISR).
Definition stktest.cpp:103
Synchronization primitives for task coordination and resource protection.
Traceable object.
Definition stk_common.h:255
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=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
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.
STK_NONCOPYABLE_CLASS(EventFlags)
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.