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_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
180 void Lock() { (void)TimedLock(WAIT_INFINITE); }
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{
216 STK_ASSERT(!hw::IsInsideISR()); // API contract: caller must not be in ISR
217
219
220 // wait if there is an active writer or if writers are waiting (Writer Preference)
221 while (m_writer_active || (m_writers_waiting != 0U))
222 {
223 if (!m_cv_readers.Wait(cs_, timeout))
224 return false; // timeout
225
226 // re-check on wake: another writer may have queued up while this task was sleeping
227 }
228
229 STK_ASSERT(m_readers < READERS_MAX); // API contract: reader count must not exceed maximum
230
231 m_readers = static_cast<uint16_t>(m_readers + 1U);
232 return true;
233}
234
235// ---------------------------------------------------------------------------
236// ReadUnlock
237// ---------------------------------------------------------------------------
238
240{
241 STK_ASSERT(!hw::IsInsideISR()); // API contract: caller must not be in ISR
242
244
245 STK_ASSERT(m_readers != 0U); // API contract: must have a matching ReadLock()
246
247 m_readers = static_cast<uint16_t>(m_readers - 1U);
248
249 // wake a waiting writer when the last reader exits
250 if (m_readers == 0U)
251 m_cv_writers.NotifyOne();
252}
253
254// ---------------------------------------------------------------------------
255// TimedLock
256// ---------------------------------------------------------------------------
257
258inline bool RWMutex::TimedLock(Timeout timeout)
259{
260 STK_ASSERT(!hw::IsInsideISR()); // API contract: caller must not be in ISR
261 STK_ASSERT(m_writers_waiting < WRITERS_MAX); // API contract: waiting writer count must not exceed maximum
262
264
265 m_writers_waiting = static_cast<uint16_t>(m_writers_waiting + 1U);
266
267 // wait until there are no active readers and no active writer
268 while (m_writer_active || (m_readers != 0U))
269 {
270 if (!m_cv_writers.Wait(cs_, timeout))
271 {
272 // timed out: withdraw from the waiting writers queue
273 m_writers_waiting = static_cast<uint16_t>(m_writers_waiting - 1U);
274 return false;
275 }
276 }
277
278 m_writers_waiting = static_cast<uint16_t>(m_writers_waiting - 1U);
279
280 // kernel invariant: no readers and no active writer when lock is granted
281 if ((m_readers != 0U) || m_writer_active)
283
284 m_writer_active = true;
285 return true;
286}
287
288// ---------------------------------------------------------------------------
289// Unlock
290// ---------------------------------------------------------------------------
291
292inline void RWMutex::Unlock()
293{
294 STK_ASSERT(!hw::IsInsideISR()); // API contract: caller must not be in ISR
295 STK_ASSERT(m_writer_active); // API contract: caller must hold the write lock
296
298
299 m_writer_active = false;
300
301 // prioritize waking waiting writers to prevent writer starvation;
302 // only wake readers if no writers are queued
303 if (m_writers_waiting != 0U)
304 m_cv_writers.NotifyOne();
305 else
306 m_cv_readers.NotifyAll();
307}
308
309} // namespace sync
310} // namespace stk
311
312#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_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.
const Timeout WAIT_INFINITE
Timeout value: block indefinitely until the synchronization object is signaled.
Definition stk_common.h:139
int32_t Timeout
Timeout time (ticks).
Definition stk_common.h:133
const Timeout NO_WAIT
Timeout value: return immediately if the synchronization object is not yet signaled (non-blocking pol...
Definition stk_common.h:145
@ KERNEL_PANIC_ASSERT
Internal assertion failed (maps from STK_ASSERT).
Definition stk_common.h:56
bool IsInsideISR()
Check whether the CPU is currently executing inside a hardware interrupt service routine (ISR).
Definition stktest.cpp:103
Synchronization primitives for task coordination and resource protection.
Traceable object.
Definition stk_common.h:255
Interface for mutex synchronization primitive.
Definition stk_common.h:381
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.