SuperTinyKernel™ RTOS 1.06.0
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_common.h"
14#include "stk_sync_cs.h"
15#include "stk_sync_cv.h"
16
20
21namespace stk {
22namespace sync {
23
63class RWMutex : public IMutex, public ITraceable
64{
65public:
68 explicit RWMutex() : m_readers(0U), m_writers_waiting(0U), m_writer_active(false)
69 {}
70
78 {
79 // API contract: must not be destroyed while readers are active, writers are waiting,
80 // or a writer holds the lock
82 }
83
88 {
89 public:
95 : m_rw(rw), m_locked(rw.TimedLock(timeout))
96 {}
97
98 ~ScopedTimedLock() { if (m_locked) { m_rw.Unlock(); } }
99
100 bool IsLocked() const { return m_locked; }
101
102 private:
104
107 };
108
113 {
114 public:
120 : m_rw(rw), m_locked(rw.TimedReadLock(timeout))
121 {}
122
123 ~ScopedTimedReadMutex() { if (m_locked) { m_rw.ReadUnlock(); } }
124
125 bool IsLocked() const { return m_locked; }
126
127 private:
129
132 };
133
140 bool TimedReadLock(Timeout timeout);
141
149
158
164 void ReadUnlock();
165
172 bool TimedLock(Timeout timeout);
173
181
188 bool TryLock() { return TimedLock(NO_WAIT); }
189
195 void Unlock();
196
197private:
199
200 static const uint16_t READERS_MAX = 0xFFFEU;
201 static const uint16_t WRITERS_MAX = 0xFFFEU;
202
205 uint16_t m_readers;
208};
209
210// ---------------------------------------------------------------------------
211// TimedReadLock
212// ---------------------------------------------------------------------------
213
214inline bool RWMutex::TimedReadLock(Timeout timeout)
215{
217
218 // wait if there is an active writer or if writers are waiting (Writer Preference)
219 while (m_writer_active || (m_writers_waiting != 0U))
220 {
221 if (!m_cv_readers.Wait(cs_, timeout))
222 return false; // timeout
223
224 // re-check on wake: another writer may have queued up while this task was sleeping
225 }
226
227 STK_ASSERT(m_readers < READERS_MAX); // API contract: reader count must not exceed maximum
228
229 m_readers = static_cast<uint16_t>(m_readers + 1U);
230 return true;
231}
232
233// ---------------------------------------------------------------------------
234// ReadUnlock
235// ---------------------------------------------------------------------------
236
238{
240
241 STK_ASSERT(m_readers != 0U); // API contract: must have a matching ReadLock()
242
243 m_readers = static_cast<uint16_t>(m_readers - 1U);
244
245 // wake a waiting writer when the last reader exits
246 if (m_readers == 0U)
247 m_cv_writers.NotifyOne_CS();
248}
249
250// ---------------------------------------------------------------------------
251// TimedLock
252// ---------------------------------------------------------------------------
253
254inline bool RWMutex::TimedLock(Timeout timeout)
255{
257
258 STK_ASSERT(m_writers_waiting < WRITERS_MAX); // API contract: waiting writer count must not exceed maximum
259
260 m_writers_waiting = static_cast<uint16_t>(m_writers_waiting + 1U);
261
262 // wait until there are no active readers and no active writer
263 while (m_writer_active || (m_readers != 0U))
264 {
265 if (!m_cv_writers.Wait(cs_, timeout))
266 {
267 // timed out: withdraw from the waiting writers queue
268 m_writers_waiting = static_cast<uint16_t>(m_writers_waiting - 1U);
269 return false;
270 }
271 }
272
273 m_writers_waiting = static_cast<uint16_t>(m_writers_waiting - 1U);
274
275 // kernel invariant: no readers and no active writer when lock is granted
276 if ((m_readers != 0U) || m_writer_active)
278
279 m_writer_active = true;
280 return true;
281}
282
283// ---------------------------------------------------------------------------
284// Unlock
285// ---------------------------------------------------------------------------
286
287inline void RWMutex::Unlock()
288{
290
291 STK_ASSERT(m_writer_active); // API contract: caller must hold the write lock
292
293 m_writer_active = false;
294
295 // prioritize waking waiting writers to prevent writer starvation;
296 // only wake readers if no writers are queued
297 if (m_writers_waiting != 0U)
298 m_cv_writers.NotifyOne_CS();
299 else
300 m_cv_readers.NotifyAll_CS();
301}
302
303} // namespace sync
304} // namespace stk
305
306#endif /* STK_SYNC_RWMUTEX_H_ */
#define STK_KERNEL_PANIC(id)
Called when the kernel detects an unrecoverable internal fault.
Definition stk_arch.h:63
Contains interface definitions of the library.
#define STK_UNUSED(X)
Explicitly marks a variable as unused to suppress compiler warnings.
Definition stk_defs.h:524
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
Definition stk_defs.h:330
Implementation of synchronization primitive: stk::sync::ScopedCriticalSection.
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:177
int32_t Timeout
Timeout time (ticks).
Definition stk_common.h:123
static constexpr Timeout WAIT_INFINITE
Timeout value: block indefinitely until the synchronization object is signaled.
Definition stk_common.h:171
@ KERNEL_PANIC_ASSERT
Internal assertion failed (maps from STK_ASSERT).
Definition stk_common.h:56
Synchronization primitives for task coordination and resource protection.
Traceable object.
Definition stk_common.h:313
Interface for mutex synchronization primitive.
Definition stk_common.h:439
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.
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
uint16_t m_writers_waiting
count of writers waiting for access
uint16_t m_readers
current active reader count
bool TimedReadLock(Timeout timeout)
Acquire the lock for shared reading with a timeout.
RWMutex()
Construct an RWMutex in the unlocked state with no active readers or writers.
void Lock()
Acquire the lock for exclusive writing (IMutex interface).
STK_NONCOPYABLE_CLASS(RWMutex)
ConditionVariable m_cv_readers
signaled when readers can proceed
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.
ScopedTimedLock(RWMutex &rw, Timeout timeout=WAIT_INFINITE)
Constructs the guard and attempts to acquire the write lock.
STK_NONCOPYABLE_CLASS(ScopedTimedReadMutex)
ScopedTimedReadMutex(RWMutex &rw, Timeout timeout=WAIT_INFINITE)
Constructs the guard and attempts to acquire the read lock.