| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // ====================================================================== | ||
| 2 | // \title Os/ConditionVariableInterface.hpp | ||
| 3 | // \brief Os::ConditionVariableHandle and Os::ConditionVariableInterface definitions | ||
| 4 | // ====================================================================== | ||
| 5 | #ifndef OS_CONDITIONVARIABLEINTERFACE_HPP_ | ||
| 6 | #define OS_CONDITIONVARIABLEINTERFACE_HPP_ | ||
| 7 | |||
| 8 | #include <type_traits> | ||
| 9 | |||
| 10 | #include "Fw/Types/Assert.hpp" | ||
| 11 | #include "Os/Mutex.hpp" | ||
| 12 | #include "Os/Os.hpp" | ||
| 13 | #include "config/OsSelection.hpp" // defines Os::ConditionVariable alias and OS_CONDITION_VARIABLE_HEADER consumed by Os/Condition.hpp; do not remove | ||
| 14 | |||
| 15 | namespace Os { | ||
| 16 | |||
| 17 | class DelegateMutex; | ||
| 18 | class DelegateConditionVariable; | ||
| 19 | |||
| 20 | // A condition variable implementation operates on the handle of the configured Os::Mutex. Selecting a | ||
| 21 | // compile-time Mutex while leaving Os::ConditionVariable on the link-time delegate (or vice versa) hands the | ||
| 22 | // CMake-chosen implementation a handle of the wrong type, so both must be delegates or neither may be. | ||
| 23 | static_assert(std::is_same<Os::Mutex, Os::DelegateMutex>::value == | ||
| 24 | std::is_same<Os::ConditionVariable, Os::DelegateConditionVariable>::value, | ||
| 25 | "Os::Mutex and Os::ConditionVariable must be overridden together in config/OsSelection.hpp"); | ||
| 26 | |||
| 27 | //! \brief Condition variable handle parent | ||
| 28 | class ConditionVariableHandle {}; | ||
| 29 | |||
| 30 | //! \brief interface for condition variables | ||
| 31 | //! | ||
| 32 | //! Condition variables allow a program to block on a condition while atomically releasing an Os::Mutex and atomically | ||
| 33 | //! reacquiring the mutex once the condition has been notified. | ||
| 34 | class ConditionVariableInterface { | ||
| 35 | public: | ||
| 36 | enum Status { | ||
| 37 | OP_OK, //!< Operation was successful | ||
| 38 | ERROR_MUTEX_NOT_HELD, //!< When trying to wait but we don't hold the mutex | ||
| 39 | ERROR_DIFFERENT_MUTEX, //!< When trying to use a different mutex than expected mutex | ||
| 40 | ERROR_NOT_IMPLEMENTED, //!< When trying to use a feature that isn't implemented | ||
| 41 | NOT_SUPPORTED, //!< ConditionVariable does not support operation | ||
| 42 | ERROR_OTHER //!< All other errors | ||
| 43 | }; | ||
| 44 | |||
| 45 | //! Default constructor | ||
| 46 | 7330 | ConditionVariableInterface() = default; | |
| 47 | //! Default destructor | ||
| 48 | 14660 | virtual ~ConditionVariableInterface() = default; | |
| 49 | |||
| 50 | //! \brief copy constructor is forbidden | ||
| 51 | ConditionVariableInterface(const ConditionVariableInterface& other) = delete; | ||
| 52 | |||
| 53 | //! \brief assignment operator is forbidden | ||
| 54 | virtual ConditionVariableInterface& operator=(const ConditionVariableInterface& other) = delete; | ||
| 55 | |||
| 56 | //! \brief wait on a condition variable | ||
| 57 | //! | ||
| 58 | //! Wait on a condition variable. This function will atomically unlock the provided mutex and block on the condition | ||
| 59 | //! in one step. Blocking will occur until a future `notify` or `notifyAll` call is made to this variable on another | ||
| 60 | //! thread of execution. | ||
| 61 | //! | ||
| 62 | //! \param mutex: mutex to unlock as part of this operation | ||
| 63 | //! \return status of the conditional wait | ||
| 64 | virtual Status pend(Os::Mutex& mutex) = 0; | ||
| 65 | |||
| 66 | //! \brief notify a single waiter on this condition variable | ||
| 67 | //! | ||
| 68 | //! Notify a single waiter on this condition variable. It is not necessary to hold the mutex supplied by the waiters | ||
| 69 | //! and it is advantageous not to hold the lock to prevent immediate re-blocking. | ||
| 70 | virtual void notify() = 0; | ||
| 71 | |||
| 72 | //! \brief notify all waiters on this condition variable | ||
| 73 | //! | ||
| 74 | //! Notify all waiters on this condition variable. It is not necessary to hold the mutex supplied by the waiters | ||
| 75 | //! and it is advantageous not to hold the lock to prevent immediate re-blocking. | ||
| 76 | virtual void notifyAll() = 0; | ||
| 77 | |||
| 78 | //! \brief return the underlying condition variable handle (implementation specific). | ||
| 79 | //! \return internal task handle representation | ||
| 80 | virtual ConditionVariableHandle* getHandle() = 0; | ||
| 81 | |||
| 82 | //! \brief provide a pointer to a ConditionVariable delegate object | ||
| 83 | //! | ||
| 84 | //! \note ERROR_DIFFERENT_MUTEX is reported by the link-time Os::DelegateConditionVariable, which records the mutex | ||
| 85 | //! first supplied to pend(); an implementation selected directly as Os::ConditionVariable does not perform that | ||
| 86 | //! check. | ||
| 87 | static ConditionVariableInterface* getDelegate(ConditionVariableHandleStorage& aligned_new_memory); | ||
| 88 | |||
| 89 | // ------------------------------------------------------------------ | ||
| 90 | // Common (non-virtual) functions built on top of pend(). Defined inline | ||
| 91 | // on the interface so they are available regardless of which | ||
| 92 | // implementation Os::ConditionVariable is configured to be. | ||
| 93 | // ------------------------------------------------------------------ | ||
| 94 | |||
| 95 | //! \brief wait on a condition variable and assert success | ||
| 96 | //! | ||
| 97 | //! Wait on a condition variable. This function will atomically unlock the provided mutex and block on the condition | ||
| 98 | //! in one step. Blocking will occur until a future `notify` or `notifyAll` call is made to this variable on another | ||
| 99 | //! thread of execution. | ||
| 100 | //! | ||
| 101 | //! \warning it is invalid to supply a mutex different from those supplied by others | ||
| 102 | //! \warning conditions *must* be rechecked after the condition variable unlocks | ||
| 103 | //! \warning the mutex must be locked by the calling task | ||
| 104 | //! | ||
| 105 | //! \param mutex: mutex to unlock as part of this operation | ||
| 106 | 11 | void wait(Os::Mutex& mutex) { | |
| 107 | 11 | const Status status = this->pend(mutex); | |
| 108 | 11 | FW_ASSERT(status == Status::OP_OK, | |
| 109 | static_cast<FwAssertArgType>(reinterpret_cast<PlatformPointerCastType>(this)), status); | ||
| 110 | 11 | } | |
| 111 | }; | ||
| 112 | |||
| 113 | } // namespace Os | ||
| 114 | |||
| 115 | #endif // OS_CONDITIONVARIABLEINTERFACE_HPP_ | ||
| 116 |