From 65b5b20bda06812eb0ad4f5bca64bec08e2b08dc Mon Sep 17 00:00:00 2001 From: pschatzmann Date: Thu, 2 Jan 2025 22:39:17 +0100 Subject: [PATCH] Restructure Concurrency --- src/AudioTools/AudioLibs/Concurrency.h | 2 +- src/AudioTools/Concurrency/LockGuard.h | 87 ++----------------- src/AudioTools/Concurrency/Mutex.h | 76 ++++++++++++++++ src/AudioTools/Concurrency/MutexRTOS.h | 45 ++++++++++ src/AudioTools/Concurrency/{All.h => RTOS.h} | 1 + .../Concurrency/SynchronizedBuffers.h | 6 +- 6 files changed, 135 insertions(+), 82 deletions(-) create mode 100644 src/AudioTools/Concurrency/Mutex.h create mode 100644 src/AudioTools/Concurrency/MutexRTOS.h rename src/AudioTools/Concurrency/{All.h => RTOS.h} (91%) diff --git a/src/AudioTools/AudioLibs/Concurrency.h b/src/AudioTools/AudioLibs/Concurrency.h index 8c913dce3..50c8755b6 100644 --- a/src/AudioTools/AudioLibs/Concurrency.h +++ b/src/AudioTools/AudioLibs/Concurrency.h @@ -4,4 +4,4 @@ * @ingroup main * @brief Multicore support */ -#include "AudioTools/Concurrency/All.h" +#include "AudioTools/Concurrency/RTOS.h" diff --git a/src/AudioTools/Concurrency/LockGuard.h b/src/AudioTools/Concurrency/LockGuard.h index 0ee549b13..2a8526e97 100644 --- a/src/AudioTools/Concurrency/LockGuard.h +++ b/src/AudioTools/Concurrency/LockGuard.h @@ -1,83 +1,10 @@ #pragma once #include "AudioConfig.h" #include "AudioTools/CoreAudio/AudioLogger.h" - -#ifdef USE_STD_CONCURRENCY -# include -#endif - -#ifdef ESP32 -# include "freertos/FreeRTOS.h" -# include "freertos/semphr.h" -#else -# include "FreeRTOS.h" -# include "semphr.h" -#endif +#include "Mutex.h" namespace audio_tools { -/** - * @brief Empty Mutex implementation which does nothing - * @ingroup concurrency - * @author Phil Schatzmann - * @copyright GPLv3 - */ -class MutexBase { -public: - virtual void lock() {} - virtual void unlock() {} -}; - -#if defined(USE_STD_CONCURRENCY) - -/** - * @brief Mutex implemntation based on std::mutex - * @ingroup concurrency - * @author Phil Schatzmann - * @copyright GPLv3 - */ -class StdMutex : public MutexBase { -public: - void lock() override { std_mutex.lock(); } - void unlock() override { std_mutex.unlock(); } - -protected: - std::mutex std_mutex; -}; - -#endif - - -/** - * @brief Mutex implemntation using FreeRTOS - * @ingroup concurrency - * @author Phil Schatzmann - * @copyright GPLv3 * - */ -class Mutex : public MutexBase { -public: - Mutex() { - TRACED(); - xSemaphore = xSemaphoreCreateBinary(); - xSemaphoreGive(xSemaphore); - } - ~Mutex() { - TRACED(); - vSemaphoreDelete(xSemaphore); - } - void lock() override { - TRACED(); - xSemaphoreTake(xSemaphore, portMAX_DELAY); - } - void unlock() override { - TRACED(); - xSemaphoreGive(xSemaphore); - } - -protected: - SemaphoreHandle_t xSemaphore = NULL; -}; - /** * @brief RAII implementaion using a Mutex: Only a few microcontrollers provide @@ -90,23 +17,25 @@ class Mutex : public MutexBase { */ class LockGuard { public: - LockGuard(Mutex &mutex) { + LockGuard(MutexBase &mutex) { TRACED(); p_mutex = &mutex; p_mutex->lock(); } - LockGuard(Mutex *mutex) { + LockGuard(MutexBase *mutex) { TRACED(); p_mutex = mutex; - p_mutex->lock(); + if (p_mutex != nullptr) + p_mutex->lock(); } ~LockGuard() { TRACED(); - p_mutex->unlock(); + if (p_mutex != nullptr) + p_mutex->unlock(); } protected: - Mutex *p_mutex = nullptr; + MutexBase *p_mutex = nullptr; }; } diff --git a/src/AudioTools/Concurrency/Mutex.h b/src/AudioTools/Concurrency/Mutex.h new file mode 100644 index 000000000..0b9f30e0d --- /dev/null +++ b/src/AudioTools/Concurrency/Mutex.h @@ -0,0 +1,76 @@ +#pragma once +#include "AudioConfig.h" +#include + +#ifdef USE_STD_CONCURRENCY +# include +#endif + +namespace audio_tools { + +/** + * @brief Empty Mutex implementation which does nothing + * @ingroup concurrency + * @author Phil Schatzmann + * @copyright GPLv3 + */ +class MutexBase { +public: + virtual void lock() {} + virtual void unlock() {} +}; + + +class SpinLock : public MutexBase { + std::atomic lock_ = {0}; + + void lock() { + for (;;) { + // Optimistically assume the lock is free on the first try + if (!lock_.exchange(true, std::memory_order_acquire)) { + return; + } + // Wait for lock to be released without generating cache misses + while (lock_.load(std::memory_order_relaxed)) { + // Issue X86 PAUSE or ARM YIELD instruction to reduce contention between + // hyper-threads + //__builtin_ia32_pause(); + delay(1); + } + } + } + + bool try_lock() { + // First do a relaxed load to check if lock is free in order to prevent + // unnecessary cache misses if someone does while(!try_lock()) + return !lock_.load(std::memory_order_relaxed) && + !lock_.exchange(true, std::memory_order_acquire); + } + + void unlock() { + lock_.store(false, std::memory_order_release); + } +}; + + +#if defined(USE_STD_CONCURRENCY) + +/** + * @brief Mutex implemntation based on std::mutex + * @ingroup concurrency + * @author Phil Schatzmann + * @copyright GPLv3 + */ +class StdMutex : public MutexBase { +public: + void lock() override { std_mutex.lock(); } + void unlock() override { std_mutex.unlock(); } + +protected: + std::mutex std_mutex; +}; + +#endif + + +} \ No newline at end of file diff --git a/src/AudioTools/Concurrency/MutexRTOS.h b/src/AudioTools/Concurrency/MutexRTOS.h new file mode 100644 index 000000000..44ade8869 --- /dev/null +++ b/src/AudioTools/Concurrency/MutexRTOS.h @@ -0,0 +1,45 @@ +#pragma once +#include "AudioConfig.h" +#include "Mutex.h" + +#ifdef ESP32 +# include "freertos/FreeRTOS.h" +# include "freertos/semphr.h" +#else +# include "FreeRTOS.h" +# include "semphr.h" +#endif + +namespace audio_tools { + +/** + * @brief Mutex implemntation using FreeRTOS + * @ingroup concurrency + * @author Phil Schatzmann + * @copyright GPLv3 * + */ +class Mutex : public MutexBase { +public: + Mutex() { + TRACED(); + xSemaphore = xSemaphoreCreateBinary(); + xSemaphoreGive(xSemaphore); + } + ~Mutex() { + TRACED(); + vSemaphoreDelete(xSemaphore); + } + void lock() override { + TRACED(); + xSemaphoreTake(xSemaphore, portMAX_DELAY); + } + void unlock() override { + TRACED(); + xSemaphoreGive(xSemaphore); + } + +protected: + SemaphoreHandle_t xSemaphore = NULL; +}; + +} \ No newline at end of file diff --git a/src/AudioTools/Concurrency/All.h b/src/AudioTools/Concurrency/RTOS.h similarity index 91% rename from src/AudioTools/Concurrency/All.h rename to src/AudioTools/Concurrency/RTOS.h index 1ea738402..38de2126d 100644 --- a/src/AudioTools/Concurrency/All.h +++ b/src/AudioTools/Concurrency/RTOS.h @@ -3,4 +3,5 @@ #include "AudioTools/Concurrency/BufferRTOS.h" #include "AudioTools/Concurrency/SynchronizedBuffers.h" #include "AudioTools/Concurrency/Task.h" +#include "MutexRTOS.h" #include "AudioTools/Concurrency/LockGuard.h" \ No newline at end of file diff --git a/src/AudioTools/Concurrency/SynchronizedBuffers.h b/src/AudioTools/Concurrency/SynchronizedBuffers.h index b06fa84f2..5862b34a2 100644 --- a/src/AudioTools/Concurrency/SynchronizedBuffers.h +++ b/src/AudioTools/Concurrency/SynchronizedBuffers.h @@ -5,6 +5,7 @@ #include "AudioTools/CoreAudio/Buffers.h" #include "AudioTools/CoreAudio/AudioLogger.h" + #ifdef ESP32 # include "freertos/FreeRTOS.h" # include "AudioTools/Concurrency/QueueRTOS.h" @@ -15,6 +16,7 @@ # include "stream_buffer.h" #endif +#include "Mutex.h" #include "LockGuard.h" namespace audio_tools { @@ -31,7 +33,7 @@ namespace audio_tools { template class SynchronizedBuffer : public BaseBuffer { public: - SynchronizedBuffer(BaseBuffer &buffer, Mutex &mutex, bool syncAvailable=false) { + SynchronizedBuffer(BaseBuffer &buffer, MutexBase &mutex, bool syncAvailable=false) { p_buffer = &buffer; p_mutex = &mutex; is_sync_available = syncAvailable; @@ -120,7 +122,7 @@ class SynchronizedBuffer : public BaseBuffer { protected: BaseBuffer *p_buffer = nullptr; - Mutex *p_mutex = nullptr; + MutexBase *p_mutex = nullptr; bool is_sync_available = false; };