mirror of
https://github.com/nasa/fprime.git
synced 2025-12-10 00:44:37 -06:00
* adding not-supported status because sometimes it's useful to report not supported * updating shadow enums to match actual enum
151 lines
6.9 KiB
C++
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_
|