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_c_sync.cpp
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#include <cstddef> // for std::size_t
11
12#include <stk_config.h>
13#include <stk.h>
14#include <sync/stk_sync.h>
15#include "stk_c.h"
16
17using namespace stk;
18using namespace stk::sync;
19
20inline void *operator new(std::size_t, void *ptr) noexcept { return ptr; }
21inline void operator delete(void *, void *) noexcept { /* nothing for placement delete */ }
22
23// ---------------------------------------------------------------------------
24// C-interface
25// ---------------------------------------------------------------------------
26extern "C" {
27
28// ---------------------------------------------------------------------------
29// Mutex
30// ---------------------------------------------------------------------------
32{
34};
35
36stk_mutex_t *stk_mutex_create(stk_mutex_mem_t *memory, uint32_t memory_size)
37{
38 STK_ASSERT(memory != nullptr);
39 STK_ASSERT(memory_size >= sizeof(stk_mutex_t));
40 if (memory_size < sizeof(stk_mutex_t))
41 return nullptr;
42
43 // construct in-place within the provided memory
44 return (stk_mutex_t *)new (memory->data) stk_mutex_t{};
45}
46
48{
49 if (mtx != NULL)
50 mtx->~stk_mutex_t();
51}
52
54{
55 STK_ASSERT(mtx != NULL);
56
57 mtx->handle.Lock();
58}
59
61{
62 STK_ASSERT(mtx != NULL);
63
64 return mtx->handle.TryLock();
65}
66
68{
69 STK_ASSERT(mtx != NULL);
70
71 mtx->handle.Unlock();
72}
73
74bool stk_mutex_timed_lock(stk_mutex_t *mtx, int32_t timeout)
75{
76 STK_ASSERT(mtx != NULL);
77
78 return mtx->handle.TimedLock(timeout);
79}
80
81// ---------------------------------------------------------------------------
82// SpinLock
83// ---------------------------------------------------------------------------
88
90{
91 STK_ASSERT(memory != nullptr);
92 STK_ASSERT(memory_size >= sizeof(stk_spinlock_t));
93 if (memory_size < sizeof(stk_spinlock_t))
94 return nullptr;
95
96 return (stk_spinlock_t *)new (memory->data) stk_spinlock_t();
97}
98
100{
101 if (lock != nullptr)
102 lock->~stk_spinlock_t();
103}
104
106{
107 STK_ASSERT(lock != nullptr);
108 lock->handle.Lock();
109}
110
112{
113 STK_ASSERT(lock != nullptr);
114 return lock->handle.TryLock();
115}
116
118{
119 STK_ASSERT(lock != nullptr);
120 lock->handle.Unlock();
121}
122
123// ---------------------------------------------------------------------------
124// ConditionVariable
125// ---------------------------------------------------------------------------
130
131stk_cv_t *stk_cv_create(stk_cv_mem_t *memory, uint32_t memory_size)
132{
133 STK_ASSERT(memory != nullptr);
134 STK_ASSERT(memory_size >= sizeof(stk_cv_t));
135 if (memory_size < sizeof(stk_cv_t))
136 return nullptr;
137
138 // construct in-place within the provided memory
139 return (stk_cv_t *)new (memory->data) stk_cv_t{};
140}
141
143{
144 if (cv != nullptr)
145 cv->~stk_cv_t();
146}
147
148bool stk_cv_wait(stk_cv_t *cv, stk_mutex_t *mtx, int32_t timeout)
149{
150 STK_ASSERT(cv != nullptr);
151 STK_ASSERT(mtx != nullptr);
152
153 return cv->handle.Wait(mtx->handle, timeout);
154}
155
157{
158 STK_ASSERT(cv != nullptr);
159
160 cv->handle.NotifyOne();
161}
162
164{
165 STK_ASSERT(cv != nullptr);
166
167 cv->handle.NotifyAll();
168}
169
170// ---------------------------------------------------------------------------
171// Event
172// ---------------------------------------------------------------------------
174{
175 stk_event_t(bool manual_reset) : handle(manual_reset)
176 {}
177
179};
180
181stk_event_t *stk_event_create(stk_event_mem_t *memory, uint32_t memory_size, bool manual_reset)
182{
183 STK_ASSERT(memory != nullptr);
184 STK_ASSERT(memory_size >= sizeof(stk_event_t));
185 if (memory_size < sizeof(stk_event_t))
186 return nullptr;
187
188 return (stk_event_t *)new (memory->data) stk_event_t(manual_reset);
189}
190
192{
193 if (ev != nullptr)
194 ev->~stk_event_t();
195}
196
197bool stk_event_wait(stk_event_t *ev, int32_t timeout)
198{
199 STK_ASSERT(ev != nullptr);
200
201 return ev->handle.Wait(timeout);
202}
203
205{
206 STK_ASSERT(ev != nullptr);
207
208 return ev->handle.TryWait();
209}
210
212{
213 STK_ASSERT(ev != nullptr);
214
215 ev->handle.Set();
216}
217
219{
220 STK_ASSERT(ev != nullptr);
221
222 ev->handle.Reset();
223}
224
226{
227 STK_ASSERT(ev != nullptr);
228
229 ev->handle.Pulse();
230}
231
232// ---------------------------------------------------------------------------
233// Semaphore
234// ---------------------------------------------------------------------------
236{
237 stk_sem_t(uint32_t initial_count) : handle(initial_count)
238 {}
239
241};
242
243stk_sem_t *stk_sem_create(stk_sem_mem_t *memory, uint32_t memory_size, uint32_t initial_count)
244{
245 STK_ASSERT(memory != nullptr);
246 STK_ASSERT(memory_size >= sizeof(stk_sem_t));
247 if (memory_size < sizeof(stk_sem_t))
248 return nullptr;
249
250 return (stk_sem_t *)new (memory->data) stk_sem_t(initial_count);
251}
252
254{
255 if (sem != nullptr)
256 sem->~stk_sem_t();
257}
258
259bool stk_sem_wait(stk_sem_t *sem, int32_t timeout)
260{
261 STK_ASSERT(sem != nullptr);
262
263 return sem->handle.Wait(timeout);
264}
265
267{
268 STK_ASSERT(sem != nullptr);
269
270 sem->handle.Signal();
271}
272
273// ---------------------------------------------------------------------------
274// EventFlags
275// ---------------------------------------------------------------------------
277{
278 stk_ef_t(uint32_t initial_flags) : handle(initial_flags)
279 {}
280
282};
283
284stk_ef_t *stk_ef_create(stk_ef_mem_t *memory, uint32_t memory_size, uint32_t initial_flags)
285{
286 STK_ASSERT(memory != nullptr);
287 STK_ASSERT(memory_size >= sizeof(stk_ef_t));
288 if (memory_size < sizeof(stk_ef_t))
289 return nullptr;
290
291 return (stk_ef_t *)new (memory->data) stk_ef_t(initial_flags);
292}
293
295{
296 if (ef != nullptr)
297 ef->~stk_ef_t();
298}
299
300uint32_t stk_ef_set(stk_ef_t *ef, uint32_t flags)
301{
302 STK_ASSERT(ef != nullptr);
303
304 return ef->handle.Set(flags);
305}
306
307uint32_t stk_ef_clear(stk_ef_t *ef, uint32_t flags)
308{
309 STK_ASSERT(ef != nullptr);
310
311 return ef->handle.Clear(flags);
312}
313
314uint32_t stk_ef_get(stk_ef_t *ef)
315{
316 STK_ASSERT(ef != nullptr);
317
318 return ef->handle.Get();
319}
320
321uint32_t stk_ef_wait(stk_ef_t *ef, uint32_t flags, uint32_t options, int32_t timeout)
322{
323 STK_ASSERT(ef != nullptr);
324
325 return ef->handle.Wait(flags, options, timeout);
326}
327
328uint32_t stk_ef_trywait(stk_ef_t *ef, uint32_t flags, uint32_t options)
329{
330 STK_ASSERT(ef != nullptr);
331
332 return ef->handle.TryWait(flags, options);
333}
334
335// ---------------------------------------------------------------------------
336// Pipe (template instantiation for stk_word_t, STK_PIPE_SIZE)
337// ---------------------------------------------------------------------------
339
341{
343};
344
345stk_pipe_t *stk_pipe_create(stk_pipe_mem_t *memory, uint32_t memory_size)
346{
347 STK_ASSERT(memory != nullptr);
348 STK_ASSERT(memory_size >= sizeof(stk_pipe_t));
349 if (memory_size < sizeof(stk_pipe_t))
350 return nullptr;
351
352 return (stk_pipe_t *)new (memory->data) stk_pipe_t{};
353}
354
356{
357 if (pipe != nullptr)
358 pipe->~stk_pipe_t();
359}
360
361bool stk_pipe_write(stk_pipe_t *pipe, stk_word_t data, int32_t timeout)
362{
363 STK_ASSERT(pipe != nullptr);
364
365 return pipe->handle.Write(data, timeout);
366}
367
368bool stk_pipe_read(stk_pipe_t *pipe, stk_word_t *data, int32_t timeout)
369{
370 STK_ASSERT(pipe != nullptr);
371 STK_ASSERT(data != nullptr);
372
373 return pipe->handle.Read(*data, timeout);
374}
375
376size_t stk_pipe_write_bulk(stk_pipe_t *pipe, const stk_word_t *src, size_t count, int32_t timeout)
377{
378 STK_ASSERT(pipe != nullptr);
379
380 return pipe->handle.WriteBulk(src, count, timeout);
381}
382
383size_t stk_pipe_read_bulk(stk_pipe_t *pipe, stk_word_t *dst, size_t count, int32_t timeout)
384{
385 STK_ASSERT(pipe != nullptr);
386
387 return pipe->handle.ReadBulk(dst, count, timeout);
388}
389
391{
392 STK_ASSERT(pipe != nullptr);
393
394 return pipe->handle.GetSize();
395}
396
397// ---------------------------------------------------------------------------
398// RWMutex (Reader-Writer Lock)
399// ---------------------------------------------------------------------------
404
406{
407 STK_ASSERT(memory != nullptr);
408 STK_ASSERT(memory_size >= sizeof(stk_rwmutex_t));
409 if (memory_size < sizeof(stk_rwmutex_t))
410 return nullptr;
411
412 return (stk_rwmutex_t *)new (memory->data) stk_rwmutex_t{};
413}
414
416{
417 if (rw != nullptr)
418 rw->~stk_rwmutex_t();
419}
420
422{
423 STK_ASSERT(rw != nullptr);
424
425 rw->handle.ReadLock();
426}
427
429{
430 STK_ASSERT(rw != nullptr);
431
432 return rw->handle.TryReadLock();
433}
434
436{
437 STK_ASSERT(rw != nullptr);
438
439 return rw->handle.TimedReadLock(timeout);
440}
441
443{
444 STK_ASSERT(rw != nullptr);
445
446 rw->handle.ReadUnlock();
447}
448
450{
451 STK_ASSERT(rw != nullptr);
452
453 rw->handle.Lock();
454}
455
457{
458 STK_ASSERT(rw != nullptr);
459
460 return rw->handle.TryLock();
461}
462
463bool stk_rwmutex_timed_lock(stk_rwmutex_t *rw, int32_t timeout)
464{
465 STK_ASSERT(rw != nullptr);
466
467 return rw->handle.TimedLock(timeout);
468}
469
471{
472 STK_ASSERT(rw != nullptr);
473
474 rw->handle.Unlock();
475}
476
477} // extern "C"
Top-level STK include. Provides the Kernel class template and all built-in task-switching strategies.
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
Definition stk_defs.h:330
Collection of synchronization primitives (stk::sync namespace).
C language binding/interface for SuperTinyKernel (STK).
Pipe< stk_word_t, STK_PIPE_SIZE > PipeX
void stk_event_set(stk_event_t *ev)
Set the event to signaled state.
void stk_sem_signal(stk_sem_t *sem)
Signal/Release a semaphore resource.
uint32_t stk_ef_set(stk_ef_t *ef, uint32_t flags)
Set one or more flags.
stk_spinlock_t * stk_spinlock_create(stk_spinlock_mem_t *memory, uint32_t memory_size)
Create a recursive SpinLock.
uint32_t stk_ef_clear(stk_ef_t *ef, uint32_t flags)
Clear one or more flags.
void stk_mutex_destroy(stk_mutex_t *mtx)
Destroy a Mutex.
bool stk_rwmutex_try_read_lock(stk_rwmutex_t *rw)
Try to acquire the read lock without blocking.
stk_ef_t * stk_ef_create(stk_ef_mem_t *memory, uint32_t memory_size, uint32_t initial_flags)
Create an EventFlags object (using provided memory).
bool stk_spinlock_trylock(stk_spinlock_t *lock)
Attempt to acquire the SpinLock immediately.
void stk_ef_destroy(stk_ef_t *ef)
Destroy an EventFlags object.
void stk_event_reset(stk_event_t *ev)
Reset the event to non-signaled state.
bool stk_rwmutex_trylock(stk_rwmutex_t *rw)
Try to acquire the write lock without blocking.
struct stk_ef_t stk_ef_t
Opaque handle to an EventFlags instance.
Definition stk_c.h:785
stk_pipe_t * stk_pipe_create(stk_pipe_mem_t *memory, uint32_t memory_size)
Create a Pipe (using provided memory).
bool stk_pipe_read(stk_pipe_t *pipe, stk_word_t *data, int32_t timeout)
Read data from the pipe.
uint32_t stk_ef_trywait(stk_ef_t *ef, uint32_t flags, uint32_t options)
Non-blocking flag poll.
void stk_cv_notify_one(stk_cv_t *cv)
Wake one task waiting on the condition variable.
bool stk_rwmutex_timed_lock(stk_rwmutex_t *rw, int32_t timeout)
Try to acquire the write lock with a timeout.
bool stk_rwmutex_timed_read_lock(stk_rwmutex_t *rw, int32_t timeout)
Try to acquire the read lock with a timeout.
bool stk_event_trywait(stk_event_t *ev)
Wait for the event to become signaled.
uint32_t stk_ef_wait(stk_ef_t *ef, uint32_t flags, uint32_t options, int32_t timeout)
Wait for one or more flags to be set.
void stk_event_destroy(stk_event_t *ev)
Destroy an Event.
stk_rwmutex_t * stk_rwmutex_create(stk_rwmutex_mem_t *memory, uint32_t memory_size)
Create an RWMutex (using provided memory).
void stk_mutex_lock(stk_mutex_t *mtx)
Lock the mutex. Blocks until available.
void stk_rwmutex_lock(stk_rwmutex_t *rw)
Acquire the lock for exclusive writing. Blocks until available.
stk_sem_t * stk_sem_create(stk_sem_mem_t *memory, uint32_t memory_size, uint32_t initial_count)
Create a Semaphore (using provided memory).
void stk_cv_destroy(stk_cv_t *cv)
Destroy a Condition Variable.
struct stk_event_t stk_event_t
Opaque handle to an Event instance.
Definition stk_c.h:667
size_t stk_pipe_get_size(stk_pipe_t *pipe)
Get current number of elements in the pipe.
void stk_spinlock_unlock(stk_spinlock_t *lock)
Release the SpinLock.
bool stk_mutex_trylock(stk_mutex_t *mtx)
Try locking the mutex. Does not block if already locked.
void stk_rwmutex_read_lock(stk_rwmutex_t *rw)
Acquire the lock for shared reading. Blocks until available.
stk_mutex_t * stk_mutex_create(stk_mutex_mem_t *memory, uint32_t memory_size)
Create a Mutex (using provided memory).
struct stk_sem_t stk_sem_t
Opaque handle to a Semaphore instance.
Definition stk_c.h:724
void stk_mutex_unlock(stk_mutex_t *mtx)
Unlock the mutex.
void stk_pipe_destroy(stk_pipe_t *pipe)
Destroy a Pipe.
void stk_spinlock_destroy(stk_spinlock_t *lock)
Destroy the SpinLock.
stk_cv_t * stk_cv_create(stk_cv_mem_t *memory, uint32_t memory_size)
Create a Condition Variable (using provided memory).
bool stk_sem_wait(stk_sem_t *sem, int32_t timeout)
Wait for a semaphore resource.
size_t stk_pipe_read_bulk(stk_pipe_t *pipe, stk_word_t *dst, size_t count, int32_t timeout)
Read multiple elements from the pipe.
struct stk_spinlock_t stk_spinlock_t
Opaque handle to a SpinLock instance.
Definition stk_c.h:579
void stk_spinlock_lock(stk_spinlock_t *lock)
Acquire the SpinLock (recursive).
void stk_sem_destroy(stk_sem_t *sem)
Destroy a Semaphore.
stk_event_t * stk_event_create(stk_event_mem_t *memory, uint32_t memory_size, bool manual_reset)
Create an Event (using provided memory).
void stk_rwmutex_read_unlock(stk_rwmutex_t *rw)
Release the shared reader lock.
uint32_t stk_ef_get(stk_ef_t *ef)
Read the current flags word without modifying it.
bool stk_cv_wait(stk_cv_t *cv, stk_mutex_t *mtx, int32_t timeout)
Wait for a signal on the condition variable.
void stk_event_pulse(stk_event_t *ev)
Pulse the event (signal then immediately reset).
size_t stk_pipe_write_bulk(stk_pipe_t *pipe, const stk_word_t *src, size_t count, int32_t timeout)
Write multiple elements to the pipe.
uintptr_t stk_word_t
CPU register type.
Definition stk_c.h:83
void stk_rwmutex_destroy(stk_rwmutex_t *rw)
Destroy an RWMutex.
bool stk_pipe_write(stk_pipe_t *pipe, stk_word_t data, int32_t timeout)
Write data to the pipe.
bool stk_event_wait(stk_event_t *ev, int32_t timeout)
Wait for the event to become signaled.
void stk_cv_notify_all(stk_cv_t *cv)
Wake all tasks waiting on the condition variable.
bool stk_mutex_timed_lock(stk_mutex_t *mtx, int32_t timeout)
Try to lock the mutex with a timeout.
void stk_rwmutex_unlock(stk_rwmutex_t *rw)
Release the exclusive writer lock.
Namespace of STK package.
Synchronization primitives for task coordination and resource protection.
Condition Variable primitive for signaling between tasks based on specific predicates.
Definition stk_sync_cv.h:68
bool Wait(IMutex &mutex, Timeout timeout=WAIT_INFINITE)
Wait for a signal.
void NotifyOne()
Wake one waiting task.
void NotifyAll()
Wake all waiting tasks.
Binary synchronization event (signaled / non-signaled) primitive.
bool Set()
Set event to signaled state.
void Pulse()
Pulse event: attempt to release waiters and then reset (Win32 PulseEvent() semantics).
bool TryWait()
Poll event state without blocking.
bool Reset()
Reset event to non-signaled state.
bool Wait(Timeout timeout=WAIT_INFINITE)
Wait until event becomes signaled or the timeout expires.
32-bit event flags group for multi-flag synchronization between tasks.
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.
uint32_t TryWait(uint32_t flags, uint32_t options=OPT_WAIT_ANY)
Non-blocking flag poll.
uint32_t Clear(uint32_t flags)
Clear one or more flags.
uint32_t Set(uint32_t flags)
Set one or more flags.
Recursive mutex primitive that allows the same thread to acquire the lock multiple times.
void Unlock()
Release lock.
bool TryLock()
Acquire the lock.
void Lock()
Acquire lock.
bool TimedLock(Timeout timeout)
Acquire lock.
Thread-safe FIFO communication pipe for inter-task data passing.
size_t GetSize() const
Get the current number of elements in the pipe.
size_t WriteBulk(const T *src, size_t count, Timeout timeout=WAIT_INFINITE)
Write multiple elements to the pipe.
bool Write(const T &data, Timeout timeout=WAIT_INFINITE)
Write data to the pipe.
bool Read(T &data, Timeout timeout=WAIT_INFINITE)
Read data from the pipe.
size_t ReadBulk(T *dst, size_t count, Timeout timeout=WAIT_INFINITE)
Read multiple elements from the pipe.
Reader-Writer Lock synchronization primitive for non-recursive shared and exclusive access.
bool TryLock()
Attempt to acquire the lock for exclusive writing without blocking.
bool TimedReadLock(Timeout timeout)
Acquire the lock for shared reading with a timeout.
void Lock()
Acquire the lock for exclusive writing (IMutex interface).
void ReadUnlock()
Release the shared reader lock.
void ReadLock()
Acquire the lock for shared reading.
void Unlock()
Release the exclusive writer lock (IMutex interface).
bool TryReadLock()
Attempt to acquire the lock for shared reading without blocking.
bool TimedLock(Timeout timeout)
Acquire the lock for exclusive writing with a timeout.
Counting semaphore primitive for resource management and signaling.
void Signal()
Post a signal (increment counter).
bool Wait(Timeout timeout=WAIT_INFINITE)
Wait for a signal (decrement counter).
Recursive spinlock.
void Unlock()
Release the lock or decrement the recursion counter.
bool TryLock()
Attempt to acquire the lock without blocking.
void Lock()
Acquire the lock.
Opaque memory container for a Mutex instance.
Definition stk_c.h:521
stk_word_t data[(10+((0) ? 1 :0))]
Definition stk_c.h:522
Opaque memory container for SpinLock object.
Definition stk_c.h:573
stk_word_t data[(1)]
Definition stk_c.h:574
Opaque memory container for a ConditionVariable instance.
Definition stk_c.h:613
stk_word_t data[(7+((0) ? 1 :0))]
Definition stk_c.h:614
Opaque memory container for an Event instance.
Definition stk_c.h:661
stk_word_t data[(8+((0) ? 1 :0))]
Definition stk_c.h:662
Opaque memory container for a Semaphore instance.
Definition stk_c.h:718
stk_word_t data[(8+((0) ? 1 :0))]
Definition stk_c.h:719
Opaque memory container for an EventFlags instance.
Definition stk_c.h:779
stk_word_t data[((7+((0) ? 1 :0))+1+((0) ? 1 :0))]
Definition stk_c.h:780
Opaque memory container for a Pipe instance.
Definition stk_c.h:873
stk_word_t data[((27+((0) ? 3 :0))+16)]
Definition stk_c.h:874
Opaque memory container for an RWMutex instance.
Definition stk_c.h:941
stk_word_t data[(17+((0) ? 3 :0))]
Definition stk_c.h:942
sync::SpinLock handle
ConditionVariable handle
stk_event_t(bool manual_reset)
stk_sem_t(uint32_t initial_count)
Semaphore handle
EventFlags handle
stk_ef_t(uint32_t initial_flags)
sync::RWMutex handle