SuperTinyKernel™ RTOS 1.08.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
107 static const uint32_t ERROR_CANCELED = 0x80000008U;
108
111 static const uint32_t ERROR_FAIL = 0x80000010U;
112
114 static const uint32_t ERROR_MASK = 0x80000000U;
115
116 // -----------------------------------------------------------------------
117 // Validation helpers
118 // -----------------------------------------------------------------------
119
123 static bool IsError(uint32_t result) { return ((result & ERROR_MASK) != 0U); }
124
125 // -----------------------------------------------------------------------
126 // Construction / destruction
127 // -----------------------------------------------------------------------
128
133 explicit EventFlags(uint32_t initial_flags = 0U) : m_flags(initial_flags)
134 {
135 STK_ASSERT((initial_flags & ERROR_MASK) == 0U); // API contract: bit 31 must not be set
136 }
137
144
145 // -----------------------------------------------------------------------
146 // Flag manipulation
147 // -----------------------------------------------------------------------
148
158 uint32_t Set(uint32_t flags);
159
167 uint32_t Clear(uint32_t flags);
168
175 uint32_t Get() const;
176
177 // -----------------------------------------------------------------------
178 // Waiting
179 // -----------------------------------------------------------------------
180
206 uint32_t Wait(uint32_t flags, uint32_t options = OPT_WAIT_ANY, Timeout timeout_ticks = WAIT_INFINITE);
207
216 uint32_t TryWait(uint32_t flags, uint32_t options = OPT_WAIT_ANY)
217 {
218 return Wait(flags, options, NO_WAIT);
219 }
220
221private:
223
224 // Predicate: returns true when the wait condition for 'flags'/'options' is met.
225 // Must be called with m_mutex held.
226 bool IsSatisfied(uint32_t flags, uint32_t options) const
227 {
228 return ((options & OPT_WAIT_ALL) == OPT_WAIT_ALL) ? ((m_flags & flags) == flags) :
229 ((m_flags & flags) != 0U);
230 }
231
232 volatile uint32_t m_flags;
234};
235
236// ---------------------------------------------------------------------------
237// Set
238// ---------------------------------------------------------------------------
239
240inline uint32_t EventFlags::Set(uint32_t flags)
241{
242 uint32_t final_result = ERROR_PARAMETER;
243
244 if ((flags != 0U) && ((flags & ERROR_MASK) == 0U))
245 {
246 const ScopedCriticalSection cs_;
247
248 m_flags |= flags;
249 final_result = m_flags;
250
251 // wake all waiters: each task will re-evaluate its own predicate
252 m_cv.NotifyAll_CS();
253 }
254
255 return final_result;
256}
257
258// ---------------------------------------------------------------------------
259// Clear
260// ---------------------------------------------------------------------------
261
262inline uint32_t EventFlags::Clear(uint32_t flags)
263{
264 uint32_t result = ERROR_PARAMETER;
265
266 if ((flags != 0U) && ((flags & ERROR_MASK) == 0U))
267 {
268 const ScopedCriticalSection cs_;
269
270 result = m_flags;
271 m_flags &= ~flags;
272 }
273
274 return result;
275}
276
277// ---------------------------------------------------------------------------
278// Get
279// ---------------------------------------------------------------------------
280
281inline uint32_t EventFlags::Get() const
282{
283 // atomic on 32-bit aligned targets, a critical section is not required for
284 // a single-word read, matching the approach used by Semaphore::GetCount()
285 return m_flags;
286}
287
288// ---------------------------------------------------------------------------
289// Wait
290// ---------------------------------------------------------------------------
291
292inline uint32_t EventFlags::Wait(uint32_t flags, uint32_t options, Timeout timeout_ticks)
293{
294 uint32_t final_result = 0U;
295
296 // validate: flags must be non-zero and must not have the error sentinel bit set
297 if ((flags == 0U) || ((flags & ERROR_MASK) != 0U))
298 {
299 final_result = ERROR_PARAMETER;
300 }
301 // ISR check: only NO_WAIT is permitted inside an ISR
302 else if (hw::IsInsideISR() && (timeout_ticks != NO_WAIT))
303 {
304 final_result = ERROR_ISR;
305 }
306 else
307 {
308 const bool timed_wait = (timeout_ticks != WAIT_INFINITE) && (timeout_ticks != NO_WAIT);
309
310 // capture an absolute deadline once, before entering the wait loop,
311 // this prevents the timeout from being silently restarted on each
312 // spurious wakeup (e.g. a partial Set() that does not satisfy WAIT_ALL)
313 const Timeout deadline = (timed_wait ?
314 static_cast<Timeout>(GetTicks() + timeout_ticks) : timeout_ticks);
315
317
318 // spin (with blocking) until the predicate is satisfied or we time out
319 while (!IsSatisfied(flags, options))
320 {
321 Timeout remaining = deadline;
322 if (timed_wait)
323 {
324 const Timeout now = static_cast<Timeout>(GetTicks());
325 remaining = (now >= deadline ? NO_WAIT : (deadline - now));
326 }
327
328 const EWaitResult wr = m_cv.WaitEx(cs_, remaining);
329
330 if (wr == WAIT_RESULT_CANCELED)
331 {
332 // cancelled by IKernel::CancelTaskWait(): stop immediately, do not
333 // reinterpret as a timeout and do not keep spinning on the predicate
334 final_result = ERROR_CANCELED;
335 break;
336 }
337 else if (wr == WAIT_RESULT_FAIL)
338 {
339 // kernel rejected the wait: report it as such, not as a timeout
340 final_result = ERROR_FAIL;
341 break;
342 }
343 else if (wr != WAIT_RESULT_SIGNAL)
344 {
345 // timeout (either a real deadline miss, or NO_WAIT after 'remaining'
346 // collapsed to NO_WAIT): mark failure and flag the loop to terminate
347 final_result = ERROR_TIMEOUT;
348 break;
349 }
350 // else: WAIT_RESULT_SIGNAL - a Set() woke us for re-evaluation (possibly a
351 // spurious/partial match under WAIT_ALL); loop back and re-check IsSatisfied()
352 }
353
354 // If we didn't time out or get cancelled, the predicate was satisfied successfully
355 if ((final_result != ERROR_TIMEOUT) && (final_result != ERROR_CANCELED) &&
356 (final_result != ERROR_FAIL))
357 {
358 // predicate satisfied: determine which flags matched
359 final_result = (((options & OPT_WAIT_ALL) == OPT_WAIT_ALL) ? flags : (m_flags & flags));
360
361 // atomically clear the matched flags unless the caller opted out
362 if ((options & OPT_NO_CLEAR) == 0U)
363 {
364 m_flags &= ~final_result;
365 }
366 }
367 }
368
369 return final_result;
370}
371
372} // namespace sync
373} // namespace stk
374
375#endif /* STK_SYNC_EVENT_FLAGS_H_ */
#define STK_NONCOPYABLE_CLASS(TYPE)
Disables copy construction and assignment for a class.
Definition stk_defs.h:708
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
Definition stk_defs.h:516
#define STK_VIRT_DTOR
Makes destructors virtual and compliant to strict rules if STK_STRICT_COMPLIANCY=0.
Definition stk_defs.h:261
Implementation of synchronization primitive: stk::sync::ConditionVariable.
Namespace of STK package.
static constexpr Timeout NO_WAIT
Timeout value: return immediately if the synchronization object is not yet signaled (non-blocking pol...
Definition stk_common.h:220
EWaitResult
Wait result (see IKernelService::Wait).
Definition stk_common.h:123
@ WAIT_RESULT_FAIL
IKernelService::Wait returned with error without waiting.
Definition stk_common.h:124
@ WAIT_RESULT_CANCELED
The wait was cancelled by another task via IKernel::CancelTaskWait(), independent of signal/timeout.
Definition stk_common.h:127
@ WAIT_RESULT_SIGNAL
The wake was caused by a signal.
Definition stk_common.h:125
int32_t Timeout
Timeout time (ticks).
Definition stk_common.h:156
static Ticks GetTicks()
Get number of ticks elapsed since kernel start.
Definition stk_helper.h:438
static constexpr Timeout WAIT_INFINITE
Timeout value: block indefinitely until the synchronization object is signaled.
Definition stk_common.h:214
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:533
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_CANCELED
Return sentinel: the wait was cancelled via IKernel::CancelTaskWait() before the flag condition was m...
static const uint32_t ERROR_ISR
Return sentinel: called from an ISR with a blocking timeout.
static const uint32_t ERROR_FAIL
Return sentinel: the kernel rejected the wait (IKernelService::Wait() returned WAIT_RESULT_FAIL,...
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.