Split off RecursiveMutex from Mutex (#437)

* Split off RecursiveMutex from Mutex

* Fix

* Code quality
This commit is contained in:
Ken Van Hoeylandt
2025-12-28 12:30:54 +01:00
committed by GitHub
parent f48654d3dc
commit 3fc2ff8bc6
45 changed files with 185 additions and 177 deletions
+22 -20
View File
@@ -1,34 +1,25 @@
/**
* @file mutex.h
* @file Mutex.h
* Mutex
*/
#pragma once
#include "Check.h"
#include "Lock.h"
#include "RtosCompatSemaphore.h"
#include "Thread.h"
#include "kernel/Kernel.h"
#include <memory>
#include <cassert>
namespace tt {
/**
* Wrapper for FreeRTOS xSemaphoreCreateMutex and xSemaphoreCreateRecursiveMutex
* Wrapper for FreeRTOS xSemaphoreCreateMutex
* Cannot be used in IRQ mode (within ISR context)
*/
class Mutex final : public Lock {
public:
/**
* A "Normal" mutex can only be locked once. Even from within the same task/thread.
* A "Recursive" mutex can be locked again from the same task/thread.
*/
enum class Type {
Normal,
Recursive,
};
private:
struct SemaphoreHandleDeleter {
@@ -38,29 +29,40 @@ private:
}
};
std::unique_ptr<std::remove_pointer_t<QueueHandle_t>, SemaphoreHandleDeleter> handle;
Type type;
std::unique_ptr<std::remove_pointer_t<QueueHandle_t>, SemaphoreHandleDeleter> handle = std::unique_ptr<std::remove_pointer_t<QueueHandle_t>, SemaphoreHandleDeleter>(xSemaphoreCreateMutex());
public:
using Lock::lock;
explicit Mutex(Type type = Type::Normal);
explicit Mutex() {
assert(handle != nullptr);
}
~Mutex() override = default;
/** Attempt to lock the mutex. Blocks until timeout passes or lock is acquired.
* @param[in] timeout
* @return success result
*/
bool lock(TickType_t timeout) const override;
bool lock(TickType_t timeout) const override {
assert(!kernel::isIsr());
return xSemaphoreTake(handle.get(), timeout) == pdPASS;
}
/** Attempt to unlock the mutex.
* @return success result
*/
bool unlock() const override;
bool unlock() const override {
assert(!kernel::isIsr());
return xSemaphoreGive(handle.get()) == pdPASS;
}
/** @return the owner of the thread */
ThreadId getOwner() const;
ThreadId getOwner() const {
assert(!kernel::isIsr());
return xSemaphoreGetMutexHolder(handle.get());
}
};
} // namespace
} // namespace tt
@@ -0,0 +1,67 @@
/**
* @file RecursiveMutex.h
* RecursiveMutex
*/
#pragma once
#include "Lock.h"
#include "RtosCompatSemaphore.h"
#include "Thread.h"
#include "kernel/Kernel.h"
#include <memory>
#include <cassert>
namespace tt {
/**
* Wrapper for FreeRTOS xSemaphoreCreateRecursiveMutex
* Cannot be used in IRQ mode (within ISR context)
*/
class RecursiveMutex final : public Lock {
private:
struct SemaphoreHandleDeleter {
void operator()(QueueHandle_t handleToDelete) {
assert(!kernel::isIsr());
vSemaphoreDelete(handleToDelete);
}
};
std::unique_ptr<std::remove_pointer_t<QueueHandle_t>, SemaphoreHandleDeleter> handle = std::unique_ptr<std::remove_pointer_t<QueueHandle_t>, SemaphoreHandleDeleter>(xSemaphoreCreateRecursiveMutex());
public:
using Lock::lock;
explicit RecursiveMutex() {
assert(handle != nullptr);
}
~RecursiveMutex() override = default;
/** Attempt to lock the mutex. Blocks until timeout passes or lock is acquired.
* @param[in] timeout
* @return success result
*/
bool lock(TickType_t timeout) const override {
assert(!kernel::isIsr());
return xSemaphoreTakeRecursive(handle.get(), timeout) == pdPASS;
}
/** Attempt to unlock the mutex.
* @return success result
*/
bool unlock() const override {
assert(!kernel::isIsr());
return xSemaphoreGiveRecursive(handle.get()) == pdPASS;
}
/** @return the owner of the thread */
ThreadId getOwner() const {
assert(!kernel::isIsr());
return xSemaphoreGetMutexHolder(handle.get());
}
};
} // namespace
-77
View File
@@ -1,77 +0,0 @@
#include "Tactility/Mutex.h"
#include "Tactility/Check.h"
#include "Tactility/CoreDefines.h"
#include "Tactility/Log.h"
namespace tt {
#define MUTEX_DEBUGGING false
#if MUTEX_DEBUGGING
#define TAG "mutex"
void tt_mutex_info(Mutex mutex, const char* label) {
MutexData* data = (MutexData*)mutex;
if (data == NULL) {
TT_LOG_I(TAG, "mutex %s: is NULL", label);
} else {
TT_LOG_I(TAG, "mutex %s: handle=%0X type=%d owner=%0x", label, data->handle, data->type, tt_mutex_get_owner(mutex));
}
}
#else
#define tt_mutex_info(mutex, text)
#endif
static inline SemaphoreHandle_t createSemaphoreHandle(Mutex::Type type) {
switch (type) {
case Mutex::Type::Normal:
return xSemaphoreCreateMutex();
case Mutex::Type::Recursive:
return xSemaphoreCreateRecursiveMutex();
default:
tt_crash("Mutex type unknown/corrupted");
}
}
Mutex::Mutex(Type type) : handle(createSemaphoreHandle(type)), type(type) {
tt_mutex_info(data, "alloc");
assert(handle != nullptr);
}
bool Mutex::lock(TickType_t timeout) const {
assert(!kernel::isIsr());
assert(handle != nullptr);
tt_mutex_info(mutex, "acquire");
switch (type) {
case Type::Normal:
return xSemaphoreTake(handle.get(), timeout) == pdPASS;
case Type::Recursive:
return xSemaphoreTakeRecursive(handle.get(), timeout) == pdPASS;
default:
tt_crash();
}
}
bool Mutex::unlock() const {
assert(!kernel::isIsr());
assert(handle != nullptr);
tt_mutex_info(mutex, "release");
switch (type) {
case Type::Normal:
return xSemaphoreGive(handle.get()) == pdPASS;
case Type::Recursive:
return xSemaphoreGiveRecursive(handle.get()) == pdPASS;
default:
tt_crash();
}
}
ThreadId Mutex::getOwner() const {
assert(!kernel::isIsr());
assert(handle != nullptr);
return (ThreadId)xSemaphoreGetMutexHolder(handle.get());
}
} // namespace