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_semaphore.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_SEMAPHORE_H_
11#define STK_SYNC_SEMAPHORE_H_
12
13#include "stk_sync_cs.h"
14
18
19namespace stk {
20namespace sync {
21
55class Semaphore final : private SyncObjectBase, public ITraceable
56{
57public:
60 static const uint16_t COUNT_MAX = 0xFFFEU;
61
71 explicit Semaphore(uint16_t initial_count = 0U, uint16_t max_count = COUNT_MAX)
72 : m_count(initial_count), m_count_max(max_count)
73 {
74 STK_ASSERT(initial_count <= max_count); // API contract: initial count must not exceed maximum
75 }
76
84 {
85 STK_ASSERT(m_wait_list.IsEmpty()); // API contract: must not be destroyed with waiting tasks
86 }
87
97 EWaitResult WaitEx(Timeout timeout_ticks = WAIT_INFINITE);
98
105 bool Wait(Timeout timeout_ticks = WAIT_INFINITE) { return (WaitEx(timeout_ticks) == WAIT_RESULT_SIGNAL); }
106
114 bool TryWait() { return Wait(NO_WAIT); }
115
125 void Signal();
126
138 bool TrySignal();
139
146 uint16_t GetCount() const { return m_count; }
147
148private:
150
151 uint16_t m_count;
152 uint16_t m_count_max;
153};
154
155// ---------------------------------------------------------------------------
156// Wait
157// ---------------------------------------------------------------------------
158
160{
162
163 // NO_WAIT with no token available is reported as an immediately-expired timeout
165
166 // fast path: resource is available
167 if (m_count != 0U)
168 {
169 m_count = static_cast<uint16_t>(m_count - 1U);
170 __stk_full_memfence();
171 result = WAIT_RESULT_SIGNAL;
172 }
173 // slow path: block until Signal() or timeout
174 else if (timeout_ticks != NO_WAIT)
175 {
176 STK_ASSERT(!hw::IsInsideISR()); // API contract: caller must not be in ISR if timeout_ticks!=NO_WAIT
177
178 // note: after waking, if not a timeout, we effectively own the resource that Signal() produced
179 // but didn't put into m_count (see logic of if (m_wait_list.IsEmpty()) in Signal())
180 result = IKernelService::GetInstance()->Wait(this, &cs_, timeout_ticks);
181 }
182 // try lock behavior (timeout_ticks=NO_WAIT)
183 else
184 {
185 // result is WAIT_RESULT_TIMEOUT already, noop
186 }
187
188 return result;
189}
190
191// ---------------------------------------------------------------------------
192// Signal
193// ---------------------------------------------------------------------------
194
195inline void Semaphore::Signal()
196{
197 const bool success = TrySignal();
198 STK_UNUSED(success);
199 STK_ASSERT(success); // API contract: the count must not exceed maximum
200}
201
202// ---------------------------------------------------------------------------
203// TrySignal
204// ---------------------------------------------------------------------------
205
207{
208 const ScopedCriticalSection cs_;
209 bool success = true;
210
211 if (m_wait_list.IsEmpty())
212 {
213 if (m_count >= m_count_max)
214 {
215 // counter already saturated and no one is waiting to hand the token to directly
216 success = false;
217 }
218 else
219 {
220 // no one is waiting, save signal for later
221 m_count = static_cast<uint16_t>(m_count + 1U);
222 __stk_full_memfence();
223 }
224 }
225 else
226 {
227 // give signal directly to the first waiting task
228 WakeOne();
229 }
230
231 return success;
232}
233
234} // namespace sync
235} // namespace stk
236
237#endif /* STK_SYNC_SEMAPHORE_H_ */
#define STK_UNUSED(X)
Explicitly marks a variable as unused to suppress compiler warnings.
Definition stk_defs.h:715
#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::ScopedCriticalSection.
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_TIMEOUT
The wake was caused by a timeout expiry.
Definition stk_common.h:126
@ 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 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
static IKernelService * GetInstance()
Get CPU-local instance of the kernel service.
virtual EWaitResult Wait(ISyncObject *sobj, IMutex *mutex, Timeout timeout)=0
Put calling process into a waiting state until synchronization object is signaled or timeout occurs.
SyncObjectBase()
Constructor.
Definition stk_helper.h:275
IWaitObject::ListHeadType m_wait_list
Tasks blocked on this object.
Definition stk_helper.h:298
void WakeOne() override
Wake the first task in the wait list (FIFO order).
Definition stk_helper.h:283
RAII-style low-level synchronization primitive for atomic code execution. Used as building brick for ...
Definition stk_sync_cs.h:54
void Signal()
Post a signal (increment counter).
uint16_t m_count_max
Counter max limit.
uint16_t m_count
Internal resource counter.
uint16_t GetCount() const
Get current counter value.
static const uint16_t COUNT_MAX
Max count value supported.
bool Wait(Timeout timeout_ticks=WAIT_INFINITE)
Wait for a signal (decrement counter).
bool TrySignal()
Try to post a signal without exceeding max_count.
Semaphore(uint16_t initial_count=0U, uint16_t max_count=COUNT_MAX)
Constructor.
EWaitResult WaitEx(Timeout timeout_ticks=WAIT_INFINITE)
Wait for a signal (decrement counter), preserving the full wait outcome.
bool TryWait()
Poll the semaphore without blocking (decrement counter if available).