Internal Interface Wrap
API reference
Loading...
Searching...
No Matches
PlatformMutex.h
Go to the documentation of this file.
1
41#pragma once
42
43#include <atomic>
44#include <cstdint>
45
46//==============================================================================
47// ## 1. NULL (NO-OP) MUTEX BACKEND -- zero-overhead default
48//==============================================================================
49
62 // -- Handle Types ------------------------------------------------------
64 using RecursiveMutexHandle = uint8_t;
66 using MutexHandle = uint8_t;
67
68 // -- Constants ---------------------------------------------------------
69 static constexpr uint32_t MAX_DELAY = 0xFFFFFFFFU;
70 static constexpr uint32_t TICK_RATE_HZ = 1000U;
71
72 // -- Recursive Mutex Operations ----------------------------------------
74 static constexpr void createRecursive(RecursiveMutexHandle*) noexcept {}
76 static constexpr void destroyRecursive(RecursiveMutexHandle*) noexcept {}
78 static constexpr bool lockRecursive(RecursiveMutexHandle*, uint32_t) noexcept { return true; }
80 static constexpr bool tryLockRecursive(RecursiveMutexHandle*) noexcept { return true; }
82 static constexpr void unlockRecursive(RecursiveMutexHandle*) noexcept {}
83
84 // -- Regular Mutex Operations ------------------------------------------
86 static constexpr void createMutex(MutexHandle*) noexcept {}
88 static constexpr void destroyMutex(MutexHandle*) noexcept {}
90 static constexpr bool lockMutex(MutexHandle*, uint32_t) noexcept { return true; }
92 static constexpr bool tryLockMutex(MutexHandle*) noexcept { return true; }
94 static constexpr void unlockMutex(MutexHandle*) noexcept {}
95
96 // -- Time / Scheduling -------------------------------------------------
98 static constexpr uint32_t getTickCount() noexcept { return 0; }
100 static constexpr uint32_t msToTicks(uint32_t ms) noexcept { return ms; }
102 static constexpr void yield() noexcept {}
103};
104
105//==============================================================================
106// ## 2. BACKEND SELECTION -- compile-time injection point
107//==============================================================================
108//
109// If the core/ layer (or any consumer) places a "PlatformMutexBackend.h" file
110// on the include path, it is picked up here via C++17 __has_include.
111// That file must:
112// 1. Define a struct with the same static methods as NullMutexBackend
113// 2. Set: using PlatformMutexActiveBackend = YourBackendType;
114// 3. Set: #define PLATFORM_MUTEX_BACKEND_CONFIGURED
115//
116// When building interface-wrap standalone (no core/ layer), the file is absent
117// and NullMutexBackend is used -- zero overhead, no external dependencies.
118//==============================================================================
119
120#if __has_include("PlatformMutexBackend.h")
121 #include "PlatformMutexBackend.h"
122#endif
123
124#if !defined(PLATFORM_MUTEX_BACKEND_CONFIGURED)
127#endif
128
129//==============================================================================
130// ## 3. PLATFORM TIME -- tick counting and conversion utilities
131//==============================================================================
132
134public:
139 static uint64_t GetCurrentTimeUs() noexcept {
141 if (hz == 0) return 0;
142 return static_cast<uint64_t>(PlatformMutexActiveBackend::getTickCount())
143 * 1000000ULL / hz;
144 }
145
149 static uint32_t MsToTicks(uint32_t ms) noexcept {
150 if (ms == 0) return 0;
151 const uint32_t ticks = PlatformMutexActiveBackend::msToTicks(ms);
152 return (ticks > 0) ? ticks : 1;
153 }
154};
155
156//==============================================================================
157// ## 4. PLATFORM MUTEX -- recursive mutex with STL-like + FreeRTOS-style API
158//==============================================================================
159
169template <typename Backend = PlatformMutexActiveBackend>
171public:
172 PlatformMutexImpl() noexcept : handle_{} {
173 Backend::createRecursive(&handle_);
174 }
175
177 Backend::destroyRecursive(&handle_);
178 }
179
180 // Non-copyable
183
184 // Movable (transfers handle ownership)
185 PlatformMutexImpl(PlatformMutexImpl&& other) noexcept : handle_(other.handle_) {
186 other.handle_ = {};
187 }
188
190 if (this != &other) {
191 Backend::destroyRecursive(&handle_);
192 handle_ = other.handle_;
193 other.handle_ = {};
194 }
195 return *this;
196 }
197
198 // -- STL-like API ------------------------------------------------------
199
200 bool lock() noexcept {
201 return Backend::lockRecursive(&handle_, Backend::MAX_DELAY);
202 }
203
204 bool try_lock() noexcept {
205 return Backend::tryLockRecursive(&handle_);
206 }
207
208 bool try_lock_for(uint32_t timeout_ms) noexcept {
209 const uint32_t ticks = PlatformTime::MsToTicks(timeout_ms);
210 return Backend::lockRecursive(&handle_, ticks);
211 }
212
213 void unlock() noexcept {
214 Backend::unlockRecursive(&handle_);
215 }
216
218 auto native_handle() const noexcept { return handle_; }
219
220 // -- FreeRTOS-style convenience API ------------------------------------
221
222 bool Take(uint32_t timeout_ms = 0) noexcept {
223 return (timeout_ms > 0) ? try_lock_for(timeout_ms) : lock();
224 }
225
226 void Give() noexcept { unlock(); }
227
228 // -- Shared-lock pass-through (for generic lock-guard compatibility) ---
229
230 bool lock_shared() noexcept { return lock(); }
231 bool try_lock_shared() noexcept { return try_lock(); }
232 bool try_lock_shared_for(uint32_t timeout_ms) noexcept { return try_lock_for(timeout_ms); }
233 void unlock_shared() noexcept { unlock(); }
234
235private:
236 typename Backend::RecursiveMutexHandle handle_;
237};
238
239//==============================================================================
240// ## 5. PLATFORM SHARED MUTEX -- reader-writer mutex
241//==============================================================================
242
251template <typename Backend = PlatformMutexActiveBackend>
253public:
256 Backend::createMutex(&writer_mutex_);
257 Backend::createMutex(&reader_mutex_);
258 }
259
261 Backend::destroyMutex(&writer_mutex_);
262 Backend::destroyMutex(&reader_mutex_);
263 }
264
265 // Non-copyable
268
269 // Movable
271 : writer_mutex_(other.writer_mutex_), reader_mutex_(other.reader_mutex_),
272 readers_(other.readers_.load()), writer_active_(other.writer_active_.load()) {
273 other.writer_mutex_ = {};
274 other.reader_mutex_ = {};
275 other.readers_.store(0);
276 other.writer_active_.store(false);
277 }
278
280 if (this != &other) {
281 Backend::destroyMutex(&writer_mutex_);
282 Backend::destroyMutex(&reader_mutex_);
283 writer_mutex_ = other.writer_mutex_;
284 reader_mutex_ = other.reader_mutex_;
285 readers_.store(other.readers_.load());
286 writer_active_.store(other.writer_active_.load());
287 other.writer_mutex_ = {};
288 other.reader_mutex_ = {};
289 other.readers_.store(0);
290 other.writer_active_.store(false);
291 }
292 return *this;
293 }
294
295 // -- Exclusive (writer) lock -------------------------------------------
296
297 bool lock() noexcept {
298 if (!Backend::lockMutex(&writer_mutex_, Backend::MAX_DELAY)) return false;
299 writer_active_.store(true);
300 while (readers_.load() > 0) { Backend::yield(); }
301 return true;
302 }
303
304 bool try_lock() noexcept {
305 if (!Backend::tryLockMutex(&writer_mutex_)) return false;
306 writer_active_.store(true);
307 if (readers_.load() > 0) {
308 writer_active_.store(false);
309 Backend::unlockMutex(&writer_mutex_);
310 return false;
311 }
312 return true;
313 }
314
315 bool try_lock_for(uint32_t timeout_ms) noexcept {
316 const uint32_t ticks = PlatformTime::MsToTicks(timeout_ms);
317 const uint32_t start = Backend::getTickCount();
318 if (!Backend::lockMutex(&writer_mutex_, ticks)) return false;
319 writer_active_.store(true);
320 const uint32_t elapsed = Backend::getTickCount() - start;
321 const uint32_t remaining = (elapsed < ticks) ? ticks - elapsed : 0;
322 const uint32_t deadline = Backend::getTickCount() + remaining;
323 while (readers_.load() > 0) {
324 if (Backend::getTickCount() >= deadline) {
325 writer_active_.store(false);
326 Backend::unlockMutex(&writer_mutex_);
327 return false;
328 }
329 Backend::yield();
330 }
331 return true;
332 }
333
334 void unlock() noexcept {
335 writer_active_.store(false);
336 Backend::unlockMutex(&writer_mutex_);
337 }
338
339 // -- Shared (reader) lock ----------------------------------------------
340
341 bool lock_shared() noexcept {
342 while (true) {
343 if (!Backend::lockMutex(&reader_mutex_, Backend::MAX_DELAY)) return false;
344 if (!writer_active_.load()) {
345 readers_++;
346 Backend::unlockMutex(&reader_mutex_);
347 return true;
348 }
349 Backend::unlockMutex(&reader_mutex_);
350 Backend::yield();
351 }
352 }
353
354 bool try_lock_shared() noexcept {
355 if (!Backend::tryLockMutex(&reader_mutex_)) return false;
356 if (!writer_active_.load()) {
357 readers_++;
358 Backend::unlockMutex(&reader_mutex_);
359 return true;
360 }
361 Backend::unlockMutex(&reader_mutex_);
362 return false;
363 }
364
365 bool try_lock_shared_for(uint32_t timeout_ms) noexcept {
366 const uint32_t ticks = PlatformTime::MsToTicks(timeout_ms);
367 const uint32_t start = Backend::getTickCount();
368 while (true) {
369 const uint32_t elapsed = Backend::getTickCount() - start;
370 if (elapsed >= ticks) return false;
371 const uint32_t remaining = ticks - elapsed;
372 if (!Backend::lockMutex(&reader_mutex_, remaining)) return false;
373 if (!writer_active_.load()) {
374 readers_++;
375 Backend::unlockMutex(&reader_mutex_);
376 return true;
377 }
378 Backend::unlockMutex(&reader_mutex_);
379 const uint32_t new_elapsed = Backend::getTickCount() - start;
380 if (new_elapsed >= ticks) return false;
381 Backend::yield();
382 }
383 }
384
385 void unlock_shared() noexcept {
386 if (Backend::lockMutex(&reader_mutex_, Backend::MAX_DELAY)) {
387 if (readers_.load() > 0) readers_--;
388 Backend::unlockMutex(&reader_mutex_);
389 }
390 }
391
392private:
393 typename Backend::MutexHandle writer_mutex_;
394 typename Backend::MutexHandle reader_mutex_;
395 std::atomic<int> readers_;
396 std::atomic<bool> writer_active_;
397};
398
399//==============================================================================
400// ## 6. RAII LOCK GUARDS (backend-agnostic -- work with any mutex type)
401//==============================================================================
402
407template <typename Mutex>
409public:
410 explicit PlatformUniqueLock(Mutex& mutex, uint32_t timeout_ms = 0) noexcept
411 : mutex_(&mutex), locked_(false) {
412 if (timeout_ms > 0) {
413 locked_ = mutex_->try_lock_for(timeout_ms);
414 } else {
415 locked_ = mutex_->lock();
416 }
417 }
418
420 if (locked_ && mutex_) {
421 mutex_->unlock();
422 }
423 }
424
425 // Non-copyable
428
429 // Movable
431 : mutex_(other.mutex_), locked_(other.locked_) {
432 other.mutex_ = nullptr;
433 other.locked_ = false;
434 }
435
437 if (this != &other) {
438 if (locked_ && mutex_) { mutex_->unlock(); }
439 mutex_ = other.mutex_;
440 locked_ = other.locked_;
441 other.mutex_ = nullptr;
442 other.locked_ = false;
443 }
444 return *this;
445 }
446
447 [[nodiscard]] bool IsLocked() const noexcept { return locked_; }
448
449 void Unlock() noexcept {
450 if (locked_ && mutex_) {
451 mutex_->unlock();
452 locked_ = false;
453 }
454 }
455
456private:
457 Mutex* mutex_;
459};
460
465template <typename SharedMutex>
467public:
468 explicit PlatformSharedLock(SharedMutex& mutex, uint32_t timeout_ms = 0) noexcept
469 : mutex_(&mutex), locked_(false) {
470 if (timeout_ms > 0) {
471 locked_ = mutex_->try_lock_shared_for(timeout_ms);
472 } else {
473 locked_ = mutex_->lock_shared();
474 }
475 }
476
478 if (locked_ && mutex_) {
479 mutex_->unlock_shared();
480 }
481 }
482
483 // Non-copyable
486
487 // Movable
489 : mutex_(other.mutex_), locked_(other.locked_) {
490 other.mutex_ = nullptr;
491 other.locked_ = false;
492 }
493
495 if (this != &other) {
496 if (locked_ && mutex_) { mutex_->unlock_shared(); }
497 mutex_ = other.mutex_;
498 locked_ = other.locked_;
499 other.mutex_ = nullptr;
500 other.locked_ = false;
501 }
502 return *this;
503 }
504
505 [[nodiscard]] bool IsLocked() const noexcept { return locked_; }
506
507 void Unlock() noexcept {
508 if (locked_ && mutex_) {
509 mutex_->unlock_shared();
510 locked_ = false;
511 }
512 }
513
514private:
515 SharedMutex* mutex_;
517};
518
519//==============================================================================
520// ## 7. CONVENIENCE TYPE ALIASES
521//==============================================================================
522
525
528
531
533template <typename Mutex>
Recursive mutex templated on a backend policy.
Definition PlatformMutex.h:170
void unlock_shared() noexcept
Definition PlatformMutex.h:233
bool Take(uint32_t timeout_ms=0) noexcept
Definition PlatformMutex.h:222
bool lock() noexcept
Definition PlatformMutex.h:200
bool lock_shared() noexcept
Definition PlatformMutex.h:230
PlatformMutexImpl(PlatformMutexImpl &&other) noexcept
Definition PlatformMutex.h:185
void Give() noexcept
Definition PlatformMutex.h:226
bool try_lock_shared() noexcept
Definition PlatformMutex.h:231
bool try_lock() noexcept
Definition PlatformMutex.h:204
PlatformMutexImpl(const PlatformMutexImpl &)=delete
PlatformMutexImpl() noexcept
Definition PlatformMutex.h:172
~PlatformMutexImpl() noexcept
Definition PlatformMutex.h:176
auto native_handle() const noexcept
Access the underlying platform handle (for interop / diagnostics)
Definition PlatformMutex.h:218
PlatformMutexImpl & operator=(PlatformMutexImpl &&other) noexcept
Definition PlatformMutex.h:189
Backend::RecursiveMutexHandle handle_
Definition PlatformMutex.h:236
void unlock() noexcept
Definition PlatformMutex.h:213
bool try_lock_shared_for(uint32_t timeout_ms) noexcept
Definition PlatformMutex.h:232
PlatformMutexImpl & operator=(const PlatformMutexImpl &)=delete
bool try_lock_for(uint32_t timeout_ms) noexcept
Definition PlatformMutex.h:208
RAII shared (reader) lock guard for any shared mutex.
Definition PlatformMutex.h:466
bool IsLocked() const noexcept
Definition PlatformMutex.h:505
SharedMutex * mutex_
Definition PlatformMutex.h:515
PlatformSharedLock(SharedMutex &mutex, uint32_t timeout_ms=0) noexcept
Definition PlatformMutex.h:468
~PlatformSharedLock() noexcept
Definition PlatformMutex.h:477
void Unlock() noexcept
Definition PlatformMutex.h:507
bool locked_
Definition PlatformMutex.h:516
PlatformSharedLock(PlatformSharedLock &&other) noexcept
Definition PlatformMutex.h:488
PlatformSharedLock & operator=(const PlatformSharedLock &)=delete
PlatformSharedLock(const PlatformSharedLock &)=delete
PlatformSharedLock & operator=(PlatformSharedLock &&other) noexcept
Definition PlatformMutex.h:494
Reader-writer mutex using two regular mutexes + atomic counters.
Definition PlatformMutex.h:252
bool lock() noexcept
Definition PlatformMutex.h:297
bool try_lock_for(uint32_t timeout_ms) noexcept
Definition PlatformMutex.h:315
~PlatformSharedMutexImpl() noexcept
Definition PlatformMutex.h:260
bool try_lock() noexcept
Definition PlatformMutex.h:304
void unlock_shared() noexcept
Definition PlatformMutex.h:385
PlatformSharedMutexImpl(PlatformSharedMutexImpl &&other) noexcept
Definition PlatformMutex.h:270
PlatformSharedMutexImpl & operator=(PlatformSharedMutexImpl &&other) noexcept
Definition PlatformMutex.h:279
Backend::MutexHandle writer_mutex_
Definition PlatformMutex.h:393
PlatformSharedMutexImpl() noexcept
Definition PlatformMutex.h:254
void unlock() noexcept
Definition PlatformMutex.h:334
bool lock_shared() noexcept
Definition PlatformMutex.h:341
std::atomic< int > readers_
Definition PlatformMutex.h:395
bool try_lock_shared() noexcept
Definition PlatformMutex.h:354
PlatformSharedMutexImpl & operator=(const PlatformSharedMutexImpl &)=delete
PlatformSharedMutexImpl(const PlatformSharedMutexImpl &)=delete
bool try_lock_shared_for(uint32_t timeout_ms) noexcept
Definition PlatformMutex.h:365
Backend::MutexHandle reader_mutex_
Definition PlatformMutex.h:394
std::atomic< bool > writer_active_
Definition PlatformMutex.h:396
Definition PlatformMutex.h:133
static uint32_t MsToTicks(uint32_t ms) noexcept
Convert milliseconds to RTOS ticks (minimum 1 tick for non-zero input).
Definition PlatformMutex.h:149
static uint64_t GetCurrentTimeUs() noexcept
Get current time in microseconds (from RTOS tick count).
Definition PlatformMutex.h:139
RAII exclusive lock guard for any mutex with lock()/try_lock_for()/unlock().
Definition PlatformMutex.h:408
PlatformUniqueLock(Mutex &mutex, uint32_t timeout_ms=0) noexcept
Definition PlatformMutex.h:410
PlatformUniqueLock(PlatformUniqueLock &&other) noexcept
Definition PlatformMutex.h:430
~PlatformUniqueLock() noexcept
Definition PlatformMutex.h:419
PlatformUniqueLock(const PlatformUniqueLock &)=delete
PlatformUniqueLock & operator=(const PlatformUniqueLock &)=delete
PlatformUniqueLock & operator=(PlatformUniqueLock &&other) noexcept
Definition PlatformMutex.h:436
bool IsLocked() const noexcept
Definition PlatformMutex.h:447
bool locked_
Definition PlatformMutex.h:458
void Unlock() noexcept
Definition PlatformMutex.h:449
Mutex * mutex_
Definition PlatformMutex.h:457
No-op mutex backend – all operations compile to nothing.
Definition PlatformMutex.h:61
uint8_t RecursiveMutexHandle
Opaque handle for a recursive mutex (1 byte, unused by no-op backend)
Definition PlatformMutex.h:64
static constexpr uint32_t MAX_DELAY
Infinite wait.
Definition PlatformMutex.h:69
static constexpr uint32_t msToTicks(uint32_t ms) noexcept
Convert milliseconds to RTOS ticks.
Definition PlatformMutex.h:100
static constexpr bool lockMutex(MutexHandle *, uint32_t) noexcept
Lock with timeout (ticks). Returns true on success.
Definition PlatformMutex.h:90
static constexpr void unlockMutex(MutexHandle *) noexcept
Unlock regular mutex.
Definition PlatformMutex.h:94
uint8_t MutexHandle
Opaque handle for a regular (non-recursive) mutex (1 byte, unused)
Definition PlatformMutex.h:66
static constexpr void destroyMutex(MutexHandle *) noexcept
Destroy a regular mutex pointed to by *h.
Definition PlatformMutex.h:88
static constexpr void unlockRecursive(RecursiveMutexHandle *) noexcept
Unlock recursive mutex.
Definition PlatformMutex.h:82
static constexpr void createRecursive(RecursiveMutexHandle *) noexcept
Create a recursive mutex. Backend writes into *h.
Definition PlatformMutex.h:74
static constexpr void createMutex(MutexHandle *) noexcept
Create a regular (non-recursive) mutex. Backend writes into *h.
Definition PlatformMutex.h:86
static constexpr uint32_t TICK_RATE_HZ
Assumed tick rate.
Definition PlatformMutex.h:70
static constexpr bool tryLockMutex(MutexHandle *) noexcept
Try lock (non-blocking). Returns true on success.
Definition PlatformMutex.h:92
static constexpr bool tryLockRecursive(RecursiveMutexHandle *) noexcept
Try lock (non-blocking). Returns true on success.
Definition PlatformMutex.h:80
static constexpr bool lockRecursive(RecursiveMutexHandle *, uint32_t) noexcept
Lock recursively with timeout (ticks). Returns true on success.
Definition PlatformMutex.h:78
static constexpr void yield() noexcept
Yield to other tasks (no-op in single-threaded).
Definition PlatformMutex.h:102
static constexpr uint32_t getTickCount() noexcept
Get current RTOS tick count.
Definition PlatformMutex.h:98
static constexpr void destroyRecursive(RecursiveMutexHandle *) noexcept
Destroy a recursive mutex pointed to by *h.
Definition PlatformMutex.h:76