Skip to content

Commit

Permalink
Restructure Concurrency
Browse files Browse the repository at this point in the history
  • Loading branch information
pschatzmann committed Jan 2, 2025
1 parent a46a7f8 commit 65b5b20
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 82 deletions.
2 changes: 1 addition & 1 deletion src/AudioTools/AudioLibs/Concurrency.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
* @ingroup main
* @brief Multicore support
*/
#include "AudioTools/Concurrency/All.h"
#include "AudioTools/Concurrency/RTOS.h"
87 changes: 8 additions & 79 deletions src/AudioTools/Concurrency/LockGuard.h
Original file line number Diff line number Diff line change
@@ -1,83 +1,10 @@
#pragma once
#include "AudioConfig.h"
#include "AudioTools/CoreAudio/AudioLogger.h"

#ifdef USE_STD_CONCURRENCY
# include <mutex>
#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
Expand All @@ -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;
};

}
Expand Down
76 changes: 76 additions & 0 deletions src/AudioTools/Concurrency/Mutex.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#pragma once
#include "AudioConfig.h"
#include <atomic>

#ifdef USE_STD_CONCURRENCY
# include <mutex>
#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<bool> 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


}
45 changes: 45 additions & 0 deletions src/AudioTools/Concurrency/MutexRTOS.h
Original file line number Diff line number Diff line change
@@ -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;
};

}
Original file line number Diff line number Diff line change
Expand Up @@ -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"
6 changes: 4 additions & 2 deletions src/AudioTools/Concurrency/SynchronizedBuffers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -15,6 +16,7 @@
# include "stream_buffer.h"
#endif

#include "Mutex.h"
#include "LockGuard.h"

namespace audio_tools {
Expand All @@ -31,7 +33,7 @@ namespace audio_tools {
template <typename T>
class SynchronizedBuffer : public BaseBuffer<T> {
public:
SynchronizedBuffer(BaseBuffer<T> &buffer, Mutex &mutex, bool syncAvailable=false) {
SynchronizedBuffer(BaseBuffer<T> &buffer, MutexBase &mutex, bool syncAvailable=false) {
p_buffer = &buffer;
p_mutex = &mutex;
is_sync_available = syncAvailable;
Expand Down Expand Up @@ -120,7 +122,7 @@ class SynchronizedBuffer : public BaseBuffer<T> {

protected:
BaseBuffer<T> *p_buffer = nullptr;
Mutex *p_mutex = nullptr;
MutexBase *p_mutex = nullptr;
bool is_sync_available = false;
};

Expand Down

0 comments on commit 65b5b20

Please sign in to comment.