diff --git a/Os/Generic/DefaultPriorityQueue.cpp b/Os/Generic/DefaultPriorityQueue.cpp index 449f1c51db..4092bd83e7 100644 --- a/Os/Generic/DefaultPriorityQueue.cpp +++ b/Os/Generic/DefaultPriorityQueue.cpp @@ -1,13 +1,14 @@ // ====================================================================== // \title Os/Posix/DefaultFile.cpp -// \brief sets default Os::File to posix implementation via linker +// \brief sets default Os::Queue to generic priority queue implementation via linker // ====================================================================== -#include "Os/Queue.hpp" -#include "Os/Generic/PriorityQueue.hpp" #include "Os/Delegate.hpp" +#include "Os/Generic/PriorityQueue.hpp" +#include "Os/Queue.hpp" namespace Os { QueueInterface* QueueInterface::getDelegate(QueueHandleStorage& aligned_new_memory) { - return Os::Delegate::makeDelegate(aligned_new_memory); -} + return Os::Delegate::makeDelegate( + aligned_new_memory); } +} // namespace Os diff --git a/Os/Generic/PriorityQueue.cpp b/Os/Generic/PriorityQueue.cpp index dba4233e4c..f946abf022 100644 --- a/Os/Generic/PriorityQueue.cpp +++ b/Os/Generic/PriorityQueue.cpp @@ -1,42 +1,41 @@ -// -// Created by Michael Starch on 9/17/24. -// +// ====================================================================== +// \title Os/Generic/PriorityQueue.cpp +// \brief priority queue implementation for Os::Queue +// ====================================================================== #include "PriorityQueue.hpp" #include #include -#include #include +#include namespace Os { namespace Generic { FwSizeType PriorityQueueHandle ::find_index() { + // This function is predicated on the definition of unsigned "overflow" + static_assert(not std::numeric_limits::is_signed, "FwSizeType is presumed to be unsigned"); + // This function will never be called when full, this assert ensures that the start index never surpasses the end + // index. + FW_ASSERT(this->m_startIndex != this->m_stopIndex); FwSizeType index = this->m_indices[this->m_startIndex % this->m_depth]; - //TODO: handle overflow + // Overflow allowed here, as computations handle wrap-around when assuming unsigned integers this->m_startIndex++; FwSizeType diff = this->m_stopIndex - this->m_startIndex; - FW_ASSERT( - diff <= this->m_depth, - static_cast(diff), - static_cast(this->m_depth), - static_cast(this->m_stopIndex), - static_cast(this->m_startIndex)); + FW_ASSERT(diff <= this->m_depth, static_cast(diff), static_cast(this->m_depth), + static_cast(this->m_stopIndex), static_cast(this->m_startIndex)); return index; } void PriorityQueueHandle ::return_index(FwSizeType index) { + // This function is predicated on the definition of unsigned "overflow" + static_assert(not std::numeric_limits::is_signed, "FwSizeType is presumed to be unsigned"); this->m_indices[this->m_stopIndex % this->m_depth] = index; - //TODO: handle overflow + // Overflow allowed here, as computations handle wrap-around when assuming unsigned integers this->m_stopIndex++; FwSizeType diff = this->m_stopIndex - this->m_startIndex; - FW_ASSERT( - diff <= this->m_depth, - static_cast(diff), - static_cast(this->m_depth), - static_cast(this->m_stopIndex), - static_cast(this->m_startIndex) - ); + FW_ASSERT(diff <= this->m_depth, static_cast(diff), static_cast(this->m_depth), + static_cast(this->m_stopIndex), static_cast(this->m_startIndex)); } void PriorityQueueHandle ::store_data(FwSizeType index, const U8* data, FwSizeType size) { @@ -61,26 +60,26 @@ PriorityQueue::~PriorityQueue() { delete[] this->m_handle.m_sizes; } - - QueueInterface::Status PriorityQueue::create(const Fw::StringBase& name, FwSizeType depth, FwSizeType messageSize) { - - //TODO: point this allocation to Os::Allocate implementation + // Allocate indices list FwSizeType* indices = new (std::nothrow) FwSizeType[depth]; if (indices == nullptr) { return QueueInterface::Status::UNKNOWN_ERROR; } + // Allocate sizes list or clean-up FwSizeType* sizes = new (std::nothrow) FwSizeType[depth]; if (sizes == nullptr) { delete[] indices; return QueueInterface::Status::UNKNOWN_ERROR; } + // Allocate sizes list or clean-up U8* data = new (std::nothrow) U8[depth * messageSize]; if (data == nullptr) { delete[] indices; delete[] sizes; return QueueInterface::Status::UNKNOWN_ERROR; } + // Allocate max heap or clean-up bool created = this->m_handle.m_heap.create(depth); if (not created) { delete[] indices; @@ -88,12 +87,12 @@ QueueInterface::Status PriorityQueue::create(const Fw::StringBase& name, FwSizeT delete[] data; return QueueInterface::Status::UNKNOWN_ERROR; } - // Assign initial indices + // Assign initial indices and sizes for (FwSizeType i = 0; i < depth; i++) { indices[i] = i; sizes[i] = 0; } - + // Set local tracking variables this->m_handle.m_maxSize = messageSize; this->m_handle.m_indices = indices; this->m_handle.m_data = data; @@ -101,17 +100,20 @@ QueueInterface::Status PriorityQueue::create(const Fw::StringBase& name, FwSizeT this->m_handle.m_startIndex = 0; this->m_handle.m_stopIndex = depth; this->m_handle.m_depth = depth; + this->m_handle.m_highMark = 0; return QueueInterface::Status::OP_OK; } QueueInterface::Status PriorityQueue::send(const U8* buffer, - FwSizeType size, - FwQueuePriorityType priority, - QueueInterface::BlockingType blockType) { + FwSizeType size, + FwQueuePriorityType priority, + QueueInterface::BlockingType blockType) { + // Check for sizing problem before locking if (size > this->m_handle.m_maxSize) { return QueueInterface::Status::SIZE_MISMATCH; } + // Artificial block scope for scope lock ensuring an unlock in all cases and ensuring an unlock before notify { Os::ScopeLock lock(this->m_handle.m_data_lock); if (this->m_handle.m_heap.isFull() and blockType == BlockingType::NONBLOCKING) { @@ -129,17 +131,17 @@ QueueInterface::Status PriorityQueue::send(const U8* buffer, } this->m_handle.store_data(index, buffer, size); this->m_handle.m_sizes[index] = size; - this->m_handle.m_hwm = FW_MAX(this->m_handle.m_hwm, this->getMessagesAvailable()); + this->m_handle.m_highMark = FW_MAX(this->m_handle.m_highMark, this->getMessagesAvailable()); } this->m_handle.m_empty.notify(); return QueueInterface::Status::OP_OK; } QueueInterface::Status PriorityQueue::receive(U8* destination, - FwSizeType capacity, - QueueInterface::BlockingType blockType, - FwSizeType& actualSize, - FwQueuePriorityType& priority) { + FwSizeType capacity, + QueueInterface::BlockingType blockType, + FwSizeType& actualSize, + FwQueuePriorityType& priority) { { Os::ScopeLock lock(this->m_handle.m_data_lock); if (this->m_handle.m_heap.isEmpty() and blockType == BlockingType::NONBLOCKING) { @@ -176,7 +178,9 @@ FwSizeType PriorityQueue::getMessagesAvailable() const { } FwSizeType PriorityQueue::getMessageHighWaterMark() const { - return this->m_handle.m_hwm; -} + // Safe to cast away const in this context because scope lock will restore unlocked state on return + Os::ScopeLock lock(const_cast(this->m_handle.m_data_lock)); + return this->m_handle.m_highMark; } +} // namespace Generic } // namespace Os diff --git a/Os/Generic/PriorityQueue.hpp b/Os/Generic/PriorityQueue.hpp index 6b5fd965dc..9d4c6362c8 100644 --- a/Os/Generic/PriorityQueue.hpp +++ b/Os/Generic/PriorityQueue.hpp @@ -1,43 +1,56 @@ -// -// Created by Michael Starch on 9/17/24. -// -#include "Os/Queue.hpp" -#include "Os/Mutex.hpp" +// ====================================================================== +// \title Os/Generic/PriorityQueue.hpp +// \brief priority queue implementation definitions for Os::Queue +// ====================================================================== #include "Os/Condition.hpp" #include "Os/Generic/Types/MaxHeap.hpp" +#include "Os/Mutex.hpp" +#include "Os/Queue.hpp" #ifndef OS_GENERIC_PRIORITYQUEUE_HPP #define OS_GENERIC_PRIORITYQUEUE_HPP namespace Os { namespace Generic { -struct Metadata { - -}; - +//! \brief critical data stored for priority queue +//! +//! The priority queue has two essential data structures: a block of unordered memory storing message data and size. The +//! queue also stores a circular list of indices into that memory tracking which slots are free and which are taken. +//! These indices are ordered by a max heap data structure projecting priority on to the otherwise unordered data. Both +//! the data region and index list have queue depth number of entries. struct PriorityQueueHandle : public QueueHandle { - Types::MaxHeap m_heap; - U8* m_data = nullptr; - FwSizeType* m_indices = nullptr; - FwSizeType* m_sizes = nullptr; - FwSizeType m_depth = 0; - FwSizeType m_startIndex = 0; - FwSizeType m_stopIndex = 0; - FwSizeType m_maxSize = 0; - FwSizeType m_hwm = 0; - Os::Mutex m_data_lock; - Os::ConditionVariable m_full; - Os::ConditionVariable m_empty; - + Types::MaxHeap m_heap; //!< MaxHeap data store for tracking priority + U8* m_data = nullptr; //!< Pointer to data allocation + FwSizeType* m_indices = nullptr; //!< List of indices into data + FwSizeType* m_sizes = nullptr; //!< Size store for each method + FwSizeType m_depth = 0; //!< Depth of the queue + FwSizeType m_startIndex = 0; //!< Start index of the circular data structure + FwSizeType m_stopIndex = 0; //!< End index of the circular data structure + FwSizeType m_maxSize = 0; //!< Maximum size allowed of a message + FwSizeType m_highMark = 0; //!< Message count high water mark + Os::Mutex m_data_lock; //!< Lock against data manipulation + Os::ConditionVariable m_full; //!< Queue full condition variable to support blocking + Os::ConditionVariable m_empty; //!< Queue empty condition variable to support blocking + + //!\brief find an available index to store data from the list FwSizeType find_index(); + //!\brief return index to the circular data structure + //!\param index: index to return to the list void return_index(FwSizeType index); + //!\brief store data into a set index in the data store void store_data(FwSizeType index, const U8* source, FwSizeType size); + //!\brief load data from a set index in the data store void load_data(FwSizeType index, U8* destination, FwSizeType capacity); }; - +//! \brief generic priority queue implementation +//! +//! A generic implementation of a priority queue to support the Os::QueueInterface. This queue uses OSAL mutexes, +//! and condition variables to provide for a task-safe blocking queue implementation. Data is stored in heap memory. +//! +//! \warning allocates memory on the heap class PriorityQueue : public Os::QueueInterface { public: //! \brief default queue interface constructor @@ -58,10 +71,13 @@ class PriorityQueue : public Os::QueueInterface { //! \brief create queue storage //! //! Creates a queue ensuring sufficient storage to hold `depth` messages of `messageSize` size each. + //! + //! \warning allocates memory on the heap + //! //! \param name: name of queue //! \param depth: depth of queue in number of messages //! \param messageSize: size of an individual message - //! \return: stauts of the creation + //! \return: status of the creation Status create(const Fw::StringBase& name, FwSizeType depth, FwSizeType messageSize) override; //! \brief send a message into the queue @@ -70,6 +86,9 @@ class PriorityQueue : public Os::QueueInterface { //! `blockType` is set to BLOCKING, this call will block on queue full. Otherwise, this will return an error //! status on queue full. //! + //! \warning It is invalid to send a null buffer + //! \warning This method will block if the queue is full and blockType is set to BLOCKING + //! //! \param buffer: message data //! \param size: size of message data //! \param priority: priority of the message @@ -83,6 +102,9 @@ class PriorityQueue : public Os::QueueInterface { //! When `blockType` is set to BLOCKING, this call will block on queue empty. Otherwise, this will return an //! error status on queue empty. Actual size received and priority of message is set on success status. //! + //! \warning It is invalid to send a null buffer + //! \warning This method will block if the queue is full and blockType is set to BLOCKING + //! //! \param destination: destination for message data //! \param capacity: maximum size of message data //! \param blockType: BLOCKING to wait for message or NONBLOCKING to return error when queue is empty diff --git a/Os/Generic/Types/MaxHeap.cpp b/Os/Generic/Types/MaxHeap.cpp index 7db099aec8..50f89403f8 100644 --- a/Os/Generic/Types/MaxHeap.cpp +++ b/Os/Generic/Types/MaxHeap.cpp @@ -16,11 +16,11 @@ #include "Os/Generic/Types/MaxHeap.hpp" #include -#include "Fw/Types/Assert.hpp" #include +#include "Fw/Types/Assert.hpp" -#include #include +#include // Macros for traversing the heap: #define LCHILD(x) (2 * x + 1) @@ -29,54 +29,53 @@ namespace Types { - MaxHeap::MaxHeap() { - // Initialize the heap: - this->m_capacity = 0; - this->m_heap = nullptr; - this->m_size = 0; - this->m_order = 0; - } +MaxHeap::MaxHeap() { + // Initialize the heap: + this->m_capacity = 0; + this->m_heap = nullptr; + this->m_size = 0; + this->m_order = 0; +} - MaxHeap::~MaxHeap() { - delete [] this->m_heap; - this->m_heap = nullptr; - } +MaxHeap::~MaxHeap() { + delete[] this->m_heap; + this->m_heap = nullptr; +} - bool MaxHeap::create(FwSizeType capacity) - { - // The heap has already been created.. so delete - // it and try again. - if( nullptr != this->m_heap ) { - delete [] this->m_heap; +bool MaxHeap::create(FwSizeType capacity) { + // The heap has already been created.. so delete + // it and try again. + if (nullptr != this->m_heap) { + delete[] this->m_heap; this->m_heap = nullptr; - } + } - this->m_heap = new(std::nothrow) Node[capacity]; - if( nullptr == this->m_heap ) { + this->m_heap = new (std::nothrow) Node[capacity]; + if (nullptr == this->m_heap) { return false; - } - this->m_capacity = capacity; - return true; } + this->m_capacity = capacity; + return true; +} - bool MaxHeap::push(FwQueuePriorityType value, FwSizeType id) { - // If the queue is full, return false: - if(this->isFull()) { +bool MaxHeap::push(FwQueuePriorityType value, FwSizeType id) { + // If the queue is full, return false: + if (this->isFull()) { return false; - } + } - // Heap indexes: - FwSizeType parent; - FwSizeType index = this->m_size; + // Heap indexes: + FwSizeType parent; + FwSizeType index = this->m_size; - // Max loop bounds for bit flip protection: - FwSizeType maxIter = this->m_size+1; - FwSizeType maxCount = 0; + // Max loop bounds for bit flip protection: + FwSizeType maxIter = this->m_size + 1; + FwSizeType maxCount = 0; - // Start at the bottom of the heap and work our ways - // upwards until we find a parent that has a value - // greater than ours. - while(index && maxCount < maxIter) { + // Start at the bottom of the heap and work our ways + // upwards until we find a parent that has a value + // greater than ours. + while (index && maxCount < maxIter) { // Get the parent index: parent = PARENT(index); // The parent index should ALWAYS be less than the @@ -85,87 +84,87 @@ namespace Types { // If the current value is less than the parent, // then the current index is in the correct place, // so break out of the loop: - if(value <= this->m_heap[parent].value) { - break; + if (value <= this->m_heap[parent].value) { + break; } // Swap the parent and child: this->m_heap[index] = this->m_heap[parent]; index = parent; ++maxCount; - } + } - // Check for programming errors or bit flips: - FW_ASSERT(maxCount < maxIter, static_cast(maxCount), static_cast(maxIter)); - FW_ASSERT(index <= this->m_size, static_cast(index)); + // Check for programming errors or bit flips: + FW_ASSERT(maxCount < maxIter, static_cast(maxCount), static_cast(maxIter)); + FW_ASSERT(index <= this->m_size, static_cast(index)); - // Set the values of the new element: - this->m_heap[index].value = value; - this->m_heap[index].order = m_order; - this->m_heap[index].id = id; + // Set the values of the new element: + this->m_heap[index].value = value; + this->m_heap[index].order = m_order; + this->m_heap[index].id = id; - ++this->m_size; - ++this->m_order; - return true; - } + ++this->m_size; + ++this->m_order; + return true; +} - bool MaxHeap::pop(FwQueuePriorityType & value, FwSizeType& id) { - // If there is nothing in the heap then - // return false: - if(this->isEmpty()) { +bool MaxHeap::pop(FwQueuePriorityType& value, FwSizeType& id) { + // If there is nothing in the heap then + // return false: + if (this->isEmpty()) { return false; - } - - // Set the return values to the top (max) of - // the heap: - value = this->m_heap[0].value; - id = this->m_heap[0].id; - - // Now place the last element on the heap in - // the root position, and resize the heap. - // This will put the smallest value in the - // heap on the top, violating the heap property. - FwSizeType index = this->m_size-1; - // Fw::Logger::log("Putting on top: i: %u v: %d\n", index, this->m_heap[index].value); - this->m_heap[0]= this->m_heap[index]; - --this->m_size; - - // Now that the heap property is violated, we - // need to reorganize the heap to restore it's - // heapy-ness. - this->heapify(); - return true; } - // Is the heap full: - bool MaxHeap::isFull() { - return (this->m_size == this->m_capacity); - } + // Set the return values to the top (max) of + // the heap: + value = this->m_heap[0].value; + id = this->m_heap[0].id; + + // Now place the last element on the heap in + // the root position, and resize the heap. + // This will put the smallest value in the + // heap on the top, violating the heap property. + FwSizeType index = this->m_size - 1; + // Fw::Logger::log("Putting on top: i: %u v: %d\n", index, this->m_heap[index].value); + this->m_heap[0] = this->m_heap[index]; + --this->m_size; + + // Now that the heap property is violated, we + // need to reorganize the heap to restore it's + // heapy-ness. + this->heapify(); + return true; +} - // Is the heap empty: - bool MaxHeap::isEmpty() { - return (this->m_size == 0); - } +// Is the heap full: +bool MaxHeap::isFull() { + return (this->m_size == this->m_capacity); +} - // Get the current size of the heap: - FwSizeType MaxHeap::getSize() const { - return this->m_size; - } +// Is the heap empty: +bool MaxHeap::isEmpty() { + return (this->m_size == 0); +} - // A non-recursive heapify method. - // Note: This method had an additional property, such that - // items pushed of the same priority will be popped in FIFO - // order. - void MaxHeap::heapify() { - FwSizeType index = 0; - FwSizeType left; - FwSizeType right; - FwSizeType largest; - - // Max loop bounds for bit flip protection: - FwSizeType maxIter = this->m_size+1; - FwSizeType maxCount = 0; - - while(index <= this->m_size && maxCount < maxIter) { +// Get the current size of the heap: +FwSizeType MaxHeap::getSize() const { + return this->m_size; +} + +// A non-recursive heapify method. +// Note: This method had an additional property, such that +// items pushed of the same priority will be popped in FIFO +// order. +void MaxHeap::heapify() { + FwSizeType index = 0; + FwSizeType left; + FwSizeType right; + FwSizeType largest; + + // Max loop bounds for bit flip protection: + FwSizeType maxIter = this->m_size + 1; + FwSizeType maxCount = 0; + + while (index <= this->m_size && maxCount < maxIter) { // Get the children indexes for this node: left = LCHILD(index); right = RCHILD(index); @@ -176,7 +175,7 @@ namespace Types { // size, we have reached the end of the heap // so we can stop: if (left >= this->m_size) { - break; + break; } // Initialize the largest node to the current @@ -189,16 +188,15 @@ namespace Types { // Make sure the right node exists before checking it: if (right < this->m_size) { - // Which one is larger, the current largest - // node or the right node? - largest = this->max(right, largest); + // Which one is larger, the current largest + // node or the right node? + largest = this->max(right, largest); } // If the largest node is the current node // then we are done heapifying: - if (largest == index) - { - break; + if (largest == index) { + break; } // Swap the largest node with the current node: @@ -209,82 +207,78 @@ namespace Types { // Set the new index to whichever child was larger: index = largest; - } - - // Check for programming errors or bit flips: - FW_ASSERT(maxCount < maxIter, static_cast(maxCount), static_cast(maxIter)); - FW_ASSERT(index <= this->m_size, static_cast(index)); } - // Return the maximum priority index between two nodes. If their - // priorities are equal, return the oldest to keep the heap stable - FwSizeType MaxHeap::max(FwSizeType a, FwSizeType b) { - FW_ASSERT(a < this->m_size, static_cast(a), static_cast(this->m_size)); - FW_ASSERT(b < this->m_size, static_cast(b), static_cast(this->m_size)); - - // Extract the priorities: - FwQueuePriorityType aValue = this->m_heap[a].value; - FwQueuePriorityType bValue = this->m_heap[b].value; - - // If the priorities are equal, the "larger" one will be - // the "older" one as determined by order pushed on to the - // heap. Using this secondary ordering technique makes the - // heap stable (ie. FIFO for equal priority elements). - // Note: We check this first, because it is the most common - // case. Let's save as many ticks as we can... - if(aValue == bValue) { + // Check for programming errors or bit flips: + FW_ASSERT(maxCount < maxIter, static_cast(maxCount), static_cast(maxIter)); + FW_ASSERT(index <= this->m_size, static_cast(index)); +} + +// Return the maximum priority index between two nodes. If their +// priorities are equal, return the oldest to keep the heap stable +FwSizeType MaxHeap::max(FwSizeType a, FwSizeType b) { + FW_ASSERT(a < this->m_size, static_cast(a), static_cast(this->m_size)); + FW_ASSERT(b < this->m_size, static_cast(b), static_cast(this->m_size)); + + // Extract the priorities: + FwQueuePriorityType aValue = this->m_heap[a].value; + FwQueuePriorityType bValue = this->m_heap[b].value; + + // If the priorities are equal, the "larger" one will be + // the "older" one as determined by order pushed on to the + // heap. Using this secondary ordering technique makes the + // heap stable (ie. FIFO for equal priority elements). + // Note: We check this first, because it is the most common + // case. Let's save as many ticks as we can... + if (aValue == bValue) { FwSizeType aAge = this->m_order - this->m_heap[a].order; FwSizeType bAge = this->m_order - this->m_heap[b].order; - if(aAge > bAge) { - return a; + if (aAge > bAge) { + return a; } return b; - } + } - // Which priority is larger?: - if( aValue > bValue ) { + // Which priority is larger?: + if (aValue > bValue) { return a; - } - // B is larger: - return b; } + // B is larger: + return b; +} - // Swap two nodes in the heap: - void MaxHeap::swap(FwSizeType a, FwSizeType b) { - FW_ASSERT(a < this->m_size, static_cast(a), static_cast(this->m_size)); - FW_ASSERT(b < this->m_size, static_cast(b), static_cast(this->m_size)); - Node temp = this->m_heap[a]; - this->m_heap[a] = this->m_heap[b]; - this->m_heap[b] = temp; - } +// Swap two nodes in the heap: +void MaxHeap::swap(FwSizeType a, FwSizeType b) { + FW_ASSERT(a < this->m_size, static_cast(a), static_cast(this->m_size)); + FW_ASSERT(b < this->m_size, static_cast(b), static_cast(this->m_size)); + Node temp = this->m_heap[a]; + this->m_heap[a] = this->m_heap[b]; + this->m_heap[b] = temp; +} - // Print heap, for debugging purposes only: - void MaxHeap::print() { - FwSizeType index = 0; - FwSizeType left; - FwSizeType right; - Fw::Logger::log("Printing Heap of Size: %d\n", this->m_size); - while(index < this->m_size) { +// Print heap, for debugging purposes only: +void MaxHeap::print() { + FwSizeType index = 0; + FwSizeType left; + FwSizeType right; + Fw::Logger::log("Printing Heap of Size: %d\n", this->m_size); + while (index < this->m_size) { left = LCHILD(index); right = RCHILD(index); - if( left >= m_size && index == 0) { - Fw::Logger::log("i: %u v: %d d: %u -> (NULL, NULL)\n", - index, this->m_heap[index].value, this->m_heap[index].id); - } - else if( right >= m_size && left < m_size ) { - Fw::Logger::log("i: %u v: %d d: %u -> (i: %u v: %d d: %u, NULL)\n", - index, this->m_heap[index].value, this->m_heap[index].id, - left, this->m_heap[left].value, this->m_heap[left].id); - } - else if( right < m_size && left < m_size ) { - Fw::Logger::log("i: %u v: %d d: %u -> (i: %u v: %d d: %u, i: %u v: %d d: %u)\n", - index, this->m_heap[index].value, this->m_heap[index].id, - left, this->m_heap[left].value,this->m_heap[left].id, - right, this->m_heap[right].value, this->m_heap[right].id); + if (left >= m_size && index == 0) { + Fw::Logger::log("i: %u v: %d d: %u -> (NULL, NULL)\n", index, this->m_heap[index].value, + this->m_heap[index].id); + } else if (right >= m_size && left < m_size) { + Fw::Logger::log("i: %u v: %d d: %u -> (i: %u v: %d d: %u, NULL)\n", index, this->m_heap[index].value, + this->m_heap[index].id, left, this->m_heap[left].value, this->m_heap[left].id); + } else if (right < m_size && left < m_size) { + Fw::Logger::log("i: %u v: %d d: %u -> (i: %u v: %d d: %u, i: %u v: %d d: %u)\n", index, + this->m_heap[index].value, this->m_heap[index].id, left, this->m_heap[left].value, + this->m_heap[left].id, right, this->m_heap[right].value, this->m_heap[right].id); } ++index; - } } } +} // namespace Types diff --git a/Os/Generic/Types/MaxHeap.hpp b/Os/Generic/Types/MaxHeap.hpp index 6dae7fdb6a..d280365a69 100644 --- a/Os/Generic/Types/MaxHeap.hpp +++ b/Os/Generic/Types/MaxHeap.hpp @@ -17,16 +17,16 @@ namespace Types { - //! \class MaxHeap - //! \brief A stable max heap data structure - //! - //! This is a max heap data structure. Items of the highest value will - //! be popped off the heap first. Items of equal value will be popped - //! off in FIFO order. Insertion and deletion from the heap are both - //! O(log(n)) time. - class MaxHeap { - - public: +//! \class MaxHeap +//! \brief A stable max heap data structure +//! +//! This is a max heap data structure. Items of the highest value will +//! be popped off the heap first. Items of equal value will be popped +//! off in FIFO order. Insertion and deletion from the heap are both +//! O(log(n)) time. +//! \warning allocates memory on the heap +class MaxHeap { + public: //! \brief MaxHeap constructor //! //! Create a max heap object @@ -40,6 +40,7 @@ namespace Types { //! \brief MaxHeap creation //! //! Create the max heap with a given maximum size + //! \warning allocates memory on the heap //! //! \param capacity the maximum number of elements to store in the heap //! @@ -88,7 +89,7 @@ namespace Types { //! void print(); - private: + private: // Private functions: // Ensure the heap meets the heap property: void heapify(); @@ -99,18 +100,18 @@ namespace Types { // The data structure for a node on the heap: struct Node { - FwQueuePriorityType value; // the priority of the node - FwSizeType order; // order in which node was pushed - FwSizeType id; // unique id for this node + FwQueuePriorityType value; // the priority of the node + FwSizeType order; // order in which node was pushed + FwSizeType id; // unique id for this node }; // Private members: - Node* m_heap; // the heap itself - FwSizeType m_size; // the current size of the heap - FwSizeType m_order; // the current count of heap pushes - FwSizeType m_capacity; // the maximum capacity of the heap - }; + Node* m_heap; // the heap itself + FwSizeType m_size; // the current size of the heap + FwSizeType m_order; // the current count of heap pushes + FwSizeType m_capacity; // the maximum capacity of the heap +}; -} +} // namespace Types -#endif // UTILS_TYPES_MAX_HEAP_HPP +#endif // UTILS_TYPES_MAX_HEAP_HPP diff --git a/Os/Generic/test/ut/PriorityQueueTests.cpp b/Os/Generic/test/ut/PriorityQueueTests.cpp index c8ad735c71..1f5675c050 100644 --- a/Os/Generic/test/ut/PriorityQueueTests.cpp +++ b/Os/Generic/test/ut/PriorityQueueTests.cpp @@ -6,7 +6,6 @@ #include "Os/Generic/PriorityQueue.hpp" #include "STest/Random/Random.hpp" - int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); STest::Random::seed(); diff --git a/Os/Generic/test/ut/QueueRulesDefinitions.hpp b/Os/Generic/test/ut/QueueRulesDefinitions.hpp index 2006c8cfc8..398091d9b8 100644 --- a/Os/Generic/test/ut/QueueRulesDefinitions.hpp +++ b/Os/Generic/test/ut/QueueRulesDefinitions.hpp @@ -1,12 +1,14 @@ +// ====================================================================== +// \title Os/Generic/test/ut/QueueRulesDefinitions.hpp +// \brief definitions fpr queue testing +// ====================================================================== #ifndef OS_STUB_TEST_UT_QUEUE_RULES_DEFINITIONS #define OS_STUB_TEST_UT_QUEUE_RULES_DEFINITIONS -#include "FpConfig.h" -#include #include +#include +#include "FpConfig.h" using PriorityCompare = std::less; constexpr FwSizeType QUEUE_MESSAGE_SIZE_UPPER_BOUND = 1024; constexpr FwSizeType QUEUE_DEPTH_UPPER_BOUND = 100; constexpr bool TESTS_SUPPORT_BLOCKING = true; - - -#endif // OS_STUB_TEST_UT_QUEUE_RULES_DEFINITIONS +#endif // OS_STUB_TEST_UT_QUEUE_RULES_DEFINITIONS diff --git a/Os/Queue.cpp b/Os/Queue.cpp index 698ec4116d..6251f55cc1 100644 --- a/Os/Queue.cpp +++ b/Os/Queue.cpp @@ -98,7 +98,8 @@ QueueInterface::Status Queue::receive(Fw::SerializeBufferBase& destination, QueueInterface::Status status = this->receive(destination.getBuffAddrSer(), destination.getBuffCapacity(), blockType, actualSize, priority); if (status == QueueInterface::Status::OP_OK) { - Fw::SerializeStatus serializeStatus = destination.setBuffLen(static_cast(actualSize)); + Fw::SerializeStatus serializeStatus = + destination.setBuffLen(static_cast(actualSize)); if (serializeStatus != Fw::SerializeStatus::FW_SERIALIZE_OK) { status = QueueInterface::Status::SIZE_MISMATCH; } diff --git a/Os/Queue.hpp b/Os/Queue.hpp index 2541213a40..86465eefaa 100644 --- a/Os/Queue.hpp +++ b/Os/Queue.hpp @@ -8,8 +8,8 @@ #include #include #include -#include #include +#include #include namespace Os { // Forward declaration for registry @@ -20,7 +20,7 @@ class QueueHandle {}; //! \brief base queue interface //! -//! Queues are used internally to F prime in order to support the messaging between components. The +//! Queues are used internally to fprime in order to support the messaging between components. The //! QueueInterface is used to abstract away from the standard OS-based queue, allowing F prime support //! multiple OSes in a consistent way. //! @@ -64,11 +64,14 @@ class QueueInterface { //! \brief create queue storage //! - //! Creates a queue ensuring sufficient storage to hold `depth` messages of `messageSize` size each. + //! Creates a queue ensuring sufficient storage to hold `depth` messages of `messageSize` size each. Resource + //! allocation is dependent on the underlying implementation and users should assume that resource allocation is + //! possible. + //! //! \param name: name of queue //! \param depth: depth of queue in number of messages //! \param messageSize: size of an individual message - //! \return: stauts of the creation + //! \return: status of the creation virtual Status create(const Fw::StringBase& name, FwSizeType depth, FwSizeType messageSize) = 0; //! \brief send a message into the queue @@ -77,6 +80,9 @@ class QueueInterface { //! `blockType` is set to BLOCKING, this call will block on queue full. Otherwise, this will return an error //! status on queue full. //! + //! It is invalid to send a null buffer. + //! This method will block if the queue is full and blockType is set to BLOCKING + //! //! \param buffer: message data //! \param size: size of message data //! \param priority: priority of the message @@ -90,6 +96,9 @@ class QueueInterface { //! When `blockType` is set to BLOCKING, this call will block on queue empty. Otherwise, this will return an //! error status on queue empty. Actual size received and priority of message is set on success status. //! + //! It is invalid to send a null buffer. + //! This method will block if the queue is empty and blockType is set to BLOCKING + //! //! \param destination: destination for message data //! \param capacity: maximum size of message data //! \param blockType: BLOCKING to wait for message or NONBLOCKING to return error when queue is empty @@ -104,6 +113,8 @@ class QueueInterface { //! \brief get number of messages available //! + //! Returns the number of messages currently available in the queue. + //! //! \return number of messages available virtual FwSizeType getMessagesAvailable() const = 0; @@ -155,18 +166,24 @@ class Queue final : public QueueInterface { //! \brief create queue storage through delegate //! - //! Creates a queue ensuring sufficient storage to hold `depth` messages of `messageSize` size each. + //! Creates a queue ensuring sufficient storage to hold `depth` messages of `messageSize` size each. This method + //! delegates to the underlying implementation. Resource allocation is dependent on the underlying implementation + //! and users should assume that resource allocation is possible. + //! //! \param name: name of queue //! \param depth: depth of queue in number of messages //! \param messageSize: size of an individual message - //! \return: stauts of the creation + //! \return: status of the creation Status create(const Fw::StringBase& name, FwSizeType depth, FwSizeType messageSize) override; //! \brief send a message into the queue through delegate //! //! Send a message into the queue, providing the message data, size, priority, and blocking type. When //! `blockType` is set to BLOCKING, this call will block on queue full. Otherwise, this will return an error - //! status on queue full. + //! status on queue full. This method delegates to the underlying implementation. + //! + //! \warning It is invalid to send a null buffer + //! \warning This method will block if the queue is full and blockType is set to BLOCKING //! //! \param buffer: message data //! \param size: size of message data @@ -179,7 +196,11 @@ class Queue final : public QueueInterface { //! //! Receive a message from the queue, providing the message destination, capacity, priority, and blocking type. //! When `blockType` is set to BLOCKING, this call will block on queue empty. Otherwise, this will return an - //! error status on queue empty. Actual size received and priority of message is set on success status. + //! error status on queue empty. Actual size received and priority of message is set on success status. This method + //! delegates to the underlying implementation. + //! + //! \warning It is invalid to send a null buffer. + //! \warning This method will block if the queue is empty and blockType is set to BLOCKING //! //! \param destination: destination for message data //! \param capacity: maximum size of message data @@ -193,7 +214,10 @@ class Queue final : public QueueInterface { FwSizeType& actualSize, FwQueuePriorityType& priority) override; - //! \brief get number of messages available through delegate + //! \brief get number of messages available + //! + //! Returns the number of messages currently available in the queue. This method delegates to the underlying + //! implementation. //! //! \return number of messages available FwSizeType getMessagesAvailable() const override; @@ -208,6 +232,9 @@ class Queue final : public QueueInterface { //! \brief send a message to a queue //! //! Send a message to a queue with the given priority and block type. See: QueueInterface::send + //! + //! \warning This method will block if the queue is full and blockType is set to BLOCKING + //! //! \param message: reference to serialize buffer storing message //! \param priority: priority of the message //! \param blockType: BLOCKING to block for space or NONBLOCKING to return error when queue is full @@ -218,6 +245,9 @@ class Queue final : public QueueInterface { //! //! Receive a message from a queue with the given block type. See: QueueInterface::receive. Note: this will entirely //! overwrite the buffer. + //! + //! \warning This method will block if the queue is full and blockType is set to BLOCKING + //! //! \param destination: reference to serialize buffer for storing message //! \param priority: (output) priority of the message //! \param blockType: BLOCKING to block for space or NONBLOCKING to return error when queue is full @@ -229,6 +259,7 @@ class Queue final : public QueueInterface { //! \brief get the queue's message maximum size FwSizeType getMessageSize() const; + //! \brief get the queue's name const QueueString& getName() const; @@ -236,9 +267,9 @@ class Queue final : public QueueInterface { static FwSizeType getNumQueues(); private: - QueueString m_name; //!< queue name - FwSizeType m_depth; //!< Queue depth - FwSizeType m_size; //!< Maximum message size + QueueString m_name; //!< queue name + FwSizeType m_depth; //!< Queue depth + FwSizeType m_size; //!< Maximum message size static std::atomic s_queueCount; //!< Count of the number of queues #if FW_QUEUE_REGISTRATION @@ -256,8 +287,8 @@ class Queue final : public QueueInterface { // 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) QueueHandleStorage m_handle_storage; //!< Storage for aligned handle - QueueInterface& m_delegate; //!< Delegate for the real implementation + alignas(FW_HANDLE_ALIGNMENT) QueueHandleStorage m_handle_storage; //!< Storage for aligned handle + QueueInterface& m_delegate; //!< Delegate for the real implementation }; //! \brief queue registry interface //! diff --git a/Os/Stub/Queue.hpp b/Os/Stub/Queue.hpp index 81ff306e22..7815024184 100644 --- a/Os/Stub/Queue.hpp +++ b/Os/Stub/Queue.hpp @@ -9,7 +9,7 @@ namespace Queue { struct StubQueueHandle : public QueueHandle {}; -//! \brief stl-powered queue implementation with injectable statuses +//! \brief stub queue implementation with injectable statuses class StubQueue : public QueueInterface { public: //! \brief default queue interface constructor @@ -33,7 +33,7 @@ class StubQueue : public QueueInterface { //! \param name: name of queue //! \param depth: depth of queue in number of messages //! \param messageSize: size of an individual message - //! \return: stauts of the creation + //! \return: status of the creation Status create(const Fw::StringBase& name, FwSizeType depth, FwSizeType messageSize) override; //! \brief send a message into the queue diff --git a/Os/Stub/test/Queue.hpp b/Os/Stub/test/Queue.hpp index 015ee24726..23071bccbe 100644 --- a/Os/Stub/test/Queue.hpp +++ b/Os/Stub/test/Queue.hpp @@ -75,7 +75,7 @@ struct InjectableStlQueueHandle : public QueueHandle { FwSizeType m_max_depth; }; -//! \brief stl-powered queue implementation with injectable statuses +//! \brief standard library powered queue implementation with injectable statuses class InjectableStlQueue : public QueueInterface { public: //! \brief default queue interface constructor @@ -99,7 +99,7 @@ class InjectableStlQueue : public QueueInterface { //! \param name: name of queue //! \param depth: depth of queue in number of messages //! \param messageSize: size of an individual message - //! \return: stauts of the creation + //! \return: status of the creation Status create(const Fw::StringBase& name, FwSizeType depth, FwSizeType messageSize) override; //! \brief send a message into the queue diff --git a/Os/test/ConcurrentRule.hpp b/Os/test/ConcurrentRule.hpp index d56db85be8..da0701585d 100644 --- a/Os/test/ConcurrentRule.hpp +++ b/Os/test/ConcurrentRule.hpp @@ -1,31 +1,34 @@ -#include +// ====================================================================== +// \title Os/test/ut/queue/RulesHeaders.cpp +// \brief definitions for concurrent running rules +// ====================================================================== #include -#include "Os/Task.hpp" -#include "Os/Mutex.hpp" -#include "Os/Condition.hpp" +#include +#include #include #include -#include +#include "Os/Condition.hpp" +#include "Os/Mutex.hpp" +#include "Os/Task.hpp" #ifndef OS_TEST_CONCURRENT_RULE #define OS_TEST_CONCURRENT_RULE -//! Global mutex protecting state -//extern Os::Mutex s_global_state_lock; - -//! Forward declaration -template class AggregatedConcurrentRule; +// Forward declaration of the aggregated concurrent rule +template +class AggregatedConcurrentRule; -template class ConcurrentRule : public STest::Rule { +template +class ConcurrentRule : public STest::Rule { friend class AggregatedConcurrentRule; + public: - ConcurrentRule(const char *const name, AggregatedConcurrentRule& runner) : STest::Rule(name), m_runner(runner) { + ConcurrentRule(const char* const name, AggregatedConcurrentRule& runner) + : STest::Rule(name), m_runner(runner) { this->m_runner.add(*this); this->m_condition_value = false; } - virtual ~ConcurrentRule() { - this->m_runner.remove(*this); - } + virtual ~ConcurrentRule() { this->m_runner.remove(*this); } //! Launch this rule asynchronously void action_async(State& state) { @@ -57,23 +60,16 @@ template class ConcurrentRule : public STest::Rule { } //! \brief get lock - Os::Mutex& getLock() { - return this->m_runner.getLock(); - } + Os::Mutex& getLock() { return this->m_runner.getLock(); } //! \brief notify another rule by nae, - void notify_other(std::string other) { - this->m_runner.notify(other); - } + void notify_other(std::string other) { this->m_runner.notify(other); } //! \brief get the condition variable - bool getCondition() { - return this->m_condition_value; - } + bool getCondition() { return this->m_condition_value; } + private: - void join() { - this->m_task.join(); - } + void join() { this->m_task.join(); } //! \brief notify this rule to take the next step void step() { @@ -98,30 +94,32 @@ template class ConcurrentRule : public STest::Rule { bool is_asynchronous = false; }; -template class ConcurrentWrapperRule : public ConcurrentRule { +template +class ConcurrentWrapperRule : public ConcurrentRule { public: - ConcurrentWrapperRule(AggregatedConcurrentRule& runner, STest::Rule& wrapped, std::string notify, const char* name=nullptr) - : ConcurrentRule((name == nullptr) ? wrapped.getName() : name, runner), m_wrapped(wrapped), m_notify(notify) { + ConcurrentWrapperRule(AggregatedConcurrentRule& runner, + STest::Rule& wrapped, + std::string notify, + const char* name = nullptr) + : ConcurrentRule((name == nullptr) ? wrapped.getName() : name, runner), + m_wrapped(wrapped), + m_notify(notify) {} - } - - bool precondition(const State& state) override { - return m_wrapped.precondition(state); - } + bool precondition(const State& state) override { return m_wrapped.precondition(state); } void action(State& state) override { - this->wait_for_next_step(); // Wait until told to go - this->m_wrapped.apply(state); // Go - this->notify_other(this->m_notify); // Notify when done + this->wait_for_next_step(); // Wait until told to go + this->m_wrapped.apply(state); // Go + this->notify_other(this->m_notify); // Notify when done } - private: + private: STest::Rule& m_wrapped; std::string m_notify; }; - -template class AggregatedConcurrentRule : public STest::Rule { +template +class AggregatedConcurrentRule : public STest::Rule { public: //! Creation AggregatedConcurrentRule() : STest::Rule("aggregated-rule") {} @@ -159,9 +157,7 @@ template class AggregatedConcurrentRule : public STest::Rulem_lock; - } + Os::Mutex& getLock() { return this->m_lock; } //! Aggregate rule may only run if bool precondition(const State& state) override { @@ -187,10 +183,11 @@ template class AggregatedConcurrentRule : public STest::Rulejoin(); } } + private: Os::Mutex m_lock; std::list*> m_rules; std::map*> m_rule_map; }; -#endif //OS_TEST_CONCURRENT_RULE \ No newline at end of file +#endif // OS_TEST_CONCURRENT_RULE \ No newline at end of file diff --git a/Os/test/ut/queue/CommonTests.cpp b/Os/test/ut/queue/CommonTests.cpp index 65259c2139..c917d64dd7 100644 --- a/Os/test/ut/queue/CommonTests.cpp +++ b/Os/test/ut/queue/CommonTests.cpp @@ -6,8 +6,8 @@ #include #include "Fw/Types/String.hpp" #include "Os/Queue.hpp" -#include "Os/test/ut/queue/RulesHeaders.hpp" #include "Os/test/ConcurrentRule.hpp" +#include "Os/test/ut/queue/RulesHeaders.hpp" const FwSizeType RANDOM_BOUND = 10000; @@ -30,7 +30,10 @@ Os::QueueInterface::Status Tester::shadow_create(FwSizeType depth, FwSizeType me return status; } -Os::QueueInterface::Status Tester::shadow_send(const U8* buffer, FwSizeType size, FwQueuePriorityType priority, Os::QueueInterface::BlockingType blockType) { +Os::QueueInterface::Status Tester::shadow_send(const U8* buffer, + FwSizeType size, + FwQueuePriorityType priority, + Os::QueueInterface::BlockingType blockType) { this->shadow_check(); QueueMessage qm; qm.priority = priority; @@ -38,16 +41,15 @@ Os::QueueInterface::Status Tester::shadow_send(const U8* buffer, FwSizeType size std::memcpy(qm.data, buffer, size); if (size > this->shadow.messageSize) { return QueueInterface::Status::SIZE_MISMATCH; - } - else if ((this->shadow.queue.size() == this->shadow.depth) && (blockType == Os::QueueInterface::BlockingType::BLOCKING)) { + } else if ((this->shadow.queue.size() == this->shadow.depth) && + (blockType == Os::QueueInterface::BlockingType::BLOCKING)) { this->shadow.send_block = qm; return QueueInterface::Status::OP_OK; - } - else if (this->shadow.queue.size() == this->shadow.depth) { + } else if (this->shadow.queue.size() == this->shadow.depth) { return QueueInterface::Status::FULL; } else { this->shadow.queue.push(qm); - this->shadow.hwm = FW_MAX(this->shadow.hwm, this->shadow.queue.size()); + this->shadow.highMark = FW_MAX(this->shadow.highMark, this->shadow.queue.size()); return QueueInterface::Status::OP_OK; } return QueueInterface::Status::OP_OK; @@ -56,10 +58,14 @@ Os::QueueInterface::Status Tester::shadow_send(const U8* buffer, FwSizeType size void Tester::shadow_send_unblock() { // Send the shadow send buffered message this->shadow.queue.push(this->shadow.send_block); - this->shadow.hwm = FW_MAX(this->shadow.hwm, this->shadow.queue.size()); + this->shadow.highMark = FW_MAX(this->shadow.highMark, this->shadow.queue.size()); } -Os::QueueInterface::Status Tester::shadow_receive(U8* destination, FwSizeType capacity, QueueInterface::BlockingType blockType, FwSizeType& actualSize, FwQueuePriorityType& priority) { +Os::QueueInterface::Status Tester::shadow_receive(U8* destination, + FwSizeType capacity, + QueueInterface::BlockingType blockType, + FwSizeType& actualSize, + FwQueuePriorityType& priority) { this->shadow_check(); if (capacity < this->shadow.messageSize) { return QueueInterface::Status::SIZE_MISMATCH; @@ -80,7 +86,6 @@ Os::QueueInterface::Status Tester::shadow_receive(U8* destination, FwSizeType ca return QueueInterface::Status::OP_OK; } - void Tester::shadow_receive_unblock() { // Make sure outputs were stored in the shadow receive buffer ASSERT_NE(this->shadow.receive_block.destination, nullptr); @@ -100,12 +105,11 @@ void Tester::shadow_receive_unblock() { this->shadow.receive_block.priority = nullptr; } -} // namespace Os -} // namespace Test -} // namespace Queue +} // namespace Queue +} // namespace Test +} // namespace Os - -TEST(InterfaceUninitalized, SendPointer) { +TEST(InterfaceUninitialized, SendPointer) { Os::Queue queue; Fw::String name = "My queue"; const FwSizeType messageSize = 200; @@ -117,7 +121,7 @@ TEST(InterfaceUninitalized, SendPointer) { ASSERT_EQ(Os::QueueInterface::Status::UNINITIALIZED, status); } -TEST(InterfaceUninitalized, SendBuffer) { +TEST(InterfaceUninitialized, SendBuffer) { Os::Queue queue; Fw::String name = "My queue"; const FwSizeType messageSize = 200; @@ -129,7 +133,7 @@ TEST(InterfaceUninitalized, SendBuffer) { ASSERT_EQ(Os::QueueInterface::Status::UNINITIALIZED, status); } -TEST(InterfaceUninitalized, ReceivePointer) { +TEST(InterfaceUninitialized, ReceivePointer) { Os::Queue queue; Fw::String name = "My queue"; FwSizeType size = 200; @@ -141,7 +145,7 @@ TEST(InterfaceUninitalized, ReceivePointer) { ASSERT_EQ(Os::QueueInterface::Status::UNINITIALIZED, status); } -TEST(InterfaceUninitalized, ReceiveBuffer) { +TEST(InterfaceUninitialized, ReceiveBuffer) { Os::Queue queue; Fw::String name = "My queue"; FwSizeType size = 200; @@ -181,8 +185,7 @@ TEST(InterfaceInvalid, SendInvalidEnum) { const FwQueuePriorityType priority = 300; Os::QueueInterface::BlockingType blockingType = static_cast(Os::QueueInterface::BlockingType::BLOCKING + 1); - ASSERT_DEATH_IF_SUPPORTED(queue.send(nullptr, messageSize, priority, blockingType), - "Assert:.*Queue\\.cpp"); + ASSERT_DEATH_IF_SUPPORTED(queue.send(nullptr, messageSize, priority, blockingType), "Assert:.*Queue\\.cpp"); } TEST(InterfaceInvalid, ReceivePointerNull) { @@ -202,9 +205,7 @@ TEST(InterfaceInvalid, ReceiveInvalidEnum) { FwQueuePriorityType priority; Os::QueueInterface::BlockingType blockingType = static_cast(Os::QueueInterface::BlockingType::BLOCKING + 1); - ASSERT_DEATH_IF_SUPPORTED( - queue.receive(nullptr, size, blockingType, size, priority), - "Assert:.*Queue\\.cpp"); + ASSERT_DEATH_IF_SUPPORTED(queue.receive(nullptr, size, blockingType, size, priority), "Assert:.*Queue\\.cpp"); } TEST(BasicRules, Create) { @@ -281,7 +282,7 @@ TEST(Blocking, SendBlock) { AggregatedConcurrentRule aggregator; Os::Test::Queue::Tester::SendBlock block(aggregator); Os::Test::Queue::Tester::ReceiveNotEmpty receive_not_empty; - ConcurrentWrapperRule unblock(aggregator, receive_not_empty, "SendBlock", "SendUnblock"); + ConcurrentWrapperRule unblock(aggregator, receive_not_empty, "SendBlock", "SendUnblock"); create_rule.apply(tester); overflow_rule.apply(tester); @@ -295,7 +296,7 @@ TEST(Blocking, ReceiveBlock) { AggregatedConcurrentRule aggregator; Os::Test::Queue::Tester::ReceiveBlock block(aggregator); Os::Test::Queue::Tester::SendNotFull send_not_full; - ConcurrentWrapperRule unblock(aggregator, send_not_full, "ReceiveBlock", "ReceiveUnblock"); + ConcurrentWrapperRule unblock(aggregator, send_not_full, "ReceiveBlock", "ReceiveUnblock"); create_rule.apply(tester); overflow_rule.apply(tester); @@ -313,31 +314,20 @@ TEST(Random, RandomNominal) { Os::Test::Queue::Tester::Overflow overflow_rule; Os::Test::Queue::Tester::Underflow underflow_rule; - // Place these rules into a list of rules - STest::Rule* rules[] = { - &create_rule, - &send_rule, - &receive_rule, - &overflow_rule, - &underflow_rule, - &send_full_no_block_rule, - &receive_empty_no_block_rule - }; + STest::Rule* rules[] = {&create_rule, + &send_rule, + &receive_rule, + &overflow_rule, + &underflow_rule, + &send_full_no_block_rule, + &receive_empty_no_block_rule}; // Take the rules and place them into a random scenario - STest::RandomScenario random( - "Random Rules", - rules, - FW_NUM_ARRAY_ELEMENTS(rules) - ); + STest::RandomScenario random("Random Rules", rules, FW_NUM_ARRAY_ELEMENTS(rules)); // Create a bounded scenario wrapping the random scenario - STest::BoundedScenario bounded( - "Bounded Random Rules Scenario", - random, - RANDOM_BOUND - ); + STest::BoundedScenario bounded("Bounded Random Rules Scenario", random, RANDOM_BOUND); // Run! const U32 numSteps = bounded.run(tester); printf("Ran %u steps.\n", numSteps); diff --git a/Os/test/ut/queue/CommonTests.hpp b/Os/test/ut/queue/CommonTests.hpp index 71f07c134d..3eb63e326c 100644 --- a/Os/test/ut/queue/CommonTests.hpp +++ b/Os/test/ut/queue/CommonTests.hpp @@ -1,7 +1,8 @@ -// -// Created by Michael Starch on 4/11/24. -// +// ====================================================================== +// \title Os/test/ut/queue/CommonTests.hpp +// \brief required header +// ====================================================================== #include "RulesHeaders.hpp" #ifndef OS_TEST_UT_QUEUE_COMMON_TESTS_HPP #define OS_TEST_UT_QUEUE_COMMON_TESTS_HPP -#endif //OS_TEST_UT_QUEUE_COMMON_TESTS_HPP +#endif // OS_TEST_UT_QUEUE_COMMON_TESTS_HPP diff --git a/Os/test/ut/queue/QueueRules.cpp b/Os/test/ut/queue/QueueRules.cpp index b95c0df96d..a2e77260b0 100644 --- a/Os/test/ut/queue/QueueRules.cpp +++ b/Os/test/ut/queue/QueueRules.cpp @@ -1,4 +1,7 @@ - +// ====================================================================== +// \title Os/test/ut/queue/QueueRules.cpp +// \brief queue rule implementations +// ====================================================================== #include "CommonTests.hpp" #include "Fw/Types/String.hpp" @@ -70,14 +73,15 @@ bool Os::Test::Queue::Tester::SendNotFull::precondition(const Os::Test::Queue::T void Os::Test::Queue::Tester::SendNotFull::action(Os::Test::Queue::Tester& state //!< The test state ) { - QueueInterface::BlockingType blocking = (STest::Random::lowerUpper(0, 1) == 1) ? QueueInterface::BLOCKING : QueueInterface::NONBLOCKING; + QueueInterface::BlockingType blocking = + (STest::Random::lowerUpper(0, 1) == 1) ? QueueInterface::BLOCKING : QueueInterface::NONBLOCKING; PickedMessage pick = pick_message(state.shadow.messageSize); // Prevent lock-up ASSERT_LT(state.queue.getMessagesAvailable(), state.queue.getDepth()); ASSERT_FALSE(state.is_shadow_full()); QueueInterface::Status status = state.shadow_send(pick.sent, pick.size, pick.priority, blocking); QueueInterface::Status test_status = state.queue.send(pick.sent, pick.size, pick.priority, blocking); - delete[] pick.sent; // Clean-up + delete[] pick.sent; // Clean-up ASSERT_EQ(status, QueueInterface::Status::OP_OK); ASSERT_EQ(test_status, status); state.shadow_check(); @@ -99,7 +103,8 @@ void Os::Test::Queue::Tester::SendFullNoBlock::action(Os::Test::Queue::Tester& s ) { PickedMessage pick = pick_message(state.shadow.messageSize); QueueInterface::Status status = state.shadow_send(pick.sent, pick.size, pick.priority, QueueInterface::NONBLOCKING); - QueueInterface::Status test_status = state.queue.send(pick.sent, pick.size, pick.priority, QueueInterface::NONBLOCKING); + QueueInterface::Status test_status = + state.queue.send(pick.sent, pick.size, pick.priority, QueueInterface::NONBLOCKING); delete[] pick.sent; ASSERT_EQ(status, QueueInterface::Status::FULL); @@ -121,17 +126,19 @@ bool Os::Test::Queue::Tester::ReceiveNotEmpty::precondition(const Os::Test::Queu void Os::Test::Queue::Tester::ReceiveNotEmpty::action(Os::Test::Queue::Tester& state //!< The test state ) { - QueueInterface::BlockingType blocking = (STest::Random::lowerUpper(0, 1) == 1) ? QueueInterface::BLOCKING : QueueInterface::NONBLOCKING; + QueueInterface::BlockingType blocking = + (STest::Random::lowerUpper(0, 1) == 1) ? QueueInterface::BLOCKING : QueueInterface::NONBLOCKING; PickedMessage message; PickedMessage test; // Prevent lock-up ASSERT_GT(state.queue.getMessagesAvailable(), 0); ASSERT_FALSE(state.is_shadow_empty()); - QueueInterface::Status status = state.shadow_receive(message.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND, - blocking, message.size, message.priority); + QueueInterface::Status status = state.shadow_receive(message.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND, blocking, + message.size, message.priority); - QueueInterface::Status test_status = state.queue.receive(test.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND, blocking, test.size, test.priority); + QueueInterface::Status test_status = + state.queue.receive(test.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND, blocking, test.size, test.priority); ASSERT_EQ(status, QueueInterface::Status::OP_OK); ASSERT_EQ(status, test_status); check_received(message, test); @@ -142,9 +149,11 @@ void Os::Test::Queue::Tester::ReceiveNotEmpty::action(Os::Test::Queue::Tester& s // // ------------------------------------------------------------------------------------------------------ -Os::Test::Queue::Tester::ReceiveEmptyNoBlock::ReceiveEmptyNoBlock() : STest::Rule("ReceiveEmptyNoBlock") {} +Os::Test::Queue::Tester::ReceiveEmptyNoBlock::ReceiveEmptyNoBlock() + : STest::Rule("ReceiveEmptyNoBlock") {} -bool Os::Test::Queue::Tester::ReceiveEmptyNoBlock::precondition(const Os::Test::Queue::Tester& state //!< The test state +bool Os::Test::Queue::Tester::ReceiveEmptyNoBlock::precondition( + const Os::Test::Queue::Tester& state //!< The test state ) { return state.shadow.created and state.is_shadow_empty(); } @@ -154,186 +163,170 @@ void Os::Test::Queue::Tester::ReceiveEmptyNoBlock::action(Os::Test::Queue::Teste PickedMessage message; PickedMessage test; - QueueInterface::Status status = state.shadow_receive(message.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND, - QueueInterface::BlockingType::NONBLOCKING, message.size, message.priority); + QueueInterface::Status status = + state.shadow_receive(message.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND, + QueueInterface::BlockingType::NONBLOCKING, message.size, message.priority); - QueueInterface::Status test_status = state.queue.receive(test.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND, QueueInterface::BlockingType::NONBLOCKING, test.size, test.priority); + QueueInterface::Status test_status = + state.queue.receive(test.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND, QueueInterface::BlockingType::NONBLOCKING, + test.size, test.priority); ASSERT_EQ(status, QueueInterface::Status::EMPTY); ASSERT_EQ(status, test_status); } +// ------------------------------------------------------------------------------------------------------ +// Rule: Overflow +// +// ------------------------------------------------------------------------------------------------------ + +Os::Test::Queue::Tester::Overflow::Overflow() : STest::Rule("Overflow") {} - // ------------------------------------------------------------------------------------------------------ - // Rule: Overflow - // - // ------------------------------------------------------------------------------------------------------ - - Os::Test::Queue::Tester::Overflow::Overflow() : - STest::Rule("Overflow") - { - } - - - bool Os::Test::Queue::Tester::Overflow::precondition( - const Os::Test::Queue::Tester& state //!< The test state - ) - { - return state.is_shadow_created(); - } - - - void Os::Test::Queue::Tester::Overflow::action( - Os::Test::Queue::Tester& state //!< The test state - ) - { - while (not state.is_shadow_full()) { - PickedMessage pick = pick_message(state.shadow.messageSize); - QueueInterface::Status status = - state.shadow_send(pick.sent, pick.size, pick.priority, QueueInterface::BlockingType::NONBLOCKING); - QueueInterface::Status test_status = - state.queue.send(pick.sent, pick.size, pick.priority, QueueInterface::BlockingType::NONBLOCKING); - delete[] pick.sent; - ASSERT_EQ(status, QueueInterface::Status::OP_OK); - ASSERT_EQ(status, test_status); - } - PickedMessage pick = pick_message(state.shadow.messageSize); - QueueInterface::Status status = - state.shadow_send(pick.sent, pick.size, pick.priority, QueueInterface::BlockingType::NONBLOCKING); - QueueInterface::Status test_status = - state.queue.send(pick.sent, pick.size, pick.priority, QueueInterface::BlockingType::NONBLOCKING); - delete[] pick.sent; - ASSERT_EQ(status, QueueInterface::Status::FULL); - ASSERT_EQ(status, test_status); - state.shadow_check(); - } - - - - - - // ------------------------------------------------------------------------------------------------------ - // Rule: Underflow - // - // ------------------------------------------------------------------------------------------------------ - - Os::Test::Queue::Tester::Underflow::Underflow() : - STest::Rule("Underflow") - { - } - - - bool Os::Test::Queue::Tester::Underflow::precondition( - const Os::Test::Queue::Tester& state //!< The test state - ) - { - return state.is_shadow_created(); - } - - void Os::Test::Queue::Tester::Underflow::action( - Os::Test::Queue::Tester& state //!< The test state - ) - { - PickedMessage message; - PickedMessage test; - while (not state.is_shadow_empty()) { - QueueInterface::Status status = - state.shadow_receive(message.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND, - QueueInterface::BlockingType::NONBLOCKING, message.size, message.priority); - - QueueInterface::Status test_status = - state.queue.receive(test.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND, - QueueInterface::BlockingType::NONBLOCKING, test.size, test.priority); - ASSERT_EQ(status, QueueInterface::Status::OP_OK); - ASSERT_EQ(status, test_status); - check_received(message, test); - } - QueueInterface::Status status = - state.shadow_receive(message.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND, - QueueInterface::BlockingType::NONBLOCKING, message.size, message.priority); - - QueueInterface::Status test_status = - state.queue.receive(test.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND, - QueueInterface::BlockingType::NONBLOCKING, test.size, test.priority); - ASSERT_EQ(status, QueueInterface::Status::EMPTY); - ASSERT_EQ(status, test_status); - state.shadow_check(); - } - - // ------------------------------------------------------------------------------------------------------ - // Rule: SendBlock - // - // ------------------------------------------------------------------------------------------------------ - - Os::Test::Queue::Tester::SendBlock::SendBlock(AggregatedConcurrentRule& runner) : ConcurrentRule("SendBlock", runner) {} - - bool Os::Test::Queue::Tester::SendBlock::precondition( - const Os::Test::Queue::Tester& state //!< The test state - ) { - return state.shadow.created && state.is_shadow_full(); - } - - void Os::Test::Queue::Tester::SendBlock::action( - Os::Test::Queue::Tester& state //!< The test state - ) { - // Backend defined check - if (not TESTS_SUPPORT_BLOCKING) { - this->notify_other("SendUnblock"); - return; - } - PickedMessage pick = pick_message(state.shadow.messageSize); - this->notify_other("SendUnblock"); - QueueInterface::Status status = state.shadow_send(pick.sent, pick.size, pick.priority, QueueInterface::BlockingType::BLOCKING); - getLock().unlock(); - QueueInterface::Status test_status = state.queue.send(pick.sent, pick.size, pick.priority, QueueInterface::BlockingType::BLOCKING); - getLock().lock(); - // Condition should be set after block - ASSERT_TRUE(this->getCondition()); - // Unblock the shadow queue send - state.shadow_send_unblock(); - delete[] pick.sent; - - ASSERT_EQ(status, QueueInterface::Status::OP_OK); - ASSERT_EQ(test_status, status); - state.shadow_check(); - } - - // ------------------------------------------------------------------------------------------------------ - // Rule: ReceiveBlock - // - // ------------------------------------------------------------------------------------------------------ - - Os::Test::Queue::Tester::ReceiveBlock::ReceiveBlock(AggregatedConcurrentRule& runner) : ConcurrentRule("ReceiveBlock", runner) {} - - bool Os::Test::Queue::Tester::ReceiveBlock::precondition( - const Os::Test::Queue::Tester& state //!< The test state - ) { - return state.shadow.created && state.is_shadow_empty(); +bool Os::Test::Queue::Tester::Overflow::precondition(const Os::Test::Queue::Tester& state //!< The test state +) { + return state.is_shadow_created(); +} + +void Os::Test::Queue::Tester::Overflow::action(Os::Test::Queue::Tester& state //!< The test state +) { + while (not state.is_shadow_full()) { + PickedMessage pick = pick_message(state.shadow.messageSize); + QueueInterface::Status status = + state.shadow_send(pick.sent, pick.size, pick.priority, QueueInterface::BlockingType::NONBLOCKING); + QueueInterface::Status test_status = + state.queue.send(pick.sent, pick.size, pick.priority, QueueInterface::BlockingType::NONBLOCKING); + delete[] pick.sent; + ASSERT_EQ(status, QueueInterface::Status::OP_OK); + ASSERT_EQ(status, test_status); } + PickedMessage pick = pick_message(state.shadow.messageSize); + QueueInterface::Status status = + state.shadow_send(pick.sent, pick.size, pick.priority, QueueInterface::BlockingType::NONBLOCKING); + QueueInterface::Status test_status = + state.queue.send(pick.sent, pick.size, pick.priority, QueueInterface::BlockingType::NONBLOCKING); + delete[] pick.sent; + ASSERT_EQ(status, QueueInterface::Status::FULL); + ASSERT_EQ(status, test_status); + state.shadow_check(); +} - void Os::Test::Queue::Tester::ReceiveBlock::action( - Os::Test::Queue::Tester& state //!< The test state - ) { - // Backend defined check - if (not TESTS_SUPPORT_BLOCKING) { - this->notify_other("ReceiveUnblock"); - return; - } - - PickedMessage message; - PickedMessage test; - this->notify_other("ReceiveUnblock"); +// ------------------------------------------------------------------------------------------------------ +// Rule: Underflow +// +// ------------------------------------------------------------------------------------------------------ - QueueInterface::Status status = state.shadow_receive(message.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND, - QueueInterface::BlockingType::BLOCKING, message.size, message.priority); - this->getLock().unlock(); - QueueInterface::Status test_status = state.queue.receive(test.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND, QueueInterface::BlockingType::BLOCKING, test.size, test.priority); - this->getLock().lock(); - // Condition should be set after block - ASSERT_TRUE(this->getCondition()); - // Unblock the shadow queue send - state.shadow_receive_unblock(); +Os::Test::Queue::Tester::Underflow::Underflow() : STest::Rule("Underflow") {} +bool Os::Test::Queue::Tester::Underflow::precondition(const Os::Test::Queue::Tester& state //!< The test state +) { + return state.is_shadow_created(); +} + +void Os::Test::Queue::Tester::Underflow::action(Os::Test::Queue::Tester& state //!< The test state +) { + PickedMessage message; + PickedMessage test; + while (not state.is_shadow_empty()) { + QueueInterface::Status status = + state.shadow_receive(message.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND, + QueueInterface::BlockingType::NONBLOCKING, message.size, message.priority); + + QueueInterface::Status test_status = + state.queue.receive(test.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND, + QueueInterface::BlockingType::NONBLOCKING, test.size, test.priority); ASSERT_EQ(status, QueueInterface::Status::OP_OK); ASSERT_EQ(status, test_status); check_received(message, test); } + QueueInterface::Status status = + state.shadow_receive(message.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND, + QueueInterface::BlockingType::NONBLOCKING, message.size, message.priority); + + QueueInterface::Status test_status = + state.queue.receive(test.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND, QueueInterface::BlockingType::NONBLOCKING, + test.size, test.priority); + ASSERT_EQ(status, QueueInterface::Status::EMPTY); + ASSERT_EQ(status, test_status); + state.shadow_check(); +} + +// ------------------------------------------------------------------------------------------------------ +// Rule: SendBlock +// +// ------------------------------------------------------------------------------------------------------ + +Os::Test::Queue::Tester::SendBlock::SendBlock(AggregatedConcurrentRule& runner) + : ConcurrentRule("SendBlock", runner) {} + +bool Os::Test::Queue::Tester::SendBlock::precondition(const Os::Test::Queue::Tester& state //!< The test state +) { + return state.shadow.created && state.is_shadow_full(); +} + +void Os::Test::Queue::Tester::SendBlock::action(Os::Test::Queue::Tester& state //!< The test state +) { + // Backend defined check + if (not TESTS_SUPPORT_BLOCKING) { + this->notify_other("SendUnblock"); + return; + } + PickedMessage pick = pick_message(state.shadow.messageSize); + this->notify_other("SendUnblock"); + QueueInterface::Status status = + state.shadow_send(pick.sent, pick.size, pick.priority, QueueInterface::BlockingType::BLOCKING); + getLock().unlock(); + QueueInterface::Status test_status = + state.queue.send(pick.sent, pick.size, pick.priority, QueueInterface::BlockingType::BLOCKING); + getLock().lock(); + // Condition should be set after block + ASSERT_TRUE(this->getCondition()); + // Unblock the shadow queue send + state.shadow_send_unblock(); + delete[] pick.sent; + + ASSERT_EQ(status, QueueInterface::Status::OP_OK); + ASSERT_EQ(test_status, status); + state.shadow_check(); +} + +// ------------------------------------------------------------------------------------------------------ +// Rule: ReceiveBlock +// +// ------------------------------------------------------------------------------------------------------ + +Os::Test::Queue::Tester::ReceiveBlock::ReceiveBlock(AggregatedConcurrentRule& runner) + : ConcurrentRule("ReceiveBlock", runner) {} + +bool Os::Test::Queue::Tester::ReceiveBlock::precondition(const Os::Test::Queue::Tester& state //!< The test state +) { + return state.shadow.created && state.is_shadow_empty(); +} + +void Os::Test::Queue::Tester::ReceiveBlock::action(Os::Test::Queue::Tester& state //!< The test state +) { + // Backend defined check + if (not TESTS_SUPPORT_BLOCKING) { + this->notify_other("ReceiveUnblock"); + return; + } + + PickedMessage message; + PickedMessage test; + this->notify_other("ReceiveUnblock"); + + QueueInterface::Status status = + state.shadow_receive(message.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND, QueueInterface::BlockingType::BLOCKING, + message.size, message.priority); + this->getLock().unlock(); + QueueInterface::Status test_status = + state.queue.receive(test.received, QUEUE_MESSAGE_SIZE_UPPER_BOUND, QueueInterface::BlockingType::BLOCKING, + test.size, test.priority); + this->getLock().lock(); + // Condition should be set after block + ASSERT_TRUE(this->getCondition()); + // Unblock the shadow queue send + state.shadow_receive_unblock(); + + ASSERT_EQ(status, QueueInterface::Status::OP_OK); + ASSERT_EQ(status, test_status); + check_received(message, test); +} diff --git a/Os/test/ut/queue/QueueRules.hpp b/Os/test/ut/queue/QueueRules.hpp index f153548c8b..2f2f667311 100644 --- a/Os/test/ut/queue/QueueRules.hpp +++ b/Os/test/ut/queue/QueueRules.hpp @@ -1,334 +1,277 @@ - - - - - // ------------------------------------------------------------------------------------------------------ - // Rule: Create - // - // ------------------------------------------------------------------------------------------------------ - struct Create : public STest::Rule { - - // ---------------------------------------------------------------------- - // Construction - // ---------------------------------------------------------------------- - - //! Constructor - Create(); - - // ---------------------------------------------------------------------- - // Public member functions - // ---------------------------------------------------------------------- - - //! Precondition - bool precondition( - const Os::Test::Queue::Tester& state //!< The test state - ); - - //! Action - void action( - Os::Test::Queue::Tester& state //!< The test state - ); - - }; - - - - - - // ------------------------------------------------------------------------------------------------------ - // Rule: SendNotFull - // - // ------------------------------------------------------------------------------------------------------ - struct SendNotFull : public STest::Rule { - - // ---------------------------------------------------------------------- - // Construction - // ---------------------------------------------------------------------- - - //! Constructor - SendNotFull(); - - // ---------------------------------------------------------------------- - // Public member functions - // ---------------------------------------------------------------------- - - //! Precondition - bool precondition( - const Os::Test::Queue::Tester& state //!< The test state - ); - - //! Action - void action( - Os::Test::Queue::Tester& state //!< The test state - ); - - }; - - // ------------------------------------------------------------------------------------------------------ - // Rule: SendFullNoBlock - // - // ------------------------------------------------------------------------------------------------------ - struct SendFullNoBlock : public STest::Rule { - - // ---------------------------------------------------------------------- - // Construction - // ---------------------------------------------------------------------- - - //! Constructor - SendFullNoBlock(); - - // ---------------------------------------------------------------------- - // Public member functions - // ---------------------------------------------------------------------- - - //! Precondition - bool precondition( - const Os::Test::Queue::Tester& state //!< The test state - ); - - //! Action - void action( - Os::Test::Queue::Tester& state //!< The test state - ); - - }; - - - - // ------------------------------------------------------------------------------------------------------ - // Rule: ReceiveNotEmpty - // - // ------------------------------------------------------------------------------------------------------ - struct ReceiveNotEmpty : public STest::Rule { - - // ---------------------------------------------------------------------- - // Construction - // ---------------------------------------------------------------------- - - //! Constructor - ReceiveNotEmpty(); - - // ---------------------------------------------------------------------- - // Public member functions - // ---------------------------------------------------------------------- - - //! Precondition - bool precondition( - const Os::Test::Queue::Tester& state //!< The test state - ); - - //! Action - void action( - Os::Test::Queue::Tester& state //!< The test state - ); - - }; - - // ------------------------------------------------------------------------------------------------------ - // Rule: ReceiveEmptyNoBlock - // - // ------------------------------------------------------------------------------------------------------ - struct ReceiveEmptyNoBlock : public STest::Rule { - - // ---------------------------------------------------------------------- - // Construction - // ---------------------------------------------------------------------- - - //! Constructor - ReceiveEmptyNoBlock(); - - // ---------------------------------------------------------------------- - // Public member functions - // ---------------------------------------------------------------------- - - //! Precondition - bool precondition( - const Os::Test::Queue::Tester& state //!< The test state - ); - - //! Action - void action( - Os::Test::Queue::Tester& state //!< The test state - ); - - }; - - - - - - // ------------------------------------------------------------------------------------------------------ - // Rule: Overflow - // - // ------------------------------------------------------------------------------------------------------ - struct Overflow : public STest::Rule { - - // ---------------------------------------------------------------------- - // Construction - // ---------------------------------------------------------------------- - - //! Constructor - Overflow(); - - // ---------------------------------------------------------------------- - // Public member functions - // ---------------------------------------------------------------------- - - //! Precondition - bool precondition( - const Os::Test::Queue::Tester& state //!< The test state - ); - - //! Action - void action( - Os::Test::Queue::Tester& state //!< The test state - ); - - }; - - - - - - // ------------------------------------------------------------------------------------------------------ - // Rule: Underflow - // - // ------------------------------------------------------------------------------------------------------ - struct Underflow : public STest::Rule { - - // ---------------------------------------------------------------------- - // Construction - // ---------------------------------------------------------------------- - - //! Constructor - Underflow(); - - // ---------------------------------------------------------------------- - // Public member functions - // ---------------------------------------------------------------------- - - //! Precondition - bool precondition( - const Os::Test::Queue::Tester& state //!< The test state - ); - - //! Action - void action( - Os::Test::Queue::Tester& state //!< The test state - ); - - }; - - // ------------------------------------------------------------------------------------------------------ - // Rule: SendBlock - // - // ------------------------------------------------------------------------------------------------------ - struct SendBlock : public ConcurrentRule { - - // ---------------------------------------------------------------------- - // Construction - // ---------------------------------------------------------------------- - - //! Constructor - SendBlock(AggregatedConcurrentRule& runner); - - // ---------------------------------------------------------------------- - // Public member functions - // ---------------------------------------------------------------------- - - //! Precondition - bool precondition( - const Os::Test::Queue::Tester& state //!< The test state - ) override; - - //! Action - void action( - Os::Test::Queue::Tester& state //!< The test state - ) override; - - }; - // ------------------------------------------------------------------------------------------------------ - // Rule: SendUnblock - // - // ------------------------------------------------------------------------------------------------------ - struct SendUnblock : public ConcurrentRule { - - // ---------------------------------------------------------------------- - // Construction - // ---------------------------------------------------------------------- - - //! Constructor - SendUnblock(AggregatedConcurrentRule& runner); - - // ---------------------------------------------------------------------- - // Public member functions - // ---------------------------------------------------------------------- - - //! Precondition - bool precondition( - const Os::Test::Queue::Tester& state //!< The test state - ) override; - - //! Action - void action( - Os::Test::Queue::Tester& state //!< The test state - ) override; - - }; - - // ------------------------------------------------------------------------------------------------------ - // Rule: ReceiveBlock - // - // ------------------------------------------------------------------------------------------------------ - struct ReceiveBlock : public ConcurrentRule { - - // ---------------------------------------------------------------------- - // Construction - // ---------------------------------------------------------------------- - - //! Constructor - ReceiveBlock(AggregatedConcurrentRule& runner); - - // ---------------------------------------------------------------------- - // Public member functions - // ---------------------------------------------------------------------- - - //! Precondition - bool precondition( - const Os::Test::Queue::Tester& state //!< The test state - ) override; - - //! Action - void action( - Os::Test::Queue::Tester& state //!< The test state - ) override; - - }; - // ------------------------------------------------------------------------------------------------------ - // Rule: ReceiveUnblock - // - // ------------------------------------------------------------------------------------------------------ - struct ReceiveUnblock : public ConcurrentRule { - - // ---------------------------------------------------------------------- - // Construction - // ---------------------------------------------------------------------- - - //! Constructor - ReceiveUnblock(AggregatedConcurrentRule& runner); - - // ---------------------------------------------------------------------- - // Public member functions - // ---------------------------------------------------------------------- - - //! Precondition - bool precondition( - const Os::Test::Queue::Tester& state //!< The test state - ) override; - - //! Action - void action( - Os::Test::Queue::Tester& state //!< The test state - ) override; - - }; \ No newline at end of file +// ====================================================================== +// \title Os/test/ut/queue/QueueRules.hpp +// \brief queue rule definitions +// ====================================================================== + +// ------------------------------------------------------------------------------------------------------ +// Rule: Create +// +// ------------------------------------------------------------------------------------------------------ +struct Create : public STest::Rule { + // ---------------------------------------------------------------------- + // Construction + // ---------------------------------------------------------------------- + + //! Constructor + Create(); + + // ---------------------------------------------------------------------- + // Public member functions + // ---------------------------------------------------------------------- + + //! Precondition + bool precondition(const Os::Test::Queue::Tester& state //!< The test state + ); + + //! Action + void action(Os::Test::Queue::Tester& state //!< The test state + ); +}; + +// ------------------------------------------------------------------------------------------------------ +// Rule: SendNotFull +// +// ------------------------------------------------------------------------------------------------------ +struct SendNotFull : public STest::Rule { + // ---------------------------------------------------------------------- + // Construction + // ---------------------------------------------------------------------- + + //! Constructor + SendNotFull(); + + // ---------------------------------------------------------------------- + // Public member functions + // ---------------------------------------------------------------------- + + //! Precondition + bool precondition(const Os::Test::Queue::Tester& state //!< The test state + ); + + //! Action + void action(Os::Test::Queue::Tester& state //!< The test state + ); +}; + +// ------------------------------------------------------------------------------------------------------ +// Rule: SendFullNoBlock +// +// ------------------------------------------------------------------------------------------------------ +struct SendFullNoBlock : public STest::Rule { + // ---------------------------------------------------------------------- + // Construction + // ---------------------------------------------------------------------- + + //! Constructor + SendFullNoBlock(); + + // ---------------------------------------------------------------------- + // Public member functions + // ---------------------------------------------------------------------- + + //! Precondition + bool precondition(const Os::Test::Queue::Tester& state //!< The test state + ); + + //! Action + void action(Os::Test::Queue::Tester& state //!< The test state + ); +}; + +// ------------------------------------------------------------------------------------------------------ +// Rule: ReceiveNotEmpty +// +// ------------------------------------------------------------------------------------------------------ +struct ReceiveNotEmpty : public STest::Rule { + // ---------------------------------------------------------------------- + // Construction + // ---------------------------------------------------------------------- + + //! Constructor + ReceiveNotEmpty(); + + // ---------------------------------------------------------------------- + // Public member functions + // ---------------------------------------------------------------------- + + //! Precondition + bool precondition(const Os::Test::Queue::Tester& state //!< The test state + ); + + //! Action + void action(Os::Test::Queue::Tester& state //!< The test state + ); +}; + +// ------------------------------------------------------------------------------------------------------ +// Rule: ReceiveEmptyNoBlock +// +// ------------------------------------------------------------------------------------------------------ +struct ReceiveEmptyNoBlock : public STest::Rule { + // ---------------------------------------------------------------------- + // Construction + // ---------------------------------------------------------------------- + + //! Constructor + ReceiveEmptyNoBlock(); + + // ---------------------------------------------------------------------- + // Public member functions + // ---------------------------------------------------------------------- + + //! Precondition + bool precondition(const Os::Test::Queue::Tester& state //!< The test state + ); + + //! Action + void action(Os::Test::Queue::Tester& state //!< The test state + ); +}; + +// ------------------------------------------------------------------------------------------------------ +// Rule: Overflow +// +// ------------------------------------------------------------------------------------------------------ +struct Overflow : public STest::Rule { + // ---------------------------------------------------------------------- + // Construction + // ---------------------------------------------------------------------- + + //! Constructor + Overflow(); + + // ---------------------------------------------------------------------- + // Public member functions + // ---------------------------------------------------------------------- + + //! Precondition + bool precondition(const Os::Test::Queue::Tester& state //!< The test state + ); + + //! Action + void action(Os::Test::Queue::Tester& state //!< The test state + ); +}; + +// ------------------------------------------------------------------------------------------------------ +// Rule: Underflow +// +// ------------------------------------------------------------------------------------------------------ +struct Underflow : public STest::Rule { + // ---------------------------------------------------------------------- + // Construction + // ---------------------------------------------------------------------- + + //! Constructor + Underflow(); + + // ---------------------------------------------------------------------- + // Public member functions + // ---------------------------------------------------------------------- + + //! Precondition + bool precondition(const Os::Test::Queue::Tester& state //!< The test state + ); + + //! Action + void action(Os::Test::Queue::Tester& state //!< The test state + ); +}; + +// ------------------------------------------------------------------------------------------------------ +// Rule: SendBlock +// +// ------------------------------------------------------------------------------------------------------ +struct SendBlock : public ConcurrentRule { + // ---------------------------------------------------------------------- + // Construction + // ---------------------------------------------------------------------- + + //! Constructor + SendBlock(AggregatedConcurrentRule& runner); + + // ---------------------------------------------------------------------- + // Public member functions + // ---------------------------------------------------------------------- + + //! Precondition + bool precondition(const Os::Test::Queue::Tester& state //!< The test state + ) override; + + //! Action + void action(Os::Test::Queue::Tester& state //!< The test state + ) override; +}; +// ------------------------------------------------------------------------------------------------------ +// Rule: SendUnblock +// +// ------------------------------------------------------------------------------------------------------ +struct SendUnblock : public ConcurrentRule { + // ---------------------------------------------------------------------- + // Construction + // ---------------------------------------------------------------------- + + //! Constructor + SendUnblock(AggregatedConcurrentRule& runner); + + // ---------------------------------------------------------------------- + // Public member functions + // ---------------------------------------------------------------------- + + //! Precondition + bool precondition(const Os::Test::Queue::Tester& state //!< The test state + ) override; + + //! Action + void action(Os::Test::Queue::Tester& state //!< The test state + ) override; +}; + +// ------------------------------------------------------------------------------------------------------ +// Rule: ReceiveBlock +// +// ------------------------------------------------------------------------------------------------------ +struct ReceiveBlock : public ConcurrentRule { + // ---------------------------------------------------------------------- + // Construction + // ---------------------------------------------------------------------- + + //! Constructor + ReceiveBlock(AggregatedConcurrentRule& runner); + + // ---------------------------------------------------------------------- + // Public member functions + // ---------------------------------------------------------------------- + + //! Precondition + bool precondition(const Os::Test::Queue::Tester& state //!< The test state + ) override; + + //! Action + void action(Os::Test::Queue::Tester& state //!< The test state + ) override; +}; +// ------------------------------------------------------------------------------------------------------ +// Rule: ReceiveUnblock +// +// ------------------------------------------------------------------------------------------------------ +struct ReceiveUnblock : public ConcurrentRule { + // ---------------------------------------------------------------------- + // Construction + // ---------------------------------------------------------------------- + + //! Constructor + ReceiveUnblock(AggregatedConcurrentRule& runner); + + // ---------------------------------------------------------------------- + // Public member functions + // ---------------------------------------------------------------------- + + //! Precondition + bool precondition(const Os::Test::Queue::Tester& state //!< The test state + ) override; + + //! Action + void action(Os::Test::Queue::Tester& state //!< The test state + ) override; +}; \ No newline at end of file diff --git a/Os/test/ut/queue/RulesHeaders.hpp b/Os/test/ut/queue/RulesHeaders.hpp index 983b98aca3..043250c29d 100644 --- a/Os/test/ut/queue/RulesHeaders.hpp +++ b/Os/test/ut/queue/RulesHeaders.hpp @@ -1,16 +1,19 @@ +// ====================================================================== +// \title Os/test/ut/queue/RulesHeaders.cpp +// \brief queue test rules headers +// ====================================================================== +#ifndef OS_TEST_QUEUE_RULES_HEADERS__ +#define OS_TEST_QUEUE_RULES_HEADERS__ -#ifndef __RULES_HEADERS__ -#define __RULES_HEADERS__ - +#include +#include +#include "Os/Queue.hpp" +#include "Os/test/ConcurrentRule.hpp" #include "STest/Rule/Rule.hpp" #include "STest/Scenario/BoundedScenario.hpp" #include "STest/Scenario/RandomScenario.hpp" #include "STest/Scenario/Scenario.hpp" -#include "Os/Queue.hpp" -#include "Os/test/ConcurrentRule.hpp" -#include -#include #include "QueueRulesDefinitions.hpp" @@ -20,7 +23,7 @@ namespace Queue { constexpr FwSizeType DEPTH_BOUND = 100000; -struct Tester { +struct Tester { public: //! Constructor Tester() = default; @@ -33,13 +36,13 @@ struct Tester { }; struct ReceiveMessage { - U8* destination = nullptr; - FwQueuePriorityType* priority = nullptr; + U8* destination = nullptr; + FwQueuePriorityType* priority = nullptr; FwSizeType* size = nullptr; }; struct QueueMessageComparer { - bool operator()(const QueueMessage& a, const QueueMessage& b){ return HELPER(a.priority, b.priority);} + bool operator()(const QueueMessage& a, const QueueMessage& b) { return HELPER(a.priority, b.priority); } private: static const PriorityCompare HELPER; @@ -48,7 +51,7 @@ struct Tester { struct QueueState { FwSizeType depth = 0; FwSizeType messageSize = 0; - FwSizeType hwm = 0; + FwSizeType highMark = 0; static FwSizeType queues; QueueMessage send_block; ReceiveMessage receive_block; @@ -62,7 +65,7 @@ struct Tester { //! Shadow is created bool is_shadow_created() const { this->shadow_check(); - return this->shadow.created; + return this->shadow.created; } //! Shadow queue is full @@ -82,32 +85,35 @@ struct Tester { EXPECT_EQ(this->shadow.depth, this->queue.getDepth()); EXPECT_EQ(this->shadow.messageSize, this->queue.getMessageSize()); EXPECT_EQ(this->shadow.queue.size(), this->queue.getMessagesAvailable()); - EXPECT_EQ(this->shadow.hwm, this->queue.getMessageHighWaterMark()); + EXPECT_EQ(this->shadow.highMark, this->queue.getMessageHighWaterMark()); } Os::QueueInterface::Status shadow_create(FwSizeType depth, FwSizeType messageSize); //! Must be called before the queue send - Os::QueueInterface::Status shadow_send(const U8* buffer, FwSizeType size, FwQueuePriorityType priority, Os::QueueInterface::BlockingType blockType); + Os::QueueInterface::Status shadow_send(const U8* buffer, + FwSizeType size, + FwQueuePriorityType priority, + Os::QueueInterface::BlockingType blockType); //! Complete a previous blocking queue send void shadow_send_unblock(); //! Must be called before the queue receive - Os::QueueInterface::Status shadow_receive(U8* destination, + Os::QueueInterface::Status shadow_receive(U8* destination, FwSizeType capacity, QueueInterface::BlockingType blockType, FwSizeType& actualSize, FwQueuePriorityType& priority); //! Complete a previous blocking queue receive void shadow_receive_unblock(); + public: #include "QueueRules.hpp" }; -} -} -} - +} // namespace Queue +} // namespace Test +} // namespace Os #endif