fprime/Os/Condition.hpp
kevin-f-ortega a7f9bc7460
Add NOT_SUPPORTED to OS' statues (#3281)
* adding not-supported status because sometimes it's useful to report not supported

* updating shadow enums to match actual enum
2025-02-26 15:42:40 -08:00

151 lines
6.9 KiB
C++

// ======================================================================
// \title Os/Condition.hpp
// \brief common function definitions for Os::ConditionVariables
// ======================================================================
#include "Os/Mutex.hpp"
#include "Os/Os.hpp"
#ifndef OS_CONDITION_HPP_
#define OS_CONDITION_HPP_
namespace Os {
//! \brief Condition variable handle parent
class ConditionVariableHandle {};
//! \brief interface for condition variables
//!
//! Condition variables allow a program to block on a condition while atomically releasing an Os::Mutex and atomically
//! reacquiring the mutex once the condition has been notified.
class ConditionVariableInterface {
public:
enum Status {
OP_OK, //!< Operation was successful
ERROR_MUTEX_NOT_HELD, //!< When trying to wait but we don't hold the mutex
ERROR_DIFFERENT_MUTEX, //!< When trying to use a different mutex than expected mutex
ERROR_NOT_IMPLEMENTED, //!< When trying to use a feature that isn't implemented
NOT_SUPPORTED, //!< ConditionVariable does not support operation
ERROR_OTHER //!< All other errors
};
//! Default constructor
ConditionVariableInterface() = default;
//! Default destructor
virtual ~ConditionVariableInterface() = default;
//! \brief copy constructor is forbidden
ConditionVariableInterface(const ConditionVariableInterface& other) = delete;
//! \brief assignment operator is forbidden
virtual ConditionVariableInterface& operator=(const ConditionVariableInterface& other) = delete;
//! \brief wait on a condition variable
//!
//! Wait on a condition variable. This function will atomically unlock the provided mutex and block on the condition
//! in one step. Blocking will occur until a future `notify` or `notifyAll` call is made to this variable on another
//! thread of execution.
//!
//! \param mutex: mutex to unlock as part of this operation
//! \return status of the conditional wait
virtual Status pend(Os::Mutex& mutex) = 0;
//! \brief notify a single waiter on this condition variable
//!
//! Notify a single waiter on this condition variable. It is not necessary to hold the mutex supplied by the waiters
//! and it is advantageous not to hold the lock to prevent immediate re-blocking.
virtual void notify() = 0;
//! \brief notify all waiters on this condition variable
//!
//! Notify all waiters on this condition variable. It is not necessary to hold the mutex supplied by the waiters
//! and it is advantageous not to hold the lock to prevent immediate re-blocking.
virtual void notifyAll() = 0;
//! \brief return the underlying condition variable handle (implementation specific).
//! \return internal task handle representation
virtual ConditionVariableHandle* getHandle() = 0;
//! \brief provide a pointer to a Mutex delegate object
static ConditionVariableInterface* getDelegate(ConditionVariableHandleStorage& aligned_new_memory);
};
//! \brief condition variable implementation
//!
//! Condition variables allow a program to block on a condition while atomically releasing an Os::Mutex and atomically
//! reacquiring the mutex once the condition has been notified.
class ConditionVariable final : public ConditionVariableInterface {
public:
//! \brief default constructor
ConditionVariable();
//! \brief default virtual destructor
~ConditionVariable() final;
//! \brief copy constructor is forbidden
ConditionVariable(const ConditionVariableInterface& other) = delete;
//! \brief copy constructor is forbidden
ConditionVariable(const ConditionVariableInterface* other) = delete;
//! \brief assignment operator is forbidden
ConditionVariableInterface& operator=(const ConditionVariableInterface& other) override = delete;
//! \brief wait on a condition variable
//!
//! Wait on a condition variable. This function will atomically unlock the provided mutex and block on the condition
//! in one step. Blocking will occur until a future `notify` or `notifyAll` call is made to this variable on another
//! thread of execution. This function delegates to the underlying implementation.
//!
//! \warning it is invalid to supply a mutex different from those supplied by others
//! \warning conditions *must* be rechecked after the condition variable unlocks
//! \warning the mutex must be locked by the calling task
//!
//! \param mutex: mutex to unlock as part of this operation
//! \return status of the conditional wait
Status pend(Os::Mutex& mutex) override;
//! \brief wait on a condition variable
//!
//! Wait on a condition variable. This function will atomically unlock the provided mutex and block on the condition
//! in one step. Blocking will occur until a future `notify` or `notifyAll` call is made to this variable on another
//! thread of execution. This function delegates to the underlying implementation.
//!
//! \warning it is invalid to supply a mutex different from those supplied by others
//! \warning conditions *must* be rechecked after the condition variable unlocks
//! \warning the mutex must be locked by the calling task
//!
//! \param mutex: mutex to unlock as part of this operation
void wait(Os::Mutex& mutex);
//! \brief notify a single waiter on this condition variable
//!
//! Notify a single waiter on this condition variable. It is not necessary to hold the mutex supplied by the waiters
//! and it is advantageous not to hold the lock to prevent immediate re-blocking. This function delegates to the
//! underlying implementation.
void notify() override;
//! \brief notify all waiters on this condition variable
//!
//! Notify all waiters on this condition variable. It is not necessary to hold the mutex supplied by the waiters
//! and it is advantageous not to hold the lock to prevent immediate re-blocking. This function delegates to the
//! underlying implementation.
void notifyAll() override;
//! \brief return the underlying condition variable handle (implementation specific). Delegates to implementation.
//! \return internal task handle representation
ConditionVariableHandle* getHandle() override;
private:
//! Pointer to mutex object previously used
Os::Mutex* m_lock = nullptr;
// This section is used to store the implementation-defined file handle. To Os::File 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)
ConditionVariableHandleStorage m_handle_storage; //!< Storage for aligned FileHandle data
ConditionVariableInterface& m_delegate; //!< Delegate for the real implementation
};
} // namespace Os
#endif // OS_CONDITION_HPP_