| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // ====================================================================== | ||
| 2 | // \title Os/Queue.hpp | ||
| 3 | // \brief common function definitions for Os::Queue | ||
| 4 | // ====================================================================== | ||
| 5 | #ifndef Os_Queue_hpp_ | ||
| 6 | #define Os_Queue_hpp_ | ||
| 7 | |||
| 8 | #include <Fw/FPrimeBasicTypes.hpp> | ||
| 9 | #include <Fw/Obj/ObjBase.hpp> | ||
| 10 | #include <Fw/Types/Serializable.hpp> | ||
| 11 | #include <Os/Mutex.hpp> | ||
| 12 | #include <Os/Os.hpp> | ||
| 13 | #include <Os/QueueString.hpp> | ||
| 14 | namespace Os { | ||
| 15 | // Forward declaration for registry | ||
| 16 | class QueueRegistry; | ||
| 17 | |||
| 18 | //! \brief QueueHandle parent class | ||
| 19 | class QueueHandle {}; | ||
| 20 | |||
| 21 | //! \brief base queue interface | ||
| 22 | //! | ||
| 23 | //! Queues are used internally to fprime in order to support the messaging between components. The | ||
| 24 | //! QueueInterface is used to abstract away from the standard OS-based queue, allowing F prime support | ||
| 25 | //! multiple OSes in a consistent way. | ||
| 26 | //! | ||
| 27 | class QueueInterface { | ||
| 28 | public: | ||
| 29 | //! \brief status returned from the queue send function | ||
| 30 | enum Status { | ||
| 31 | OP_OK, //!< message sent/received okay | ||
| 32 | ALREADY_CREATED, //!< creating an already created queue | ||
| 33 | EMPTY, //!< If non-blocking, all the messages have been drained. | ||
| 34 | UNINITIALIZED, //!< Queue wasn't initialized successfully | ||
| 35 | SIZE_MISMATCH, //!< attempted to send or receive with buffer too large, too small | ||
| 36 | SEND_ERROR, //!< message send error | ||
| 37 | RECEIVE_ERROR, //!< message receive error | ||
| 38 | INVALID_PRIORITY, //!< invalid priority requested | ||
| 39 | FULL, //!< Queue was full when attempting to send a message | ||
| 40 | NOT_SUPPORTED, //!< Queue feature is not supported | ||
| 41 | ALLOCATION_FAILED, //!< required memory could not be allocated | ||
| 42 | UNKNOWN_ERROR //!< Unexpected error; can't match with returns | ||
| 43 | }; | ||
| 44 | |||
| 45 | //! \brief message type | ||
| 46 | enum BlockingType { | ||
| 47 | BLOCKING, //!< Message will block until space is available | ||
| 48 | NONBLOCKING //!< Message will return with status when space is unavailable | ||
| 49 | }; | ||
| 50 | |||
| 51 | //! \brief default queue interface constructor | ||
| 52 | ✗ | QueueInterface() = default; | |
| 53 | |||
| 54 | //! \brief default queue destructor | ||
| 55 | ✗ | virtual ~QueueInterface() = default; | |
| 56 | |||
| 57 | //! \brief copy constructor is forbidden | ||
| 58 | QueueInterface(const QueueInterface& other) = delete; | ||
| 59 | |||
| 60 | //! \brief copy constructor is forbidden | ||
| 61 | QueueInterface(const QueueInterface* other) = delete; | ||
| 62 | |||
| 63 | //! \brief assignment operator is forbidden | ||
| 64 | virtual QueueInterface& operator=(const QueueInterface& other) = delete; // NO_CODESONAR (cpp:S3657) | ||
| 65 | |||
| 66 | //! \brief create queue storage | ||
| 67 | //! | ||
| 68 | //! Creates a queue ensuring sufficient storage to hold `depth` messages of `messageSize` size each. Resource | ||
| 69 | //! allocation is dependent on the underlying implementation and users should assume that resource allocation is | ||
| 70 | //! possible. | ||
| 71 | //! | ||
| 72 | //! \param id: identifier for the queue, used for memory allocation | ||
| 73 | //! \param name: name of queue | ||
| 74 | //! \param depth: depth of queue in number of messages | ||
| 75 | //! \param messageSize: size of an individual message | ||
| 76 | //! \return: status of the creation | ||
| 77 | virtual Status create(FwEnumStoreType id, | ||
| 78 | const Fw::ConstStringBase& name, | ||
| 79 | FwSizeType depth, | ||
| 80 | FwSizeType messageSize) = 0; | ||
| 81 | |||
| 82 | //! \brief teardown the queue | ||
| 83 | //! | ||
| 84 | //! Allow for queues to deallocate resources as part of system shutdown. This delegates to the underlying queue | ||
| 85 | //! implementation. | ||
| 86 | virtual void teardown() = 0; | ||
| 87 | |||
| 88 | //! \brief send a message into the queue | ||
| 89 | //! | ||
| 90 | //! Send a message into the queue, providing the message data, size, priority, and blocking type. When | ||
| 91 | //! `blockType` is set to BLOCKING, this call will block on queue full. Otherwise, this will return an error | ||
| 92 | //! status on queue full. | ||
| 93 | //! | ||
| 94 | //! It is invalid to send a null buffer. | ||
| 95 | //! This method will block if the queue is full and blockType is set to BLOCKING | ||
| 96 | //! | ||
| 97 | //! \param buffer: message data | ||
| 98 | //! \param size: size of message data | ||
| 99 | //! \param priority: priority of the message | ||
| 100 | //! \param blockType: BLOCKING to block for space or NONBLOCKING to return error when queue is full | ||
| 101 | //! \return: status of the send | ||
| 102 | virtual Status send(const U8* buffer, FwSizeType size, FwQueuePriorityType priority, BlockingType blockType) = 0; | ||
| 103 | |||
| 104 | //! \brief receive a message from the queue | ||
| 105 | //! | ||
| 106 | //! Receive a message from the queue, providing the message destination, capacity, priority, and blocking type. | ||
| 107 | //! When `blockType` is set to BLOCKING, this call will block on queue empty. Otherwise, this will return an | ||
| 108 | //! error status on queue empty. Actual size received and priority of message is set on success status. | ||
| 109 | //! | ||
| 110 | //! It is invalid to send a null buffer. | ||
| 111 | //! This method will block if the queue is empty and blockType is set to BLOCKING | ||
| 112 | //! | ||
| 113 | //! \param destination: destination for message data | ||
| 114 | //! \param capacity: maximum size of message data | ||
| 115 | //! \param blockType: BLOCKING to wait for message or NONBLOCKING to return error when queue is empty | ||
| 116 | //! \param actualSize: (output) actual size of message read | ||
| 117 | //! \param priority: (output) priority of message read | ||
| 118 | //! \return: status of the send | ||
| 119 | virtual Status receive(U8* destination, | ||
| 120 | FwSizeType capacity, | ||
| 121 | BlockingType blockType, | ||
| 122 | FwSizeType& actualSize, | ||
| 123 | FwQueuePriorityType& priority) = 0; | ||
| 124 | |||
| 125 | //! \brief get number of messages available | ||
| 126 | //! | ||
| 127 | //! Returns the number of messages currently available in the queue. | ||
| 128 | //! | ||
| 129 | //! \return number of messages available | ||
| 130 | virtual FwSizeType getMessagesAvailable() const = 0; | ||
| 131 | |||
| 132 | //! \brief get maximum messages stored at any given time | ||
| 133 | //! | ||
| 134 | //! Returns the maximum number of messages in this queue at any given time. This is the high-water mark for this | ||
| 135 | //! queue. | ||
| 136 | //! \return queue message high-water mark | ||
| 137 | virtual FwSizeType getMessageHighWaterMark() const = 0; | ||
| 138 | |||
| 139 | //! \brief return the underlying queue handle (implementation specific) | ||
| 140 | //! \return internal task handle representation | ||
| 141 | virtual QueueHandle* getHandle() = 0; | ||
| 142 | |||
| 143 | //! \brief provide a pointer to a queue delegate object | ||
| 144 | //! | ||
| 145 | //! This function must return a pointer to a `QueueInterface` object that contains the real implementation of the | ||
| 146 | //! queue functions as defined by the implementor. This function must do several things to be considered correctly | ||
| 147 | //! implemented: | ||
| 148 | //! | ||
| 149 | //! 1. Assert that the supplied memory is non-null. e.g `FW_ASSERT(aligned_placement_new_memory != NULL);` | ||
| 150 | //! 2. Assert that their implementation fits within FW_HANDLE_MAX_SIZE. | ||
| 151 | //! e.g. `static_assert(sizeof(PosixQueueImplementation) <= sizeof Os::Queue::m_handle_storage, | ||
| 152 | //! "FW_HANDLE_MAX_SIZE to small");` | ||
| 153 | //! 3. Assert that their implementation aligns within FW_HANDLE_ALIGNMENT. | ||
| 154 | //! e.g. `static_assert((FW_HANDLE_ALIGNMENT % alignof(PosixQueueImplementation)) == 0, "Bad handle alignment");` | ||
| 155 | //! 4. Placement new their implementation into `aligned_placement_new_memory` | ||
| 156 | //! e.g. `TaskInterface* interface = new (aligned_placement_new_memory) PosixQueueImplementation;` | ||
| 157 | //! 5. Return the result of the placement new | ||
| 158 | //! e.g. `return interface;` | ||
| 159 | //! | ||
| 160 | //! \return result of placement new, must be equivalent to `aligned_placement_new_memory` | ||
| 161 | //! | ||
| 162 | static QueueInterface* getDelegate(QueueHandleStorage& aligned_placement_new_memory); | ||
| 163 | }; | ||
| 164 | |||
| 165 | class Queue final : public QueueInterface { | ||
| 166 | public: | ||
| 167 | //! \brief queue constructor | ||
| 168 | Queue(); | ||
| 169 | |||
| 170 | //! \brief default queue destructor | ||
| 171 | virtual ~Queue(); | ||
| 172 | |||
| 173 | //! \brief copy constructor is forbidden | ||
| 174 | Queue(const Queue& other) = delete; | ||
| 175 | |||
| 176 | //! \brief copy constructor is forbidden | ||
| 177 | Queue(const Queue* other) = delete; | ||
| 178 | |||
| 179 | //! \brief assignment operator is forbidden | ||
| 180 | QueueInterface& operator=(const QueueInterface& other) override = delete; | ||
| 181 | |||
| 182 | //! \brief create queue storage through delegate | ||
| 183 | //! | ||
| 184 | //! Creates a queue ensuring sufficient storage to hold `depth` messages of `messageSize` size each. This method | ||
| 185 | //! delegates to the underlying implementation. Resource allocation is dependent on the underlying implementation | ||
| 186 | //! and users should assume that resource allocation is possible. | ||
| 187 | //! | ||
| 188 | //! \param name: name of queue | ||
| 189 | //! \param depth: depth of queue in number of messages | ||
| 190 | //! \param messageSize: size of an individual message | ||
| 191 | //! \return: status of the creation | ||
| 192 | Status create(FwEnumStoreType id, | ||
| 193 | const Fw::ConstStringBase& name, | ||
| 194 | FwSizeType depth, | ||
| 195 | FwSizeType messageSize) override; | ||
| 196 | |||
| 197 | //! \brief teardown the queue | ||
| 198 | //! | ||
| 199 | //! Allow for queues to deallocate resources as part of system shutdown. This delegates to the underlying queue | ||
| 200 | //! implementation. | ||
| 201 | //! implementation. | ||
| 202 | void teardown() override; | ||
| 203 | |||
| 204 | //! \brief send a message into the queue through delegate | ||
| 205 | //! | ||
| 206 | //! Send a message into the queue, providing the message data, size, priority, and blocking type. When | ||
| 207 | //! `blockType` is set to BLOCKING, this call will block on queue full. Otherwise, this will return an error | ||
| 208 | //! status on queue full. This method delegates to the underlying implementation. | ||
| 209 | //! | ||
| 210 | //! \warning It is invalid to send a null buffer | ||
| 211 | //! \warning This method will block if the queue is full and blockType is set to BLOCKING | ||
| 212 | //! | ||
| 213 | //! \param buffer: message data | ||
| 214 | //! \param size: size of message data | ||
| 215 | //! \param priority: priority of the message | ||
| 216 | //! \param blockType: BLOCKING to block for space or NONBLOCKING to return error when queue is full | ||
| 217 | //! \return: status of the send | ||
| 218 | Status send(const U8* buffer, FwSizeType size, FwQueuePriorityType priority, BlockingType blockType) override; | ||
| 219 | |||
| 220 | //! \brief receive a message from the queue through delegate | ||
| 221 | //! | ||
| 222 | //! Receive a message from the queue, providing the message destination, capacity, priority, and blocking type. | ||
| 223 | //! When `blockType` is set to BLOCKING, this call will block on queue empty. Otherwise, this will return an | ||
| 224 | //! error status on queue empty. Actual size received and priority of message is set on success status. This method | ||
| 225 | //! delegates to the underlying implementation. | ||
| 226 | //! | ||
| 227 | //! \warning It is invalid to send a null buffer. | ||
| 228 | //! \warning This method will block if the queue is empty and blockType is set to BLOCKING | ||
| 229 | //! | ||
| 230 | //! \param destination: destination for message data | ||
| 231 | //! \param capacity: maximum size of message data | ||
| 232 | //! \param blockType: BLOCKING to wait for message or NONBLOCKING to return error when queue is empty | ||
| 233 | //! \param actualSize: (output) actual size of message read | ||
| 234 | //! \param priority: (output) priority of message read | ||
| 235 | //! \return: status of the send | ||
| 236 | Status receive(U8* destination, | ||
| 237 | FwSizeType capacity, | ||
| 238 | BlockingType blockType, | ||
| 239 | FwSizeType& actualSize, | ||
| 240 | FwQueuePriorityType& priority) override; | ||
| 241 | |||
| 242 | //! \brief get number of messages available | ||
| 243 | //! | ||
| 244 | //! Returns the number of messages currently available in the queue. This method delegates to the underlying | ||
| 245 | //! implementation. | ||
| 246 | //! | ||
| 247 | //! \return number of messages available | ||
| 248 | FwSizeType getMessagesAvailable() const override; | ||
| 249 | |||
| 250 | //! \brief get maximum messages stored at any given time through delegate | ||
| 251 | //! | ||
| 252 | //! Returns the maximum number of messages in this queue at any given time. This is the high-water mark for | ||
| 253 | //! this queue. | ||
| 254 | //! \return queue message high-water mark | ||
| 255 | FwSizeType getMessageHighWaterMark() const override; | ||
| 256 | |||
| 257 | //! \brief return the underlying queue handle (implementation specific). Delegates to implementation. | ||
| 258 | //! \return internal task handle representation | ||
| 259 | QueueHandle* getHandle() override; | ||
| 260 | |||
| 261 | //! \brief send a message to a queue | ||
| 262 | //! | ||
| 263 | //! Send a message to a queue with the given priority and block type. See: QueueInterface::send | ||
| 264 | //! | ||
| 265 | //! \warning This method will block if the queue is full and blockType is set to BLOCKING | ||
| 266 | //! | ||
| 267 | //! \param message: reference to serialize buffer storing message | ||
| 268 | //! \param priority: priority of the message | ||
| 269 | //! \param blockType: BLOCKING to block for space or NONBLOCKING to return error when queue is full | ||
| 270 | //! \return status of the send | ||
| 271 | Status send(const Fw::LinearBufferBase& message, FwQueuePriorityType priority, BlockingType blockType); | ||
| 272 | |||
| 273 | //! \brief receive a message from a queue | ||
| 274 | //! | ||
| 275 | //! Receive a message from a queue with the given block type. See: QueueInterface::receive. Note: this will entirely | ||
| 276 | //! overwrite the buffer. | ||
| 277 | //! | ||
| 278 | //! \warning This method will block if the queue is full and blockType is set to BLOCKING | ||
| 279 | //! | ||
| 280 | //! \param destination: reference to serialize buffer for storing message | ||
| 281 | //! \param priority: (output) priority of the message | ||
| 282 | //! \param blockType: BLOCKING to block for space or NONBLOCKING to return error when queue is full | ||
| 283 | //! \return status of the send | ||
| 284 | Status receive(Fw::LinearBufferBase& destination, BlockingType blockType, FwQueuePriorityType& priority); | ||
| 285 | |||
| 286 | //! \brief get the queue's depth in messages | ||
| 287 | FwSizeType getDepth() const; | ||
| 288 | |||
| 289 | //! \brief get the queue's message maximum size | ||
| 290 | FwSizeType getMessageSize() const; | ||
| 291 | |||
| 292 | //! \brief get the queue's name | ||
| 293 | const QueueString& getName() const; | ||
| 294 | |||
| 295 | //! \brief get number of queues system-wide | ||
| 296 | static FwSizeType getNumQueues(); | ||
| 297 | |||
| 298 | //! \brief get static mutex | ||
| 299 | static Os::Mutex& getStaticMutex(); | ||
| 300 | |||
| 301 | private: | ||
| 302 | QueueString m_name; //!< queue name | ||
| 303 | FwSizeType m_depth; //!< Queue depth | ||
| 304 | FwSizeType m_size; //!< Maximum message size | ||
| 305 | static Os::Mutex s_countLock; //!< Lock the count | ||
| 306 | static FwSizeType s_queueCount; //!< Count of the number of queues | ||
| 307 | |||
| 308 | #if FW_QUEUE_REGISTRATION | ||
| 309 | public: | ||
| 310 | //! \brief set QueueRegistry for tracking queues | ||
| 311 | //! | ||
| 312 | //! \param registry: registry to set | ||
| 313 | static void setRegistry(QueueRegistry* registry); | ||
| 314 | |||
| 315 | private: | ||
| 316 | static QueueRegistry* s_queueRegistry; //!< Queue registry store | ||
| 317 | #endif | ||
| 318 | |||
| 319 | // This section is used to store the implementation-defined file handle. To Os::File and fprime, this type is | ||
| 320 | // opaque and thus normal allocation cannot be done. Instead, we allow the implementor to store then handle in | ||
| 321 | // the byte-array here and set `handle` to that address for storage. | ||
| 322 | // | ||
| 323 | alignas(FW_HANDLE_ALIGNMENT) QueueHandleStorage m_handle_storage; //!< Storage for aligned handle | ||
| 324 | QueueInterface& m_delegate; //!< Delegate for the real implementation | ||
| 325 | }; | ||
| 326 | //! \brief queue registry interface | ||
| 327 | //! | ||
| 328 | //! The QueueRegistry is used to track queues in the system. There is intended to be a single, global, queue registry | ||
| 329 | //! across the system. It is used to track queues and will receive a callback on the creation of each queue. | ||
| 330 | class QueueRegistry { | ||
| 331 | public: | ||
| 332 | //! Default QueueRegistry | ||
| 333 | ✗ | QueueRegistry() = default; | |
| 334 | //! Default ~QueueRegistry | ||
| 335 | ✗ | virtual ~QueueRegistry() = default; | |
| 336 | |||
| 337 | //! \brief queue registry callback | ||
| 338 | //! | ||
| 339 | //! Register the queue with this queue registry. Must be implemented by QueueRegistry implementations. | ||
| 340 | //! | ||
| 341 | //! \param queue: queue being registered | ||
| 342 | virtual void registerQueue(Queue* queue) = 0; //!< method called by queue init() methods to register a new queue | ||
| 343 | }; | ||
| 344 | } // namespace Os | ||
| 345 | #endif | ||
| 346 |