Skip to content
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion Os/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,29 @@ register_fprime_module(
add_named_os_module(Console Fw_Logger)
add_named_os_module("File;FileSystem;Directory" Utils_Hash Fw_DataStructures)
add_named_os_module(Task ${CMAKE_THREAD_LIBS_INIT})
add_named_os_module("Mutex;Condition")
# Mutex: Mutex.hpp is a thin public alias header (no Mutex.cpp); the interface and
# link-time delegate live in MutexInterface.hpp / DelegateMutex.{hpp,cpp}. Registered
# explicitly (rather than via add_named_os_module) because that helper assumes a
# matching <name>.cpp per header. Condition.{cpp,hpp} stays bundled into Os_Mutex as
# before, preserving the module name that the Stub impl and REQUIRES_IMPLEMENTATIONS
# references depend on.
register_fprime_module(
"Os_Mutex"
REQUIRES_IMPLEMENTATIONS
"Os_Mutex"
SOURCES
"${CMAKE_CURRENT_LIST_DIR}/DelegateMutex.cpp"
"${CMAKE_CURRENT_LIST_DIR}/Condition.cpp"
HEADERS
"${CMAKE_CURRENT_LIST_DIR}/Mutex.hpp"
"${CMAKE_CURRENT_LIST_DIR}/MutexInterface.hpp"
"${CMAKE_CURRENT_LIST_DIR}/DelegateMutex.hpp"
"${CMAKE_CURRENT_LIST_DIR}/Condition.hpp"
DEPENDS
Fw_Time
Fw_Types
)
fprime_target_dependencies(Os PUBLIC "Os_Mutex")
add_named_os_module(CountingSemaphore)
add_named_os_module(Queue)
add_named_os_module(Cpu)
Expand Down
39 changes: 39 additions & 0 deletions Os/DelegateMutex.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// ======================================================================
// \title Os/DelegateMutex.cpp
// \brief implementation of Os::DelegateMutex (link-time delegating Os::Mutex)
// ======================================================================
#include <Fw/Types/Assert.hpp>
#include <Os/DelegateMutex.hpp>

namespace Os {

// ----------------------------------------------------------------------
// DelegateMutex: link-time delegating implementation
// ----------------------------------------------------------------------

DelegateMutex::DelegateMutex() : m_delegate(*MutexInterface::getDelegate(m_handle_storage)) {
// m_handle_storage is placement-new storage populated by getDelegate(); do not value-initialize it (#5297)
FW_ASSERT(&this->m_delegate == reinterpret_cast<MutexInterface*>(&this->m_handle_storage[0]));
}

DelegateMutex::~DelegateMutex() {
FW_ASSERT(&this->m_delegate == reinterpret_cast<MutexInterface*>(&this->m_handle_storage[0]));
m_delegate.~MutexInterface();
}

MutexHandle* DelegateMutex::getHandle() {
FW_ASSERT(&this->m_delegate == reinterpret_cast<MutexInterface*>(&this->m_handle_storage[0]));
return this->m_delegate.getHandle();
}

DelegateMutex::Status DelegateMutex::take() {
FW_ASSERT(&this->m_delegate == reinterpret_cast<MutexInterface*>(&this->m_handle_storage[0]));
return this->m_delegate.take();
}

DelegateMutex::Status DelegateMutex::release() {
FW_ASSERT(&this->m_delegate == reinterpret_cast<MutexInterface*>(&this->m_handle_storage[0]));
return this->m_delegate.release();
}

} // namespace Os
48 changes: 48 additions & 0 deletions Os/DelegateMutex.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// ======================================================================
// \title Os/DelegateMutex.hpp
// \brief Define the Os::DelegateMutex class
// ======================================================================
#ifndef OS_DELEGATEMUTEX_HPP_
#define OS_DELEGATEMUTEX_HPP_

#include "Os/MutexInterface.hpp"

namespace Os {

//! \brief Link-time delegating Mutex implementation.
//!
//! Stores an implementation-defined mutex handle in a byte array and forwards all operations to a
//! delegate constructed (via placement-new) by MutexInterface::getDelegate(). Which getDelegate()
//! is linked selects the concrete implementation at link time. This is the default binding of the
//! Os::Mutex alias; platforms may instead alias Os::Mutex directly to a concrete implementation for
//! compile-time selection (see config/OsDelegateMutex.hpp).
class DelegateMutex final : public MutexInterface {
public:
DelegateMutex(); //!< Constructor. Mutex is unlocked when created
~DelegateMutex() final; //!< Destructor

//! \brief copy constructor is forbidden
DelegateMutex(const DelegateMutex& other) = delete;

//! \brief assignment operator is forbidden
DelegateMutex& operator=(const DelegateMutex& other) = delete;

//! \brief return the underlying mutex handle (implementation specific)
//! \return internal mutex handle representation
MutexHandle* getHandle() override;

Status take() override; //!< lock the mutex and get return status
Status release() override; //!< unlock the mutex and get return status

private:
// This section is used to store the implementation-defined mutex handle. To Os::Mutex and fprime, this type is
// opaque and thus normal allocation cannot be done. Instead, we allow the implementor to store the handle in
// the byte-array here and set `m_delegate` to that address for storage.
//
alignas(FW_HANDLE_ALIGNMENT) MutexHandleStorage m_handle_storage; //!< Mutex handle storage
MutexInterface& m_delegate; //!< Delegate for the real implementation
};

} // namespace Os

#endif // OS_DELEGATEMUTEX_HPP_
56 changes: 0 additions & 56 deletions Os/Mutex.cpp

This file was deleted.

128 changes: 32 additions & 96 deletions Os/Mutex.hpp
Original file line number Diff line number Diff line change
@@ -1,105 +1,41 @@
// ======================================================================
// \title Os/Mutex.hpp
// \brief common definitions for Os::Mutex
// \brief public Os::Mutex interface and alias
Comment thread
LeStarch marked this conversation as resolved.
//
// This header aggregates all definitions needed to use Os::Mutex:
// the interface, the configured alias, and the concrete delegate type.
//
// The includes below must appear in the order given: each depends on names
// defined by the one before it, so reordering them will fail to compile.
// The ordering constraints are:
//
// 1. config/OsDelegateMutex.hpp (CFG) defines the Os::Mutex type alias by
// forward-declaring a link-time delegate (e.g. DelegateMutex) or directly
// aliasing a concrete implementation (e.g. Va416x0Os::AtomicMutex::AtomicMutex).
// Must not include Os OSAL headers (they aren't yet defined).
// Should only be included in Os/MutexInterface.hpp.
//
// 2. Os/MutexInterface.hpp (IF) includes CFG first, then defines
// MutexHandle, MutexInterface, and ScopeLock.
//
// 3. OS_MUTEX_HEADER (IMPL) is defined by CFG and points to the concrete
// implementation header. If using delegation, this points to
// Os/DelegateMutex.hpp. If using compile-time selection, it points
// directly to a platform-specific implementation (e.g. AtomicMutex.hpp).
//
// MutexInterface.hpp must precede OS_MUTEX_HEADER here,
// and CFG must never include either of them (that would form a cycle).
// ======================================================================
#ifndef Os_Mutex_hpp
#define Os_Mutex_hpp

#include <Fw/FPrimeBasicTypes.hpp>
#include <Os/Os.hpp>
#include "Os/MutexInterface.hpp"
Comment thread
LeStarch marked this conversation as resolved.

namespace Os {

struct MutexHandle {};

class MutexInterface {
public:
enum Status {
OP_OK, //!< Operation was successful
ERROR_BUSY, //!< Mutex is busy
ERROR_DEADLOCK, //!< Deadlock condition detected
NOT_SUPPORTED, //!< Mutex does not support operation
ERROR_OTHER //!< All other errors
};

//! \brief default constructor
MutexInterface() = default;

//! \brief default virtual destructor
virtual ~MutexInterface() = default;

//! \brief copy constructor is forbidden
MutexInterface(const MutexInterface& other) = delete;

//! \brief copy constructor is forbidden
MutexInterface(const MutexInterface* other) = delete;

//! \brief assignment operator is forbidden
MutexInterface& operator=(const MutexInterface& other) = delete;

//! \brief return the underlying mutex handle (implementation specific)
//! \return internal mutex handle representation
virtual MutexHandle* getHandle() = 0;

//! \brief provide a pointer to a Mutex delegate object
static MutexInterface* getDelegate(MutexHandleStorage& aligned_new_memory);

virtual Status take() = 0; //!< lock the mutex return status
virtual Status release() = 0; //!< unlock the mutex return status
};

class Mutex final : public MutexInterface {
public:
Mutex(); //!< Constructor. Mutex is unlocked when created
~Mutex() final; //!< Destructor

//! \brief return the underlying mutex handle (implementation specific)
//! \return internal mutex handle representation
MutexHandle* getHandle() override;

Status take() override; //!< lock the mutex and get return status
Status release() override; //!< unlock the mutex and get return status
void lock(); //!< lock the mutex and assert success
void unLock(); //!< unlock the mutex and assert success
void unlock() { this->unLock(); } //!< alias for unLock to meet BasicLockable requirements

private:
// This section is used to store the implementation-defined mutex handle. To Os::Mutex and fprime, this type is
// opaque and thus normal allocation cannot be done. Instead, we allow the implementor to store then handle in
// the byte-array here and set `handle` to that address for storage.
//
alignas(FW_HANDLE_ALIGNMENT) MutexHandleStorage m_handle_storage; //!< Mutex handle storage
MutexInterface& m_delegate; //!< Delegate for the real implementation
};
//! \brief locks a mutex within the current scope
//!
//! The scope lock will lock the associated mutex immediately and will ensure the mutex is unlock when the scope lock
//! is destroyed.
//!
//! \warning it is unadvisable to dynamically allocate ScopeLock as this violates the implied usage.
class ScopeLock {
public:
//! \brief construct the scope lock
//!
//! Will lock the supplied mutex and will unlock the mutex when this object goes out of scope.
//! \param mutex
explicit ScopeLock(Mutex& mutex);

//!\brief unlock the scoped mutex
~ScopeLock();

//! \brief copy constructor is forbidden
ScopeLock(const ScopeLock& other) = delete;

//! \brief copy constructor is forbidden
ScopeLock(const ScopeLock* other) = delete;

//! \brief assignment operator is forbidden
ScopeLock& operator=(const ScopeLock& other) = delete;
// Validate that OS_MUTEX_HEADER was defined by config/OsDelegateMutex.hpp
#ifndef OS_MUTEX_HEADER
#error "OS_MUTEX_HEADER must be defined in config/OsDelegateMutex.hpp"
#endif

private:
Mutex& m_mutex; //!< Stores the mutex reference
};
} // namespace Os
#include OS_MUTEX_HEADER

#endif
#endif // Os_Mutex_hpp
Loading