SuperTinyKernel™ RTOS 1.06.x
Lightweight, high-performance, deterministic, bare-metal C++ RTOS for resource-constrained embedded systems. MIT Open Source License.
Loading...
Searching...
No Matches
stk_sync_rwmutex.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_RWMUTEX_H_
11#define STK_SYNC_RWMUTEX_H_
12
13#include "stk_sync_cv.h"
14
18
19namespace stk {
20namespace sync {
21
61class RWMutex final : public IMutex, public ITraceable
62{
63public:
66 explicit RWMutex() : m_readers(0U), m_writers_waiting(0U), m_writer_active(false)
67 {}
68
76 {
77 // API contract: must not be destroyed while readers are active, writers are waiting,
78 // or a writer holds the lock
80 }
81
86 {
87 public:
92 explicit ScopedTimedLock(RWMutex &rw, Timeout timeout_ticks = WAIT_INFINITE)
93 : m_rw(rw), m_locked(rw.TimedLock(timeout_ticks))
94 {}
95
96 ~ScopedTimedLock() { if (m_locked) { m_rw.Unlock(); } }
97
98 bool IsLocked() const { return m_locked; }
99
100 private:
102
105 };
106
111 {
112 public:
117 explicit ScopedTimedReadMutex(RWMutex &rw, Timeout timeout_ticks = WAIT_INFINITE)
118 : m_rw(rw), m_locked(rw.TimedReadLock(timeout_ticks))
119 {}
120
121 ~ScopedTimedReadMutex() { if (m_locked) { m_rw.ReadUnlock(); } }
122
123 bool IsLocked() const { return m_locked; }
124
125 private:
127
130 };
131
138 bool TimedReadLock(Timeout timeout_ticks);
139
147
156
162 void ReadUnlock();
163
170 bool TimedLock(Timeout timeout_ticks);
171
178 void Lock() override { STK_UNUSED(TimedLock(WAIT_INFINITE)); }
179
186 bool TryLock() { return TimedLock(NO_WAIT); }
187
193 void Unlock() override;
194
195private:
197
198 static const uint16_t READERS_MAX = 0xFFFEU;
199 static const uint16_t WRITERS_MAX = 0xFFFEU;
200
203 uint16_t m_readers;
206};
207
208// ---------------------------------------------------------------------------
209// TimedReadLock
210// ---------------------------------------------------------------------------
211
212inline bool RWMutex::TimedReadLock(Timeout timeout_ticks)
213{
214 bool success = true;
216
217 // wait if there is an active writer or if writers are waiting (Writer Preference)
218 while (m_writer_active || (m_writers_waiting != 0U))
219 {
220 if (!m_cv_readers.Wait(cs_, timeout_ticks))
221 {
222 success = false; // timeout
223 break;
224 }
225
226 // re-check on wake: another writer may have queued up while this task was sleeping
227 }
228
229 // only increment reader count if the lock was successfully acquired without timing out
230 if (success)
231 {
232 STK_ASSERT(m_readers < READERS_MAX); // API contract: reader count must not exceed maximum
233
234 m_readers = static_cast<uint16_t>(m_readers + 1U);
235 }
236
237 return success;
238}
239
240// ---------------------------------------------------------------------------
241// ReadUnlock
242// ---------------------------------------------------------------------------
243
245{
246 const ScopedCriticalSection cs_;
247
248 STK_ASSERT(m_readers != 0U); // API contract: must have a matching ReadLock()
249
250 m_readers = static_cast<uint16_t>(m_readers - 1U);
251
252 // wake a waiting writer when the last reader exits
253 if (m_readers == 0U)
254 {
255 m_cv_writers.NotifyOne_CS();
256 }
257}
258
259// ---------------------------------------------------------------------------
260// TimedLock
261// ---------------------------------------------------------------------------
262
263inline bool RWMutex::TimedLock(Timeout timeout_ticks)
264{
265 bool success = true;
267
268 STK_ASSERT(m_writers_waiting < WRITERS_MAX); // API contract: waiting writer count must not exceed maximum
269
270 m_writers_waiting = static_cast<uint16_t>(m_writers_waiting + 1U);
271
272 // wait until there are no active readers and no active writer
273 while (m_writer_active || (m_readers != 0U))
274 {
275 if (!m_cv_writers.Wait(cs_, timeout_ticks))
276 {
277 // timed out: withdraw from the waiting writers queue
278 m_writers_waiting = static_cast<uint16_t>(m_writers_waiting - 1U);
279 success = false;
280 break;
281 }
282 }
283
284 // only finalize state if the wait didn't time out
285 if (success)
286 {
287 m_writers_waiting = static_cast<uint16_t>(m_writers_waiting - 1U);
288
289 // kernel invariant: no readers and no active writer when lock is granted
290 if ((m_readers != 0U) || m_writer_active)
291 {
293 }
294
295 m_writer_active = true;
296 }
297
298 return success;
299}
300
301// ---------------------------------------------------------------------------
302// Unlock
303// ---------------------------------------------------------------------------
304
305inline void RWMutex::Unlock()
306{
307 const ScopedCriticalSection cs_;
308
309 STK_ASSERT(m_writer_active); // API contract: caller must hold the write lock
310
311 m_writer_active = false;
312
313 // prioritize waking waiting writers to prevent writer starvation;
314 // only wake readers if no writers are queued
315 if (m_writers_waiting != 0U)
316 {
317 m_cv_writers.NotifyOne_CS();
318 }
319 else
320 {
321 m_cv_readers.NotifyAll_CS();
322 }
323}
324
325} // namespace sync
326} // namespace stk
327
328#endif /* STK_SYNC_RWMUTEX_H_ */
#define STK_UNUSED(X)
Explicitly marks a variable as unused to suppress compiler warnings.
Definition stk_defs.h:608
#define STK_NONCOPYABLE_CLASS(TYPE)
Disables copy construction and assignment for a class.
Definition stk_defs.h:601
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
Definition stk_defs.h:409
#define STK_VIRT_DTOR
Makes destructors virtual and compliant to strict rules if STK_STRICT_COMPLIANCY=0.
Definition stk_defs.h:159
Implementation of synchronization primitive: stk::sync::ConditionVariable.
Namespace of STK package.
constexpr Timeout NO_WAIT
Timeout value: return immediately if the synchronization object is not yet signaled (non-blocking pol...
Definition stk_common.h:189
int32_t Timeout
Timeout time (ticks).
Definition stk_common.h:125
static __stk_forceinline void STK_KERNEL_PANIC(stk::EKernelPanicId id)
Called when the kernel detects an unrecoverable internal fault.
Definition stk_arch.h:75
constexpr Timeout WAIT_INFINITE
Timeout value: block indefinitely until the synchronization object is signaled.
Definition stk_common.h:183
@ KERNEL_PANIC_ASSERT
Internal assertion failed (maps from STK_ASSERT).
Definition stk_common.h:57
Synchronization primitives for task coordination and resource protection.
Traceable object.
Definition stk_common.h:393
Interface for mutex synchronization primitive.
Definition stk_common.h:542
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
static const uint16_t READERS_MAX
maximum number of concurrent readers
bool TryLock()
Attempt to acquire the lock for exclusive writing without blocking.
bool TimedLock(Timeout timeout_ticks)
Acquire the lock for exclusive writing with a timeout.
ConditionVariable m_cv_writers
signaled when a writer can proceed
bool m_writer_active
true if a writer currently holds the lock
static const uint16_t WRITERS_MAX
maximum number of waiting writers
void Unlock() override
Release the exclusive writer lock (IMutex interface).
uint16_t m_writers_waiting
count of writers waiting for access
void Lock() override
Acquire the lock for exclusive writing (IMutex interface).
uint16_t m_readers
current active reader count
RWMutex()
Construct an RWMutex in the unlocked state with no active readers or writers.
bool TimedReadLock(Timeout timeout_ticks)
Acquire the lock for shared reading with a timeout.
ConditionVariable m_cv_readers
signaled when readers can proceed
void ReadUnlock()
Release the shared reader lock.
void ReadLock()
Acquire the lock for shared reading.
bool TryReadLock()
Attempt to acquire the lock for shared reading without blocking.
ScopedTimedLock(RWMutex &rw, Timeout timeout_ticks=WAIT_INFINITE)
Constructs the guard and attempts to acquire the write lock.
ScopedTimedReadMutex(RWMutex &rw, Timeout timeout_ticks=WAIT_INFINITE)
Constructs the guard and attempts to acquire the read lock.