HF Interface Wrapper 0.1.0-dev
Embedded C++ hardware abstraction layer
Loading...
Searching...
No Matches
PlatformMutex.h
Go to the documentation of this file.
1
18#pragma once
19
20#include "McuSelect.h"
21
22// Suppress pedantic warnings for ESP-IDF headers
23#ifdef __cplusplus
24#pragma GCC diagnostic push
25#pragma GCC diagnostic ignored "-Wpedantic"
26#endif
27
28// ESP-IDF C headers must be wrapped in extern "C" for C++ compatibility
29#ifdef __cplusplus
30extern "C" {
31#endif
32
33#ifdef HF_MCU_FAMILY_ESP32
34#include "freertos/FreeRTOS.h"
35#include "freertos/semphr.h"
36#include "freertos/task.h"
37#elif defined(HF_MCU_FAMILY_STM32)
38#include "FreeRTOS.h"
39#include "cmsis_os.h"
40#include "semphr.h"
41#include "task.h"
42#elif defined(HF_MCU_FAMILY_RP2040)
43#include "FreeRTOS.h"
44#include "semphr.h"
45#include "task.h"
46#else
47#error \
48 "RTOS mutex implementation not available for this MCU platform. Please add support in PlatformMutex.h"
49#endif
50
51#ifdef __cplusplus
52}
53#endif
54
55// Restore warnings after ESP-IDF headers
56#ifdef __cplusplus
57#pragma GCC diagnostic pop
58#endif
59
60#include <atomic>
61#include <cstdint>
62
64public:
65 static uint64_t GetCurrentTimeUs() noexcept {
66 return static_cast<uint64_t>(xTaskGetTickCount()) * 1000 / configTICK_RATE_HZ * 1000;
67 }
68
69 static TickType_t MsToTicks(uint32_t ms) noexcept {
70 if (ms == 0) {
71 return 0;
72 }
73 const TickType_t ticks = pdMS_TO_TICKS(ms);
74 return (ticks > 0) ? ticks : 1;
75 }
76};
77
79public:
80 PlatformMutex() noexcept : handle_(xSemaphoreCreateRecursiveMutex()) {}
81
82 ~PlatformMutex() noexcept {
83 if (handle_) {
84 vSemaphoreDelete(handle_);
85 }
86 }
87
88 PlatformMutex(const PlatformMutex&) = delete;
90
91 PlatformMutex(PlatformMutex&& other) noexcept : handle_(other.handle_) {
92 other.handle_ = nullptr;
93 }
94
96 if (this != &other) {
97 if (handle_) {
98 vSemaphoreDelete(handle_);
99 }
100 handle_ = other.handle_;
101 other.handle_ = nullptr;
102 }
103 return *this;
104 }
105
106 bool lock() noexcept {
107 if (!handle_)
108 return false;
109 return xSemaphoreTakeRecursive(handle_, portMAX_DELAY) == pdTRUE;
110 }
111
112 bool try_lock() noexcept {
113 if (!handle_)
114 return false;
115 return xSemaphoreTakeRecursive(handle_, 0) == pdTRUE;
116 }
117
118 bool try_lock_for(uint32_t timeout_ms) noexcept {
119 if (!handle_)
120 return false;
121 const TickType_t ticks = PlatformTime::MsToTicks(timeout_ms);
122 return xSemaphoreTakeRecursive(handle_, ticks) == pdTRUE;
123 }
124
125 void unlock() noexcept {
126 if (handle_) {
127 xSemaphoreGiveRecursive(handle_);
128 }
129 }
130
131 SemaphoreHandle_t native_handle() const noexcept {
132 return handle_;
133 }
134
135 // Convenience FreeRTOS-style API -------------------------------------------------
136 bool Take(uint32_t timeout_ms = 0) noexcept {
137 if (timeout_ms > 0) {
138 return try_lock_for(timeout_ms);
139 }
140 return lock();
141 }
142
143 void Give() noexcept {
144 unlock();
145 }
146
147 // Shared lock methods (delegated to regular mutex for simplicity)
148 bool lock_shared() noexcept {
149 return lock();
150 }
151
152 bool try_lock_shared() noexcept {
153 return try_lock();
154 }
155
156 bool try_lock_shared_for(uint32_t timeout_ms) noexcept {
157 return try_lock_for(timeout_ms);
158 }
159
160 void unlock_shared() noexcept {
161 unlock();
162 }
163
164private:
165 SemaphoreHandle_t handle_;
166};
167
169public:
171 writer_mutex_ = xSemaphoreCreateMutex();
172 reader_mutex_ = xSemaphoreCreateMutex();
173 }
174
176 if (writer_mutex_ != nullptr) {
177 vSemaphoreDelete(writer_mutex_);
178 }
179 if (reader_mutex_ != nullptr) {
180 vSemaphoreDelete(reader_mutex_);
181 }
182 }
183
186
188 : writer_mutex_(other.writer_mutex_), reader_mutex_(other.reader_mutex_),
189 readers_(other.readers_.load()), writer_active_(other.writer_active_.load()) {
190 other.writer_mutex_ = nullptr;
191 other.reader_mutex_ = nullptr;
192 other.readers_.store(0);
193 other.writer_active_.store(false);
194 }
195
197 if (this != &other) {
198 if (writer_mutex_ != nullptr) {
199 vSemaphoreDelete(writer_mutex_);
200 }
201 if (reader_mutex_ != nullptr) {
202 vSemaphoreDelete(reader_mutex_);
203 }
204 writer_mutex_ = other.writer_mutex_;
205 reader_mutex_ = other.reader_mutex_;
206 readers_.store(other.readers_.load());
207 writer_active_.store(other.writer_active_.load());
208 other.writer_mutex_ = nullptr;
209 other.reader_mutex_ = nullptr;
210 other.readers_.store(0);
211 other.writer_active_.store(false);
212 }
213 return *this;
214 }
215
216 bool lock() noexcept {
217 if (xSemaphoreTake(writer_mutex_, portMAX_DELAY) != pdTRUE) {
218 return false;
219 }
220 writer_active_.store(true);
221 while (readers_.load() > 0) {
222 taskYIELD();
223 }
224 return true;
225 }
226
227 bool try_lock() noexcept {
228 if (xSemaphoreTake(writer_mutex_, 0) != pdTRUE) {
229 return false;
230 }
231 writer_active_.store(true);
232 if (readers_.load() > 0) {
233 writer_active_.store(false);
234 xSemaphoreGive(writer_mutex_);
235 return false;
236 }
237 return true;
238 }
239
240 bool try_lock_for(uint32_t timeout_ms) noexcept {
241 const TickType_t ticks = PlatformTime::MsToTicks(timeout_ms);
242 const TickType_t start_time = xTaskGetTickCount();
243 if (xSemaphoreTake(writer_mutex_, ticks) != pdTRUE) {
244 return false;
245 }
246 writer_active_.store(true);
247 const TickType_t elapsed = xTaskGetTickCount() - start_time;
248 const TickType_t remaining = (elapsed < ticks) ? ticks - elapsed : 0;
249 const TickType_t reader_wait_end = xTaskGetTickCount() + remaining;
250 while (readers_.load() > 0) {
251 if (xTaskGetTickCount() >= reader_wait_end) {
252 writer_active_.store(false);
253 xSemaphoreGive(writer_mutex_);
254 return false;
255 }
256 taskYIELD();
257 }
258 return true;
259 }
260
261 void unlock() noexcept {
262 writer_active_.store(false);
263 xSemaphoreGive(writer_mutex_);
264 }
265
266 bool lock_shared() noexcept {
267 while (true) {
268 if (xSemaphoreTake(reader_mutex_, portMAX_DELAY) != pdTRUE) {
269 return false;
270 }
271 if (!writer_active_.load()) {
272 readers_++;
273 xSemaphoreGive(reader_mutex_);
274 return true;
275 }
276 xSemaphoreGive(reader_mutex_);
277 taskYIELD();
278 }
279 }
280
281 bool try_lock_shared() noexcept {
282 if (xSemaphoreTake(reader_mutex_, 0) != pdTRUE) {
283 return false;
284 }
285 if (!writer_active_.load()) {
286 readers_++;
287 xSemaphoreGive(reader_mutex_);
288 return true;
289 }
290 xSemaphoreGive(reader_mutex_);
291 return false;
292 }
293
294 bool try_lock_shared_for(uint32_t timeout_ms) noexcept {
295 const TickType_t ticks = PlatformTime::MsToTicks(timeout_ms);
296 const TickType_t start_time = xTaskGetTickCount();
297 while (true) {
298 const TickType_t elapsed = xTaskGetTickCount() - start_time;
299 if (elapsed >= ticks) {
300 return false;
301 }
302 const TickType_t remaining = ticks - elapsed;
303 if (xSemaphoreTake(reader_mutex_, remaining) != pdTRUE) {
304 return false;
305 }
306 if (!writer_active_.load()) {
307 readers_++;
308 xSemaphoreGive(reader_mutex_);
309 return true;
310 }
311 xSemaphoreGive(reader_mutex_);
312 const TickType_t new_elapsed = xTaskGetTickCount() - start_time;
313 if (new_elapsed >= ticks) {
314 return false;
315 }
316 taskYIELD();
317 }
318 }
319
320 void unlock_shared() noexcept {
321 if (xSemaphoreTake(reader_mutex_, portMAX_DELAY) == pdTRUE) {
322 if (readers_.load() > 0) {
323 readers_--;
324 }
325 xSemaphoreGive(reader_mutex_);
326 }
327 }
328
329private:
330 SemaphoreHandle_t writer_mutex_;
331 SemaphoreHandle_t reader_mutex_;
332 std::atomic<int> readers_;
333 std::atomic<bool> writer_active_;
334};
335
336template <typename Mutex>
338public:
339 explicit PlatformUniqueLock(Mutex& mutex, uint32_t timeout_ms = 0) noexcept
340 : mutex_(&mutex), locked_(false) {
341 if (timeout_ms > 0) {
342 locked_ = mutex_->try_lock_for(timeout_ms);
343 } else {
344 locked_ = mutex_->lock();
345 }
346 }
347
349 if (locked_ && mutex_) {
350 mutex_->unlock();
351 }
352 }
353
356
357 PlatformUniqueLock(PlatformUniqueLock&& other) noexcept : mutex_(other.mutex_), locked_(other.locked_) {
358 other.mutex_ = nullptr;
359 other.locked_ = false;
360 }
361
363 if (this != &other) {
364 if (locked_ && mutex_) {
365 mutex_->unlock();
366 }
367 mutex_ = other.mutex_;
368 locked_ = other.locked_;
369 other.mutex_ = nullptr;
370 other.locked_ = false;
371 }
372 return *this;
373 }
374
375 [[nodiscard]] bool IsLocked() const noexcept {
376 return locked_;
377 }
378
379 void Unlock() noexcept {
380 if (locked_ && mutex_) {
381 mutex_->unlock();
382 locked_ = false;
383 }
384 }
385
386private:
387 Mutex* mutex_;
389};
390
391template <typename SharedMutex>
393public:
394 explicit PlatformSharedLock(SharedMutex& mutex, uint32_t timeout_ms = 0) noexcept
395 : mutex_(&mutex), locked_(false) {
396 if (timeout_ms > 0) {
397 locked_ = mutex_->try_lock_shared_for(timeout_ms);
398 } else {
399 locked_ = mutex_->lock_shared();
400 }
401 }
402
404 if (locked_ && mutex_) {
405 mutex_->unlock_shared();
406 }
407 }
408
411
412 PlatformSharedLock(PlatformSharedLock&& other) noexcept : mutex_(other.mutex_), locked_(other.locked_) {
413 other.mutex_ = nullptr;
414 other.locked_ = false;
415 }
416
418 if (this != &other) {
419 if (locked_ && mutex_) {
420 mutex_->unlock_shared();
421 }
422 mutex_ = other.mutex_;
423 locked_ = other.locked_;
424 other.mutex_ = nullptr;
425 other.locked_ = false;
426 }
427 return *this;
428 }
429
430 [[nodiscard]] bool IsLocked() const noexcept {
431 return locked_;
432 }
433
434 void Unlock() noexcept {
435 if (locked_ && mutex_) {
436 mutex_->unlock_shared();
437 locked_ = false;
438 }
439 }
440
441private:
442 SharedMutex* mutex_;
444};
445
446//==============================================================================
447// CONVENIENCE TYPE ALIASES
448//==============================================================================
449
451template <typename Mutex>
453
Centralized MCU platform selection and configuration header.
Definition PlatformMutex.h:78
void Give() noexcept
Definition PlatformMutex.h:143
~PlatformMutex() noexcept
Definition PlatformMutex.h:82
SemaphoreHandle_t native_handle() const noexcept
Definition PlatformMutex.h:131
SemaphoreHandle_t handle_
Definition PlatformMutex.h:165
void unlock_shared() noexcept
Definition PlatformMutex.h:160
PlatformMutex(PlatformMutex &&other) noexcept
Definition PlatformMutex.h:91
bool try_lock_shared() noexcept
Definition PlatformMutex.h:152
bool try_lock() noexcept
Definition PlatformMutex.h:112
void unlock() noexcept
Definition PlatformMutex.h:125
PlatformMutex & operator=(PlatformMutex &&other) noexcept
Definition PlatformMutex.h:95
bool lock() noexcept
Definition PlatformMutex.h:106
bool try_lock_for(uint32_t timeout_ms) noexcept
Definition PlatformMutex.h:118
PlatformMutex(const PlatformMutex &)=delete
bool lock_shared() noexcept
Definition PlatformMutex.h:148
PlatformMutex() noexcept
Definition PlatformMutex.h:80
PlatformMutex & operator=(const PlatformMutex &)=delete
bool Take(uint32_t timeout_ms=0) noexcept
Definition PlatformMutex.h:136
bool try_lock_shared_for(uint32_t timeout_ms) noexcept
Definition PlatformMutex.h:156
Definition PlatformMutex.h:392
bool IsLocked() const noexcept
Definition PlatformMutex.h:430
SharedMutex * mutex_
Definition PlatformMutex.h:442
PlatformSharedLock(SharedMutex &mutex, uint32_t timeout_ms=0) noexcept
Definition PlatformMutex.h:394
~PlatformSharedLock() noexcept
Definition PlatformMutex.h:403
void Unlock() noexcept
Definition PlatformMutex.h:434
bool locked_
Definition PlatformMutex.h:443
PlatformSharedLock(PlatformSharedLock &&other) noexcept
Definition PlatformMutex.h:412
PlatformSharedLock & operator=(const PlatformSharedLock &)=delete
PlatformSharedLock(const PlatformSharedLock &)=delete
PlatformSharedLock & operator=(PlatformSharedLock &&other) noexcept
Definition PlatformMutex.h:417
Definition PlatformMutex.h:168
PlatformSharedMutex & operator=(const PlatformSharedMutex &)=delete
SemaphoreHandle_t writer_mutex_
Definition PlatformMutex.h:330
bool try_lock_shared_for(uint32_t timeout_ms) noexcept
Definition PlatformMutex.h:294
bool try_lock() noexcept
Definition PlatformMutex.h:227
void unlock() noexcept
Definition PlatformMutex.h:261
PlatformSharedMutex() noexcept
Definition PlatformMutex.h:170
~PlatformSharedMutex() noexcept
Definition PlatformMutex.h:175
std::atomic< bool > writer_active_
Definition PlatformMutex.h:333
void unlock_shared() noexcept
Definition PlatformMutex.h:320
PlatformSharedMutex(const PlatformSharedMutex &)=delete
PlatformSharedMutex(PlatformSharedMutex &&other) noexcept
Definition PlatformMutex.h:187
std::atomic< int > readers_
Definition PlatformMutex.h:332
SemaphoreHandle_t reader_mutex_
Definition PlatformMutex.h:331
bool try_lock_for(uint32_t timeout_ms) noexcept
Definition PlatformMutex.h:240
bool lock() noexcept
Definition PlatformMutex.h:216
bool lock_shared() noexcept
Definition PlatformMutex.h:266
bool try_lock_shared() noexcept
Definition PlatformMutex.h:281
PlatformSharedMutex & operator=(PlatformSharedMutex &&other) noexcept
Definition PlatformMutex.h:196
Definition PlatformMutex.h:63
static TickType_t MsToTicks(uint32_t ms) noexcept
Definition PlatformMutex.h:69
static uint64_t GetCurrentTimeUs() noexcept
Definition PlatformMutex.h:65
Definition PlatformMutex.h:337
PlatformUniqueLock(Mutex &mutex, uint32_t timeout_ms=0) noexcept
Definition PlatformMutex.h:339
PlatformUniqueLock(PlatformUniqueLock &&other) noexcept
Definition PlatformMutex.h:357
~PlatformUniqueLock() noexcept
Definition PlatformMutex.h:348
PlatformUniqueLock(const PlatformUniqueLock &)=delete
PlatformUniqueLock & operator=(const PlatformUniqueLock &)=delete
PlatformUniqueLock & operator=(PlatformUniqueLock &&other) noexcept
Definition PlatformMutex.h:362
bool IsLocked() const noexcept
Definition PlatformMutex.h:375
bool locked_
Definition PlatformMutex.h:388
void Unlock() noexcept
Definition PlatformMutex.h:379
Mutex * mutex_
Definition PlatformMutex.h:387