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
227 {
228 return m_cv.GetWaitList();
229 }
230
240 {
241 return m_cv.GetFirstWaiterTid();
242 }
243
244private:
246
247 // Predicate: returns true when the wait condition for 'flags'/'options' is met.
248 // Must be called with m_mutex held.
249 bool IsSatisfied(uint32_t flags, uint32_t options) const
250 {
251 return ((options & OPT_WAIT_ALL) == OPT_WAIT_ALL) ? ((m_flags & flags) == flags) :
252 ((m_flags & flags) != 0U);
253 }
254
255 volatile uint32_t m_flags;
257};
258
259// ---------------------------------------------------------------------------
260// Set
261// ---------------------------------------------------------------------------
262
263inline uint32_t EventFlags::Set(uint32_t flags)
264{
265 uint32_t final_result = ERROR_PARAMETER;
266
267 if ((flags != 0U) && ((flags & ERROR_MASK) == 0U))
268 {
269 const ScopedCriticalSection cs_;
270
271 m_flags |= flags;
272 final_result = m_flags;
273
274 // wake all waiters: each task will re-evaluate its own predicate
275 m_cv.NotifyAll_CS();
276 }
277
278 return final_result;
279}
280
281// ---------------------------------------------------------------------------
282// Clear
283// ---------------------------------------------------------------------------
284
285inline uint32_t EventFlags::Clear(uint32_t flags)
286{
287 uint32_t result = ERROR_PARAMETER;
288
289 if ((flags != 0U) && ((flags & ERROR_MASK) == 0U))
290 {
291 const ScopedCriticalSection cs_;
292
293 result = m_flags;
294 m_flags &= ~flags;
295 }
296
297 return result;
298}
299
300// ---------------------------------------------------------------------------
301// Get
302// ---------------------------------------------------------------------------
303
304inline uint32_t EventFlags::Get() const
305{
306 // atomic on 32-bit aligned targets, a critical section is not required for
307 // a single-word read, matching the approach used by Semaphore::GetCount()
308 return m_flags;
309}
310
311// ---------------------------------------------------------------------------
312// Wait
313// ---------------------------------------------------------------------------
314
315inline uint32_t EventFlags::Wait(uint32_t flags, uint32_t options, Timeout timeout_ticks)
316{
317 uint32_t final_result = 0U;
318
319 // validate: flags must be non-zero and must not have the error sentinel bit set
320 if ((flags == 0U) || ((flags & ERROR_MASK) != 0U))
321 {
322 final_result = ERROR_PARAMETER;
323 }
324 // ISR check: only NO_WAIT is permitted inside an ISR
325 else if (hw::IsInsideISR() && (timeout_ticks != NO_WAIT))
326 {
327 final_result = ERROR_ISR;
328 }
329 else
330 {
331 const bool timed_wait = (timeout_ticks != WAIT_INFINITE) && (timeout_ticks != NO_WAIT);
332
333 // capture an absolute deadline once, before entering the wait loop,
334 // this prevents the timeout from being silently restarted on each
335 // spurious wakeup (e.g. a partial Set() that does not satisfy WAIT_ALL)
336 const Timeout deadline = (timed_wait ?
337 static_cast<Timeout>(GetTicks() + timeout_ticks) : timeout_ticks);
338
340
341 // spin (with blocking) until the predicate is satisfied or we time out
342 while (!IsSatisfied(flags, options))
343 {
344 Timeout remaining = deadline;
345 if (timed_wait)
346 {
347 const Timeout now = static_cast<Timeout>(GetTicks());
348 remaining = (now >= deadline ? NO_WAIT : (deadline - now));
349 }
350
351 const EWaitResult wr = m_cv.WaitEx(cs_, remaining);
352
353 if (wr == WAIT_RESULT_CANCELED)
354 {
355 // cancelled by IKernel::CancelTaskWait(): stop immediately, do not
356 // reinterpret as a timeout and do not keep spinning on the predicate
357 final_result = ERROR_CANCELED;
358 break;
359 }
360 else if (wr == WAIT_RESULT_FAIL)
361 {
362 // kernel rejected the wait: report it as such, not as a timeout
363 final_result = ERROR_FAIL;
364 break;
365 }
366 else if (wr != WAIT_RESULT_SIGNAL)
367 {
368 // timeout (either a real deadline miss, or NO_WAIT after 'remaining'
369 // collapsed to NO_WAIT): mark failure and flag the loop to terminate
370 final_result = ERROR_TIMEOUT;
371 break;
372 }
373 // else: WAIT_RESULT_SIGNAL - a Set() woke us for re-evaluation (possibly a
374 // spurious/partial match under WAIT_ALL); loop back and re-check IsSatisfied()
375 }
376
377 // If we didn't time out or get cancelled, the predicate was satisfied successfully
378 if ((final_result != ERROR_TIMEOUT) && (final_result != ERROR_CANCELED) &&
379 (final_result != ERROR_FAIL))
380 {
381 // predicate satisfied: determine which flags matched
382 final_result = (((options & OPT_WAIT_ALL) == OPT_WAIT_ALL) ? flags : (m_flags & flags));
383
384 // atomically clear the matched flags unless the caller opted out
385 if ((options & OPT_NO_CLEAR) == 0U)
386 {
387 m_flags &= ~final_result;
388 }
389 }
390 }
391
392 return final_result;
393}
394
395} // namespace sync
396} // namespace stk
397
398#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:234
EWaitResult
Wait result (see IKernelService::Wait).
Definition stk_common.h:137
@ WAIT_RESULT_FAIL
IKernelService::Wait returned with error without waiting.
Definition stk_common.h:138
@ WAIT_RESULT_CANCELED
The wait was cancelled by another task via IKernel::CancelTaskWait(), independent of signal/timeout.
Definition stk_common.h:141
@ WAIT_RESULT_SIGNAL
The wake was caused by a signal.
Definition stk_common.h:139
int32_t Timeout
Timeout time (ticks).
Definition stk_common.h:170
static Ticks GetTicks()
Get number of ticks elapsed since kernel start.
Definition stk_helper.h:452
static constexpr Timeout WAIT_INFINITE
Timeout value: block indefinitely until the synchronization object is signaled.
Definition stk_common.h:228
Word TId
Task (thread) id.
Definition stk_common.h:165
bool IsInsideISR()
Check whether the CPU is currently executing inside a hardware interrupt service routine (ISR).
Synchronization primitives for task coordination and resource protection.
DLHeadType ListHeadType
List head type for IWaitObject elements.
Definition stk_common.h:502
Traceable object.
Definition stk_common.h:559
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.
const IWaitObject::ListHeadType & GetWaitList() const
Get list of tasks blocked on this object.
static const uint32_t ERROR_CANCELED
Return sentinel: the wait was cancelled via IKernel::CancelTaskWait() before the flag condition was m...
TId GetFirstWaiterTid() const
Get id of the task which is first in the wait list (FIFO order), i.e. the one that WakeOne() would wa...
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.