| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // ====================================================================== | ||
| 2 | // \title Os/Condition.hpp | ||
| 3 | // \brief common function definitions for Os::ConditionVariables | ||
| 4 | // ====================================================================== | ||
| 5 | #include "Os/Mutex.hpp" | ||
| 6 | #include "Os/Os.hpp" | ||
| 7 | |||
| 8 | #ifndef OS_CONDITION_HPP_ | ||
| 9 | #define OS_CONDITION_HPP_ | ||
| 10 | |||
| 11 | namespace Os { | ||
| 12 | |||
| 13 | //! \brief Condition variable handle parent | ||
| 14 | class ConditionVariableHandle {}; | ||
| 15 | |||
| 16 | //! \brief interface for condition variables | ||
| 17 | //! | ||
| 18 | //! Condition variables allow a program to block on a condition while atomically releasing an Os::Mutex and atomically | ||
| 19 | //! reacquiring the mutex once the condition has been notified. | ||
| 20 | class ConditionVariableInterface { | ||
| 21 | public: | ||
| 22 | enum Status { | ||
| 23 | OP_OK, //!< Operation was successful | ||
| 24 | ERROR_MUTEX_NOT_HELD, //!< When trying to wait but we don't hold the mutex | ||
| 25 | ERROR_DIFFERENT_MUTEX, //!< When trying to use a different mutex than expected mutex | ||
| 26 | ERROR_NOT_IMPLEMENTED, //!< When trying to use a feature that isn't implemented | ||
| 27 | NOT_SUPPORTED, //!< ConditionVariable does not support operation | ||
| 28 | ERROR_OTHER //!< All other errors | ||
| 29 | }; | ||
| 30 | |||
| 31 | //! Default constructor | ||
| 32 | 5942 | ConditionVariableInterface() = default; | |
| 33 | //! Default destructor | ||
| 34 | 11884 | virtual ~ConditionVariableInterface() = default; | |
| 35 | |||
| 36 | //! \brief copy constructor is forbidden | ||
| 37 | ConditionVariableInterface(const ConditionVariableInterface& other) = delete; | ||
| 38 | |||
| 39 | //! \brief assignment operator is forbidden | ||
| 40 | virtual ConditionVariableInterface& operator=(const ConditionVariableInterface& other) = delete; | ||
| 41 | |||
| 42 | //! \brief wait on a condition variable | ||
| 43 | //! | ||
| 44 | //! Wait on a condition variable. This function will atomically unlock the provided mutex and block on the condition | ||
| 45 | //! in one step. Blocking will occur until a future `notify` or `notifyAll` call is made to this variable on another | ||
| 46 | //! thread of execution. | ||
| 47 | //! | ||
| 48 | //! \param mutex: mutex to unlock as part of this operation | ||
| 49 | //! \return status of the conditional wait | ||
| 50 | virtual Status pend(Os::Mutex& mutex) = 0; | ||
| 51 | |||
| 52 | //! \brief notify a single waiter on this condition variable | ||
| 53 | //! | ||
| 54 | //! Notify a single waiter on this condition variable. It is not necessary to hold the mutex supplied by the waiters | ||
| 55 | //! and it is advantageous not to hold the lock to prevent immediate re-blocking. | ||
| 56 | virtual void notify() = 0; | ||
| 57 | |||
| 58 | //! \brief notify all waiters on this condition variable | ||
| 59 | //! | ||
| 60 | //! Notify all waiters on this condition variable. It is not necessary to hold the mutex supplied by the waiters | ||
| 61 | //! and it is advantageous not to hold the lock to prevent immediate re-blocking. | ||
| 62 | virtual void notifyAll() = 0; | ||
| 63 | |||
| 64 | //! \brief return the underlying condition variable handle (implementation specific). | ||
| 65 | //! \return internal task handle representation | ||
| 66 | virtual ConditionVariableHandle* getHandle() = 0; | ||
| 67 | |||
| 68 | //! \brief provide a pointer to a Mutex delegate object | ||
| 69 | static ConditionVariableInterface* getDelegate(ConditionVariableHandleStorage& aligned_new_memory); | ||
| 70 | }; | ||
| 71 | |||
| 72 | //! \brief condition variable implementation | ||
| 73 | //! | ||
| 74 | //! Condition variables allow a program to block on a condition while atomically releasing an Os::Mutex and atomically | ||
| 75 | //! reacquiring the mutex once the condition has been notified. | ||
| 76 | class ConditionVariable final : public ConditionVariableInterface { | ||
| 77 | public: | ||
| 78 | //! \brief default constructor | ||
| 79 | ConditionVariable(); | ||
| 80 | |||
| 81 | //! \brief default virtual destructor | ||
| 82 | ~ConditionVariable() final; | ||
| 83 | |||
| 84 | //! \brief copy constructor is forbidden | ||
| 85 | ConditionVariable(const ConditionVariableInterface& other) = delete; | ||
| 86 | |||
| 87 | //! \brief copy constructor is forbidden | ||
| 88 | ConditionVariable(const ConditionVariableInterface* other) = delete; | ||
| 89 | |||
| 90 | //! \brief assignment operator is forbidden | ||
| 91 | ConditionVariableInterface& operator=(const ConditionVariableInterface& other) override = delete; | ||
| 92 | |||
| 93 | //! \brief wait on a condition variable | ||
| 94 | //! | ||
| 95 | //! Wait on a condition variable. This function will atomically unlock the provided mutex and block on the condition | ||
| 96 | //! in one step. Blocking will occur until a future `notify` or `notifyAll` call is made to this variable on another | ||
| 97 | //! thread of execution. This function delegates to the underlying implementation. | ||
| 98 | //! | ||
| 99 | //! \warning it is invalid to supply a mutex different from those supplied by others | ||
| 100 | //! \warning conditions *must* be rechecked after the condition variable unlocks | ||
| 101 | //! \warning the mutex must be locked by the calling task | ||
| 102 | //! | ||
| 103 | //! \param mutex: mutex to unlock as part of this operation | ||
| 104 | //! \return status of the conditional wait | ||
| 105 | Status pend(Os::Mutex& mutex) override; | ||
| 106 | |||
| 107 | //! \brief wait on a condition variable | ||
| 108 | //! | ||
| 109 | //! Wait on a condition variable. This function will atomically unlock the provided mutex and block on the condition | ||
| 110 | //! in one step. Blocking will occur until a future `notify` or `notifyAll` call is made to this variable on another | ||
| 111 | //! thread of execution. This function delegates to the underlying implementation. | ||
| 112 | //! | ||
| 113 | //! \warning it is invalid to supply a mutex different from those supplied by others | ||
| 114 | //! \warning conditions *must* be rechecked after the condition variable unlocks | ||
| 115 | //! \warning the mutex must be locked by the calling task | ||
| 116 | //! | ||
| 117 | //! \param mutex: mutex to unlock as part of this operation | ||
| 118 | void wait(Os::Mutex& mutex); | ||
| 119 | |||
| 120 | //! \brief notify a single waiter on this condition variable | ||
| 121 | //! | ||
| 122 | //! Notify a single waiter on this condition variable. It is not necessary to hold the mutex supplied by the waiters | ||
| 123 | //! and it is advantageous not to hold the lock to prevent immediate re-blocking. This function delegates to the | ||
| 124 | //! underlying implementation. | ||
| 125 | void notify() override; | ||
| 126 | |||
| 127 | //! \brief notify all waiters on this condition variable | ||
| 128 | //! | ||
| 129 | //! Notify all waiters on this condition variable. It is not necessary to hold the mutex supplied by the waiters | ||
| 130 | //! and it is advantageous not to hold the lock to prevent immediate re-blocking. This function delegates to the | ||
| 131 | //! underlying implementation. | ||
| 132 | void notifyAll() override; | ||
| 133 | |||
| 134 | //! \brief return the underlying condition variable handle (implementation specific). Delegates to implementation. | ||
| 135 | //! \return internal task handle representation | ||
| 136 | ConditionVariableHandle* getHandle() override; | ||
| 137 | |||
| 138 | private: | ||
| 139 | //! Pointer to mutex object previously used | ||
| 140 | Os::Mutex* m_lock = nullptr; | ||
| 141 | |||
| 142 | // This section is used to store the implementation-defined file handle. To Os::File and fprime, this type is | ||
| 143 | // opaque and thus normal allocation cannot be done. Instead, we allow the implementor to store then handle in | ||
| 144 | // the byte-array here and set `handle` to that address for storage. | ||
| 145 | alignas(FW_HANDLE_ALIGNMENT) | ||
| 146 | ConditionVariableHandleStorage m_handle_storage; //!< Storage for aligned FileHandle data | ||
| 147 | ConditionVariableInterface& m_delegate; //!< Delegate for the real implementation | ||
| 148 | }; | ||
| 149 | } // namespace Os | ||
| 150 | #endif // OS_CONDITION_HPP_ | ||
| 151 |