Make Os::Queues use Fw::MemAllocator pattern for memory (#4451)

* Queues use MemAllocator pattern

* Derive queue allocation from MallocRegistry

* Formatting

* Fix UTs

* Fix CI

* Fix alignment in UT

* Formatting and sp

* Formatting, bad header

* More formatting

* Add queue teardown

* Deinit components

* Fix priority queue test

* Fix bug in priority queue allocation

* Correct comments

* Fix FppTest and Ref UTs

* Fix max heap teardown

* Fix review comment on max heap

* Fix null -> nullptr
This commit is contained in:
M Starch 2025-12-02 17:36:15 -08:00 committed by GitHub
parent 89a9e3247b
commit cddf38bb6f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
87 changed files with 574 additions and 181 deletions

View File

@ -27,7 +27,9 @@ ActiveTestTester ::ActiveTestTester()
this->component.registerExternalParameters(&this->paramTesterDelegate);
}
ActiveTestTester ::~ActiveTestTester() {}
ActiveTestTester ::~ActiveTestTester() {
this->component.deinit();
}
void ActiveTestTester ::initComponents() {
this->init();

View File

@ -27,7 +27,9 @@ QueuedTestTester ::QueuedTestTester()
this->component.registerExternalParameters(&this->paramTesterDelegate);
}
QueuedTestTester ::~QueuedTestTester() {}
QueuedTestTester ::~QueuedTestTester() {
this->component.deinit();
}
void QueuedTestTester ::initComponents() {
this->init();

View File

@ -56,7 +56,9 @@ DpTestTester::DpTestTester()
generateRandomString(this->stringRecordData);
}
DpTestTester::~DpTestTester() {}
DpTestTester::~DpTestTester() {
this->component.deinit();
}
// ----------------------------------------------------------------------
// Tests

View File

@ -22,7 +22,9 @@ SmTestTester::SmTestTester() : SmTestGTestBase("SmTestTester", SmTestTester::MAX
this->component.setIdBase(ID_BASE);
}
SmTestTester::~SmTestTester() {}
SmTestTester::~SmTestTester() {
this->component.deinit();
}
// ----------------------------------------------------------------------
// Tests

View File

@ -26,7 +26,9 @@ BasicTester::BasicTester(const char* const compName)
m_smChoiceBasic_action_b_history(),
m_smChoiceBasic_guard_g() {}
BasicTester::~BasicTester() {}
BasicTester::~BasicTester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Handler implementations for typed input ports

View File

@ -23,7 +23,9 @@ BasicU32Tester ::BasicU32Tester(const char* const compName)
m_smChoiceBasicU32_action_b_history(),
m_smChoiceBasicU32_guard_g() {}
BasicU32Tester ::~BasicU32Tester() {}
BasicU32Tester ::~BasicU32Tester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Implementations for internal state machine actions

View File

@ -23,7 +23,9 @@ ChoiceToChoiceTester ::ChoiceToChoiceTester(const char* const compName)
m_smChoiceChoiceToChoice_guard_g1(),
m_smChoiceChoiceToChoice_guard_g2() {}
ChoiceToChoiceTester ::~ChoiceToChoiceTester() {}
ChoiceToChoiceTester ::~ChoiceToChoiceTester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Implementations for internal state machine actions

View File

@ -22,7 +22,9 @@ ChoiceToStateTester::ChoiceToStateTester(const char* const compName)
m_smChoiceChoiceToState_actionHistory(),
m_smChoiceChoiceToState_guard_g() {}
ChoiceToStateTester::~ChoiceToStateTester() {}
ChoiceToStateTester::~ChoiceToStateTester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Implementations for internal state machine actions

View File

@ -22,7 +22,9 @@ InputPairU16U32Tester ::InputPairU16U32Tester(const char* const compName)
m_smChoiceInputPairU16U32_action_a_history(),
m_smChoiceInputPairU16U32_guard_g() {}
InputPairU16U32Tester ::~InputPairU16U32Tester() {}
InputPairU16U32Tester ::~InputPairU16U32Tester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Implementations for internal state machine actions

View File

@ -24,7 +24,9 @@ SequenceTester ::SequenceTester(const char* const compName)
m_smChoiceSequence_guard_g1(),
m_smChoiceSequence_guard_g2() {}
SequenceTester ::~SequenceTester() {}
SequenceTester ::~SequenceTester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Implementations for internal state machine actions

View File

@ -24,7 +24,9 @@ SequenceU32Tester::SequenceU32Tester(const char* const compName)
m_smChoiceSequenceU32_guard_g1(),
m_smChoiceSequenceU32_guard_g2() {}
SequenceU32Tester::~SequenceU32Tester() {}
SequenceU32Tester::~SequenceU32Tester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Implementations for internal state machine actions

View File

@ -19,7 +19,9 @@ namespace SmInstanceInitial {
BasicTester::BasicTester(const char* const compName)
: BasicComponentBase(compName), m_basic1_action_a_history(), m_smInitialBasic1_action_a_history() {}
BasicTester::~BasicTester() {}
BasicTester::~BasicTester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Handler implementations for typed input ports

View File

@ -24,7 +24,9 @@ ChoiceTester::ChoiceTester(const char* const compName)
m_choice_guard_g(),
m_smInitialChoice_guard_g() {}
ChoiceTester::~ChoiceTester() {}
ChoiceTester::~ChoiceTester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Implementations for internal state machine actions

View File

@ -19,7 +19,9 @@ namespace SmInstanceInitial {
NestedTester::NestedTester(const char* const compName)
: NestedComponentBase(compName), m_nested_action_a_history(), m_smInitialNested_action_a_history() {}
NestedTester::~NestedTester() {}
NestedTester::~NestedTester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Implementations for internal state machine actions

View File

@ -23,7 +23,9 @@ BasicGuardStringTester ::BasicGuardStringTester(const char* const compName)
m_smStateBasicGuardString_action_a_history(),
m_smStateBasicGuardString_guard_g() {}
BasicGuardStringTester ::~BasicGuardStringTester() {}
BasicGuardStringTester ::~BasicGuardStringTester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Implementations for internal state machine actions

View File

@ -23,7 +23,9 @@ BasicGuardTestAbsTypeTester::BasicGuardTestAbsTypeTester(const char* const compN
m_smStateBasicGuardTestAbsType_action_a_history(),
m_smStateBasicGuardTestAbsType_guard_g() {}
BasicGuardTestAbsTypeTester::~BasicGuardTestAbsTypeTester() {}
BasicGuardTestAbsTypeTester::~BasicGuardTestAbsTypeTester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Implementations for internal state machine actions

View File

@ -22,7 +22,9 @@ BasicGuardTestArrayTester::BasicGuardTestArrayTester(const char* const compName)
m_smStateBasicGuardTestArray_action_a_history(),
m_smStateBasicGuardTestArray_guard_g() {}
BasicGuardTestArrayTester::~BasicGuardTestArrayTester() {}
BasicGuardTestArrayTester::~BasicGuardTestArrayTester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Implementations for internal state machine actions

View File

@ -22,7 +22,9 @@ BasicGuardTestEnumTester::BasicGuardTestEnumTester(const char* const compName)
m_smStateBasicGuardTestEnum_action_a_history(),
m_smStateBasicGuardTestEnum_guard_g() {}
BasicGuardTestEnumTester::~BasicGuardTestEnumTester() {}
BasicGuardTestEnumTester::~BasicGuardTestEnumTester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Implementations for internal state machine actions

View File

@ -22,7 +22,9 @@ BasicGuardTestStructTester::BasicGuardTestStructTester(const char* const compNam
m_smStateBasicGuardTestStruct_action_a_history(),
m_smStateBasicGuardTestStruct_guard_g() {}
BasicGuardTestStructTester::~BasicGuardTestStructTester() {}
BasicGuardTestStructTester::~BasicGuardTestStructTester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Implementations for internal state machine actions

View File

@ -20,7 +20,9 @@ namespace SmInstanceState {
BasicGuardTester ::BasicGuardTester(const char* const compName)
: BasicGuardComponentBase(compName), m_smStateBasicGuard_action_a_history(), m_smStateBasicGuard_guard_g() {}
BasicGuardTester ::~BasicGuardTester() {}
BasicGuardTester ::~BasicGuardTester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Implementations for internal state machine actions

View File

@ -22,7 +22,9 @@ BasicGuardU32Tester::BasicGuardU32Tester(const char* const compName)
m_smStateBasicGuardU32_action_a_history(),
m_smStateBasicGuardU32_guard_g() {}
BasicGuardU32Tester::~BasicGuardU32Tester() {}
BasicGuardU32Tester::~BasicGuardU32Tester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Implementations for internal state machine actions

View File

@ -19,7 +19,9 @@ namespace SmInstanceState {
BasicInternalTester::BasicInternalTester(const char* const compName)
: BasicInternalComponentBase(compName), m_smStateBasicInternal_action_a_history() {}
BasicInternalTester::~BasicInternalTester() {}
BasicInternalTester::~BasicInternalTester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Implementations for internal state machine actions

View File

@ -19,7 +19,9 @@ namespace SmInstanceState {
BasicSelfTester::BasicSelfTester(const char* const compName)
: BasicSelfComponentBase(compName), m_smStateBasicSelf_action_a_history() {}
BasicSelfTester::~BasicSelfTester() {}
BasicSelfTester::~BasicSelfTester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Implementations for internal state machine actions

View File

@ -22,7 +22,9 @@ BasicStringTester ::BasicStringTester(const char* const compName)
m_smStateBasicString_action_a_history(),
m_smStateBasicString_action_b_history() {}
BasicStringTester ::~BasicStringTester() {}
BasicStringTester ::~BasicStringTester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Implementations for internal state machine actions

View File

@ -21,7 +21,9 @@ BasicTestAbsTypeTester ::BasicTestAbsTypeTester(const char* const compName)
m_smStateBasicTestAbsType_action_a_history(),
m_smStateBasicTestAbsType_action_b_history() {}
BasicTestAbsTypeTester ::~BasicTestAbsTypeTester() {}
BasicTestAbsTypeTester ::~BasicTestAbsTypeTester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Implementations for internal state machine actions

View File

@ -21,7 +21,9 @@ BasicTestArrayTester::BasicTestArrayTester(const char* const compName)
m_smStateBasicTestArray_action_a_history(),
m_smStateBasicTestArray_action_b_history() {}
BasicTestArrayTester::~BasicTestArrayTester() {}
BasicTestArrayTester::~BasicTestArrayTester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Implementations for internal state machine actions

View File

@ -21,7 +21,9 @@ BasicTestEnumTester::BasicTestEnumTester(const char* const compName)
m_smStateBasicTestEnum_action_a_history(),
m_smStateBasicTestEnum_action_b_history() {}
BasicTestEnumTester::~BasicTestEnumTester() {}
BasicTestEnumTester::~BasicTestEnumTester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Implementations for internal state machine actions

View File

@ -21,7 +21,9 @@ BasicTestStructTester::BasicTestStructTester(const char* const compName)
m_smStateBasicTestStruct_action_a_history(),
m_smStateBasicTestStruct_action_b_history() {}
BasicTestStructTester::~BasicTestStructTester() {}
BasicTestStructTester::~BasicTestStructTester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Implementations for internal state machine actions

View File

@ -19,7 +19,9 @@ namespace SmInstanceState {
BasicTester ::BasicTester(const char* const compName)
: BasicComponentBase(compName), m_basic1_action_a_history(), m_smStateBasic1_action_a_history() {}
BasicTester ::~BasicTester() {}
BasicTester ::~BasicTester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Handler implementations for typed input ports

View File

@ -19,7 +19,9 @@ namespace SmInstanceState {
BasicU32Tester::BasicU32Tester(const char* const compName)
: BasicU32ComponentBase(compName), m_smStateBasicU32_action_a_history(), m_smStateBasicU32_action_b_history() {}
BasicU32Tester::~BasicU32Tester() {}
BasicU32Tester::~BasicU32Tester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Implementations for internal state machine actions

View File

@ -19,7 +19,9 @@ namespace SmInstanceState {
InternalTester::InternalTester(const char* const compName)
: InternalComponentBase(compName), m_smStateInternal_action_a_history() {}
InternalTester::~InternalTester() {}
InternalTester::~InternalTester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Implementations for internal state machine actions

View File

@ -18,7 +18,9 @@ namespace SmInstanceState {
PolymorphismTester::PolymorphismTester(const char* const compName) : PolymorphismComponentBase(compName) {}
PolymorphismTester::~PolymorphismTester() {}
PolymorphismTester::~PolymorphismTester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Tests

View File

@ -19,7 +19,9 @@ namespace SmInstanceState {
StateToChildTester::StateToChildTester(const char* const compName)
: StateToChildComponentBase(compName), m_smStateStateToChild_actionHistory() {}
StateToChildTester::~StateToChildTester() {}
StateToChildTester::~StateToChildTester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Implementations for internal state machine actions

View File

@ -20,7 +20,9 @@ namespace SmInstanceState {
StateToChoiceTester::StateToChoiceTester(const char* const compName)
: StateToChoiceComponentBase(compName), m_smStateStateToChoice_actionHistory(), m_smStateStateToChoice_guard_g() {}
StateToChoiceTester::~StateToChoiceTester() {}
StateToChoiceTester::~StateToChoiceTester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Implementations for internal state machine actions

View File

@ -19,7 +19,9 @@ namespace SmInstanceState {
StateToSelfTester::StateToSelfTester(const char* const compName)
: StateToSelfComponentBase(compName), m_smStateStateToSelf_actionHistory() {}
StateToSelfTester::~StateToSelfTester() {}
StateToSelfTester::~StateToSelfTester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Implementations for internal state machine actions

View File

@ -19,7 +19,9 @@ namespace SmInstanceState {
StateToStateTester::StateToStateTester(const char* const compName)
: StateToStateComponentBase(compName), m_smStateStateToState_actionHistory() {}
StateToStateTester::~StateToStateTester() {}
StateToStateTester::~StateToStateTester() {
this->deinit();
}
// ----------------------------------------------------------------------
// Implementations for internal state machine actions

View File

@ -15,6 +15,10 @@ void QueuedComponentBase::init(FwEnumStoreType instance) {
PassiveComponentBase::init(instance);
}
void QueuedComponentBase::deinit() {
this->m_queue.teardown();
}
#if FW_OBJECT_TO_STRING == 1
const char* QueuedComponentBase::getToStringFormatString() {
return "QueueComp: %s";
@ -28,7 +32,7 @@ Os::Queue::Queue::Status QueuedComponentBase::createQueue(FwSizeType depth, FwSi
#else
queueName.format("CompQ_%" PRI_FwSizeType, Os::Queue::getNumQueues());
#endif
return this->m_queue.create(queueName, depth, msgSize);
return this->m_queue.create(this->getInstance(), queueName, depth, msgSize);
}
FwSizeType QueuedComponentBase::getNumMsgsDropped() {

View File

@ -31,6 +31,7 @@ class QueuedComponentBase : public PassiveComponentBase {
QueuedComponentBase(const char* name); //!< Constructor
virtual ~QueuedComponentBase(); //!< Destructor
void init(FwEnumStoreType instance); //!< initialization function
void deinit(); //!< Allows de-initialization on teardown
Os::Queue m_queue; //!< queue object for active component
Os::Queue::Status createQueue(FwSizeType depth, FwSizeType msgSize);
virtual MsgDispatchStatus doDispatch() = 0; //!< method to dispatch a single message in the queue.

70
Fw/LanguageHelpers.hpp Normal file
View File

@ -0,0 +1,70 @@
// ======================================================================
// \title LanguageHelpers.hpp
// \author lestarch
// \brief hpp file for C++ language helper functions
//
// \copyright
// Copyright (C) 2025 California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship
// acknowledged.
// ======================================================================
#ifndef FW_TYPES_LANGUAGE_HELPERS_HPP_
#define FW_TYPES_LANGUAGE_HELPERS_HPP_
#include <new>
#include <type_traits>
#include "Fw/Types/Assert.hpp"
#include "Fw/Types/ByteArray.hpp"
namespace Fw {
//! \brief placement new for arrays
//!
//! C++ as a language does not guaranteed that placement new for a C++ array of length N will fit within a memory
//! region of size N *sizeof(T). Moreover, there are some compilers whose implementation of placement new for arrays
//! do not guarantee this property.
//!
//! This function provides a helper for placement new for arrays that guarantees that the array will fit within the
//! provided memory region. It checks that the provided memory region is large enough to hold the array (N * sizeof(T)
//! and that the alignment of the provided memory region is sufficient for the type T. It also checks that the provided
//! memory region is non-null.
//!
//! \warning this function cannot be used for arrays of arrays (i.e. T cannot be an array type).
//!
//! \tparam T the type of the array elements
//! \param array the byte array to use for placement new (pair of bytes pointer and size)
//! \param arraySize the number of elements in the array
//! \return a pointer to the array of type T
template <typename T>
T* arrayPlacementNew(Fw::ByteArray array, FwSizeType arraySize) {
static_assert(!std::is_array<T>::value, "Cannot use arrayPlacementNew new for arrays of arrays");
static_assert(std::is_constructible<T>::value,
"Cannot use arrayPlacementNew on types without a default zero-argument constructor");
void* base_pointer = reinterpret_cast<void*>(array.bytes);
FW_ASSERT(base_pointer != nullptr);
FW_ASSERT((reinterpret_cast<PlatformPointerCastType>(base_pointer) % alignof(T)) == 0);
FW_ASSERT(array.size >= (sizeof(T) * arraySize));
T* type_pointer = static_cast<T*>(base_pointer);
for (FwSizeType index = 0; index < arraySize; index++) {
new (&type_pointer[index]) T();
}
return type_pointer;
}
//! \brief placement delete for arrays
//!
//! This is the partner of tha above function that performs the destructor operation on every element of type T in the
//! array. This assumes that all elements have been constructed.
//!
//! \warning this function cannot be used for arrays of arrays (i.e. T cannot be an array type).
//!
//! \tparam T the type of the array elements
//! \param arrayPointer pointer to an array of type T
//! \param arraySize the number of elements in the array
template <typename T>
void arrayPlacementDestruct(T* arrayPointer, FwSizeType arraySize) {
static_assert(!std::is_array<T>::value, "Cannot use arrayPlacementDestruct new for arrays of arrays");
FW_ASSERT(arrayPointer != nullptr);
for (FwSizeType index = 0; index < arraySize; index++) {
arrayPointer[index].~T();
}
}
} // namespace Fw
#endif // FW_TYPES_LANGUAGE_HELPERS_HPP_

View File

@ -33,7 +33,7 @@ class MallocAllocator : public MemAllocator {
//! Allocate memory using malloc(). The identifier is unused and memory is never recoverable.
//! malloc() guarantees alignment for any type and so does this allocator. It will not respect smaller alignments.
//!
//! \param identifier the memory segment identifier (not used)
//! \param identifier the allocating entity identifier (not used)
//! \param size the requested size (not changed)
//! \param recoverable - flag to indicate the memory could be recoverable (always set to false)
//! \param alignment - alignment requirement for the allocation. Default: maximum alignment defined by C++.

View File

@ -6,11 +6,10 @@
*/
#include <Fw/Types/Assert.hpp>
#include <Fw/Types/MemAllocator.hpp>
#include <config/MemoryAllocation.hpp>
#include <type_traits>
namespace Fw {
MemAllocatorRegistry* MemAllocatorRegistry::s_registry = nullptr; //!< singleton registry
MemAllocator::MemAllocator() {}
MemAllocator::~MemAllocator() {}
@ -36,9 +35,8 @@ void* MemAllocator ::checkedAllocate(const FwEnumStoreType identifier, FwSizeTyp
return this->checkedAllocate(identifier, size, unused, alignment);
}
MemAllocatorRegistry::MemAllocatorRegistry() {
// Register self as the singleton
MemAllocatorRegistry::s_registry = this;
MemAllocatorRegistry::MemAllocatorRegistry() : m_defaultAllocator(MemAllocatorRegistry::getDefaultAllocator()) {
this->registerAllocator(MemoryAllocation::MemoryAllocatorType::SYSTEM, m_defaultAllocator);
}
void MemAllocatorRegistry::registerAllocator(const MemoryAllocation::MemoryAllocatorType type,
@ -47,8 +45,8 @@ void MemAllocatorRegistry::registerAllocator(const MemoryAllocation::MemoryAlloc
}
MemAllocatorRegistry& MemAllocatorRegistry::getInstance() {
FW_ASSERT(s_registry != nullptr);
return *s_registry;
static MemAllocatorRegistry registry;
return registry;
}
MemAllocator& MemAllocatorRegistry::getAllocator(const MemoryAllocation::MemoryAllocatorType type) {
@ -63,4 +61,12 @@ MemAllocator& MemAllocatorRegistry::getAnAllocator(const MemoryAllocation::Memor
}
return *this->m_allocators[type];
}
MemAllocator& MemAllocatorRegistry::getDefaultAllocator() {
static_assert(std::is_constructible<MemoryAllocation::DefaultMemoryAllocatorType>::value,
"DefaultMemoryAllocatorType must be constructible without arguments");
static MemoryAllocation::DefaultMemoryAllocatorType defaultAllocator;
return defaultAllocator;
}
} /* namespace Fw */

View File

@ -55,7 +55,7 @@ class MemAllocator {
//! identifier is a unique identifier for the allocating entity. This entity (e.g. a component) may call allocate
//! multiple times with the same id, but no other entity in the system shall call allocate with that id.
//!
//! \param identifier the memory segment identifier, each identifier is to be used in once single allocation
//! \param identifier - a unique identifier for the allocating entity
//! \param size the requested size - changed to actual if different
//! \param recoverable - flag to indicate the memory could be recoverable
//! \param alignment - alignment requirement for the allocation. Default: maximum alignment defined by C++.
@ -70,7 +70,7 @@ class MemAllocator {
//! Deallocate memory previously allocated by allocate(). The pointer must be one returned by allocate() and the
//! identifier must match the one used in the original allocate() call.
//!
//! \param identifier the memory segment identifier, each identifier is to be used in once single allocation
//! \param identifier - a unique identifier for the allocating entity, must match the call to allocate()
//! \param ptr the pointer to memory returned by allocate()
virtual void deallocate(const FwEnumStoreType identifier, void* ptr) = 0;
@ -80,7 +80,7 @@ class MemAllocator {
//! by the underlying allocator but is not returned to the caller. This is for cases when the caller does not care
//! about recoverability of memory.
//!
//! \param identifier the memory segment identifier, each identifier is to be used in once single allocation
//! \param identifier - a unique identifier for the allocating entity
//! \param size the requested size - changed to actual if different
//! \param alignment - alignment requirement for the allocation. Default: maximum alignment defined by C++.
//! \return the pointer to memory. Zero if unable to allocate
@ -95,7 +95,7 @@ class MemAllocator {
//!
//! Allocations are checked using FW_ASSERT implying that an allocation failure results in a tripped assertion.
//!
//! \param identifier the memory segment identifier, each identifier is to be used in once single allocation
//! \param identifier - a unique identifier for the allocating entity
//! \param size the requested size, actual allocation will be at least this size
//! \param recoverable - flag to indicate the memory could be recoverable
//! \param alignment - alignment requirement for the allocation. Default: maximum alignment defined by C++.
@ -114,7 +114,7 @@ class MemAllocator {
//!
//! Allocations are checked using FW_ASSERT implying that an allocation failure results in a tripped assertion.
//!
//! \param identifier the memory segment identifier, each identifier is to be used in once single allocation
//! \param identifier - a unique identifier for the allocating entity
//! \param size the requested size, actual allocation will be at least this size
//! \param alignment - alignment requirement for the allocation. Default: maximum alignment defined by C++.
//! \return the pointer to memory. Zero if unable to allocate
@ -132,11 +132,12 @@ class MemAllocator {
};
class MemAllocatorRegistry {
public:
private:
// Constructor which will register itself as the singleton
MemAllocatorRegistry();
~MemAllocatorRegistry() = default;
public:
//! \brief get the singleton registry
//!
//! \return the singleton registry
@ -169,11 +170,17 @@ class MemAllocatorRegistry {
MemAllocator& getAnAllocator(const MemoryAllocation::MemoryAllocatorType type);
private:
//! \brief get the default allocator
//!
//! Creates a single instance of the default allocator and returns a reference to it. This is done to ensure that
//! the default allocator is only created once and is available when ill-ordered static initialization occurs.
//!
//! \return the default allocator
static MemAllocator& getDefaultAllocator();
//! Array of allocators for each type defaulted to nullptr
MemAllocator* m_allocators[MemoryAllocation::MemoryAllocatorType::NUM_CONSTANTS] = {nullptr};
//! The singleton registry pointer
static MemAllocatorRegistry* s_registry; //!< singleton registry
MemAllocator& m_defaultAllocator; //!< default allocator
};
} /* namespace Fw */

View File

@ -2,11 +2,12 @@
// \title Os/Generic/PriorityQueue.cpp
// \brief priority queue implementation for Os::Queue
// ======================================================================
#include "PriorityQueue.hpp"
#include <Fw/Types/Assert.hpp>
#include "Os/Generic/PriorityQueue.hpp"
#include <cstring>
#include <new>
#include "Fw/LanguageHelpers.hpp"
#include "Fw/Types/Assert.hpp"
#include "Fw/Types/MemAllocator.hpp"
#include "config/MemoryAllocatorTypeEnumAc.hpp"
namespace Os {
namespace Generic {
@ -38,62 +39,137 @@ void PriorityQueueHandle ::load_data(FwSizeType index, U8* destination, FwSizeTy
(void)::memcpy(destination, this->m_data + offset, static_cast<size_t>(size));
}
PriorityQueue::~PriorityQueue() {
delete[] this->m_handle.m_data;
delete[] this->m_handle.m_indices;
delete[] this->m_handle.m_sizes;
}
PriorityQueue::~PriorityQueue() {}
QueueInterface::Status PriorityQueue::create(const Fw::ConstStringBase& name,
QueueInterface::Status PriorityQueue::create(FwEnumStoreType id,
const Fw::ConstStringBase& name,
FwSizeType depth,
FwSizeType messageSize) {
const FwEnumStoreType identifier = id;
QueueInterface::Status status = Os::QueueInterface::Status::OP_OK;
// Ensure we are created exactly once
FW_ASSERT(this->m_handle.m_indices == nullptr);
FW_ASSERT(this->m_handle.m_sizes == nullptr);
FW_ASSERT(this->m_handle.m_data == nullptr);
// Allocate indices list
FwSizeType* indices = new (std::nothrow) FwSizeType[depth];
if (indices == nullptr) {
return QueueInterface::Status::ALLOCATION_FAILED;
}
// Allocate sizes list or clean-up
FwSizeType* sizes = new (std::nothrow) FwSizeType[depth];
if (sizes == nullptr) {
delete[] indices;
return QueueInterface::Status::ALLOCATION_FAILED;
}
// Allocate sizes list or clean-up
U8* data = new (std::nothrow) U8[depth * messageSize];
if (data == nullptr) {
delete[] indices;
delete[] sizes;
return QueueInterface::Status::ALLOCATION_FAILED;
}
// Allocate max heap or clean-up
bool created = this->m_handle.m_heap.create(depth);
if (not created) {
delete[] indices;
delete[] sizes;
delete[] data;
return QueueInterface::Status::ALLOCATION_FAILED;
}
// 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;
this->m_handle.m_sizes = sizes;
this->m_handle.m_startIndex = 0;
this->m_handle.m_stopIndex = 0;
this->m_handle.m_depth = depth;
this->m_handle.m_highMark = 0;
// Get the memory allocator configured for priority queues
Fw::MemAllocator& allocator = Fw::MemAllocatorRegistry::getInstance().getAnAllocator(
Fw::MemoryAllocation::MemoryAllocatorType::OS_GENERIC_PRIORITY_QUEUE);
return QueueInterface::Status::OP_OK;
// Allocate indices list
void* allocation = nullptr;
FwSizeType size = 0;
FwSizeType* indices = nullptr;
FwSizeType* sizes = nullptr;
U8* data = nullptr;
U8* heap_pointer = nullptr;
// Allocate indices list and construct it when valid
size = depth * sizeof(FwSizeType);
allocation = allocator.allocate(identifier, size, alignof(FwSizeType));
if (allocation == nullptr) {
status = QueueInterface::Status::ALLOCATION_FAILED;
} else if (size < (depth * sizeof(FwSizeType))) {
allocator.deallocate(identifier, allocation);
status = QueueInterface::Status::ALLOCATION_FAILED;
} else {
indices = Fw::arrayPlacementNew<FwSizeType>(Fw::ByteArray(static_cast<U8*>(allocation), size), depth);
}
// Allocate sizes list and construct it when valid
if (status == QueueInterface::Status::OP_OK) {
size = depth * sizeof(FwSizeType);
allocation = allocator.allocate(identifier, size, alignof(FwSizeType));
if (allocation == nullptr) {
allocator.deallocate(identifier, indices);
status = QueueInterface::Status::ALLOCATION_FAILED;
} else if (size < (depth * sizeof(FwSizeType))) {
allocator.deallocate(identifier, indices);
allocator.deallocate(identifier, allocation);
status = QueueInterface::Status::ALLOCATION_FAILED;
} else {
sizes = Fw::arrayPlacementNew<FwSizeType>(Fw::ByteArray(static_cast<U8*>(allocation), size), depth);
}
}
// Allocate data
if (status == QueueInterface::Status::OP_OK) {
size = depth * messageSize;
allocation = allocator.allocate(identifier, size, alignof(U8));
if (allocation == nullptr) {
allocator.deallocate(identifier, indices);
allocator.deallocate(identifier, sizes);
status = QueueInterface::Status::ALLOCATION_FAILED;
} else if (size < (depth * messageSize)) {
allocator.deallocate(identifier, indices);
allocator.deallocate(identifier, sizes);
allocator.deallocate(identifier, allocation);
status = QueueInterface::Status::ALLOCATION_FAILED;
} else {
data = static_cast<U8*>(allocation);
}
}
// Allocate data for max heap
if (status == QueueInterface::Status::OP_OK) {
size = Types::MaxHeap::ELEMENT_SIZE * depth;
allocation = allocator.allocate(identifier, size, Types::MaxHeap::ALIGNMENT);
if (allocation == nullptr) {
allocator.deallocate(identifier, indices);
allocator.deallocate(identifier, sizes);
allocator.deallocate(identifier, data);
status = QueueInterface::Status::ALLOCATION_FAILED;
} else if (size < (Types::MaxHeap::ELEMENT_SIZE * depth)) {
allocator.deallocate(identifier, indices);
allocator.deallocate(identifier, sizes);
allocator.deallocate(identifier, data);
allocator.deallocate(identifier, allocation);
status = QueueInterface::Status::ALLOCATION_FAILED;
} else {
heap_pointer = static_cast<U8*>(allocation);
this->m_handle.m_heap.create(depth, Fw::ByteArray(static_cast<U8*>(allocation), size));
}
}
// Set up structures when all allocations succeeded
if (status == QueueInterface::Status::OP_OK) {
// 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_id = id;
this->m_handle.m_maxSize = messageSize;
this->m_handle.m_indices = indices;
this->m_handle.m_data = data;
this->m_handle.m_sizes = sizes;
this->m_handle.m_heap_pointer = heap_pointer;
this->m_handle.m_startIndex = 0;
this->m_handle.m_stopIndex = 0;
this->m_handle.m_depth = depth;
this->m_handle.m_highMark = 0;
}
return status;
}
void PriorityQueue::teardown() {
this->teardownInternal();
}
void PriorityQueue::teardownInternal() {
if (this->m_handle.m_data != nullptr) {
const FwEnumStoreType identifier = this->m_handle.m_id;
Fw::MemAllocator& allocator = Fw::MemAllocatorRegistry::getInstance().getAnAllocator(
Fw::MemoryAllocation::MemoryAllocatorType::OS_GENERIC_PRIORITY_QUEUE);
allocator.deallocate(identifier, this->m_handle.m_data);
allocator.deallocate(identifier, this->m_handle.m_indices);
allocator.deallocate(identifier, this->m_handle.m_sizes);
this->m_handle.m_heap.teardown();
allocator.deallocate(identifier, this->m_handle.m_heap_pointer);
// Set these pointers to nullptr
this->m_handle.m_data = nullptr;
this->m_handle.m_indices = nullptr;
this->m_handle.m_sizes = nullptr;
}
}
QueueInterface::Status PriorityQueue::send(const U8* buffer,

View File

@ -20,6 +20,7 @@ namespace Generic {
//! the data region and index list have queue depth number of entries.
struct PriorityQueueHandle : public QueueHandle {
Types::MaxHeap m_heap; //!< MaxHeap data store for tracking priority
U8* m_heap_pointer; //!< Pointer to the MaxHeap data store
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
@ -31,6 +32,7 @@ struct PriorityQueueHandle : public QueueHandle {
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
FwEnumStoreType m_id; //!< Identifier for the queue, used for memory allocation
//!\brief find an available index to store data from the list
FwSizeType find_index();
@ -74,13 +76,31 @@ class PriorityQueue : public Os::QueueInterface {
//!
//! Creates a queue ensuring sufficient storage to hold `depth` messages of `messageSize` size each.
//!
//! \warning allocates memory on the heap
//! \warning allocates memory through the memory allocator registry
//!
//! \param id: identifier for the queue, used for memory allocation
//! \param name: name of queue
//! \param depth: depth of queue in number of messages
//! \param messageSize: size of an individual message
//! \return: status of the creation
Status create(const Fw::ConstStringBase& name, FwSizeType depth, FwSizeType messageSize) override;
Status create(FwEnumStoreType id,
const Fw::ConstStringBase& name,
FwSizeType depth,
FwSizeType messageSize) override;
//! \brief teardown the queue
//!
//! Allow for queues to deallocate resources as part of system shutdown. This delegates to the underlying queue
//! implementation.
void teardown() override;
//! \brief teardown the queue
//!
//! Allow for queues to deallocate resources as part of system shutdown. This delegates to the underlying queue
//! implementation.
//!
//! Note: this is a helper to allow this to be called from the destructor.
void teardownInternal();
//! \brief send a message into the queue
//!

View File

@ -17,10 +17,9 @@
#include "Os/Generic/Types/MaxHeap.hpp"
#include <Fw/FPrimeBasicTypes.hpp>
#include <Fw/Logger/Logger.hpp>
#include "Fw/Types/Assert.hpp"
#include <cstdio>
#include <new>
#include "Fw/LanguageHelpers.hpp"
#include "Fw/Types/Assert.hpp"
// Macros for traversing the heap:
#define LCHILD(x) (2 * x + 1)
@ -30,7 +29,6 @@
namespace Types {
MaxHeap::MaxHeap() {
// Initialize the heap:
this->m_capacity = 0;
this->m_heap = nullptr;
this->m_size = 0;
@ -38,20 +36,30 @@ MaxHeap::MaxHeap() {
}
MaxHeap::~MaxHeap() {
delete[] this->m_heap;
this->m_heap = nullptr;
}
bool MaxHeap::create(FwSizeType capacity) {
void MaxHeap::create(FwSizeType capacity, Fw::ByteArray heap_allocation) {
FW_ASSERT(this->m_heap == nullptr);
FW_ASSERT(heap_allocation.size >= (capacity * sizeof(Node)), static_cast<FwAssertArgType>(capacity),
static_cast<FwAssertArgType>(heap_allocation.size));
FW_ASSERT(heap_allocation.bytes != nullptr);
// Loop bounds will overflow if capacity set to the max allowable value
FW_ASSERT(capacity < std::numeric_limits<FwSizeType>::max());
this->m_heap = new (std::nothrow) Node[capacity];
if (nullptr == this->m_heap) {
return false;
}
this->m_heap = Fw::arrayPlacementNew<Node>(heap_allocation, capacity);
this->m_capacity = capacity;
return true;
}
void MaxHeap::teardown() {
// Only destroy the heap if it is still allocated
if (this->m_heap != nullptr) {
Fw::arrayPlacementDestruct<Node>(this->m_heap, this->m_capacity);
}
// Reset the capacity and heap so that the provider of memory
this->m_capacity = 0;
this->m_heap = nullptr;
this->m_size = 0;
this->m_order = 0;
}
bool MaxHeap::push(FwQueuePriorityType value, FwSizeType id) {

View File

@ -14,6 +14,7 @@
#define UTILS_TYPES_MAX_HEAP_HPP
#include <Fw/FPrimeBasicTypes.hpp>
#include <Fw/Types/ByteArray.hpp>
namespace Types {
@ -39,12 +40,13 @@ class MaxHeap {
~MaxHeap();
//! \brief MaxHeap creation
//!
//! Create the max heap with a given maximum size
//! \warning allocates memory on the heap
//!
//! Create the max heap with a given capacity. Constructs heap elements in the provided memory.
//! \param capacity the maximum number of elements to store in the heap
//! \param heap_allocation the memory to use for the heap
//!
bool create(FwSizeType capacity);
void create(FwSizeType capacity, Fw::ByteArray heap_allocation);
//! \brief MaxHeap teardown
void teardown();
//! \brief Push an item onto the heap.
//!
//! The item will be put into the heap according to its value. The
@ -105,6 +107,11 @@ class MaxHeap {
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
public:
//! Exposes the ELEMENT_SIZE for pre-allocation
static constexpr FwSizeType ELEMENT_SIZE = sizeof(Node);
//! Exposes the ALIGNMENT for pre-allocation
static constexpr FwSizeType ALIGNMENT = alignof(Node);
};
} // namespace Types

View File

@ -5,41 +5,37 @@
#define DEPTH 5
#define DATA_SIZE 3
#define BIG 100000
TEST(Nominal, Creation) {
bool ret;
alignas(Types::MaxHeap::ALIGNMENT) U8 heap_allocation[Types::MaxHeap::ELEMENT_SIZE * BIG];
{
Types::MaxHeap heap;
ret = heap.create(0);
ASSERT_TRUE(ret);
heap.create(0, Fw::ByteArray(heap_allocation, sizeof(heap_allocation)));
}
{
Types::MaxHeap heap;
ret = heap.create(1000000);
ASSERT_TRUE(ret);
heap.create(BIG, Fw::ByteArray(heap_allocation, sizeof(heap_allocation)));
}
{
Types::MaxHeap heap;
ret = heap.create(1);
ASSERT_TRUE(ret);
heap.create(1, Fw::ByteArray(heap_allocation, sizeof(heap_allocation)));
}
{
Types::MaxHeap heap;
ret = heap.create(DEPTH);
ASSERT_TRUE(ret);
heap.create(DEPTH, Fw::ByteArray(heap_allocation, sizeof(heap_allocation)));
}
{
Types::MaxHeap heap;
ret = heap.create(DEPTH);
ASSERT_TRUE(ret);
heap.create(DEPTH, Fw::ByteArray(heap_allocation, sizeof(heap_allocation)));
}
}
TEST(Nominal, Empty) {
bool ret;
alignas(Types::MaxHeap::ALIGNMENT) U8 heap_allocation[Types::MaxHeap::ELEMENT_SIZE * DEPTH];
Types::MaxHeap heap;
ret = heap.create(DEPTH);
ASSERT_TRUE(ret);
heap.create(DEPTH, Fw::ByteArray(heap_allocation, sizeof(heap_allocation)));
FwQueuePriorityType value;
FwSizeType id = 0;
@ -59,9 +55,9 @@ TEST(Nominal, Empty) {
TEST(Nominal, PushPop) {
printf("Creating heap.\n");
bool ret;
alignas(Types::MaxHeap::ALIGNMENT) U8 heap_allocation[Types::MaxHeap::ELEMENT_SIZE * DEPTH];
Types::MaxHeap heap;
ret = heap.create(DEPTH);
ASSERT_TRUE(ret);
heap.create(DEPTH, Fw::ByteArray(heap_allocation, sizeof(heap_allocation)));
FwQueuePriorityType value;
FwSizeType size;

View File

@ -19,7 +19,10 @@ Queue::~Queue() {
m_delegate.~QueueInterface();
}
QueueInterface::Status Queue ::create(const Fw::ConstStringBase& name, FwSizeType depth, FwSizeType messageSize) {
QueueInterface::Status Queue ::create(FwEnumStoreType id,
const Fw::ConstStringBase& name,
FwSizeType depth,
FwSizeType messageSize) {
FW_ASSERT(&this->m_delegate == reinterpret_cast<QueueInterface*>(&this->m_handle_storage[0]));
FW_ASSERT(depth > 0);
FW_ASSERT(messageSize > 0);
@ -27,7 +30,7 @@ QueueInterface::Status Queue ::create(const Fw::ConstStringBase& name, FwSizeTyp
if (this->m_depth > 0 || this->m_size > 0) {
return QueueInterface::Status::ALREADY_CREATED;
}
QueueInterface::Status status = this->m_delegate.create(name, depth, messageSize);
QueueInterface::Status status = this->m_delegate.create(id, name, depth, messageSize);
if (status == QueueInterface::Status::OP_OK) {
this->m_name = name;
this->m_depth = depth;
@ -43,6 +46,11 @@ QueueInterface::Status Queue ::create(const Fw::ConstStringBase& name, FwSizeTyp
return status;
}
void Queue::teardown() {
FW_ASSERT(&this->m_delegate == reinterpret_cast<QueueInterface*>(&this->m_handle_storage[0]));
return this->m_delegate.teardown();
}
QueueInterface::Status Queue::send(const U8* buffer,
FwSizeType size,
FwQueuePriorityType priority,

View File

@ -69,11 +69,23 @@ class QueueInterface {
//! allocation is dependent on the underlying implementation and users should assume that resource allocation is
//! possible.
//!
//! \param id: identifier for the queue, used for memory allocation
//! \param name: name of queue
//! \param depth: depth of queue in number of messages
//! \param messageSize: size of an individual message
//! \return: status of the creation
virtual Status create(const Fw::ConstStringBase& name, FwSizeType depth, FwSizeType messageSize) = 0;
virtual Status create(FwEnumStoreType id,
const Fw::ConstStringBase& name,
FwSizeType depth,
FwSizeType messageSize) = 0;
//! \brief teardown the queue
//!
//! Allow for queues to deallocate resources as part of system shutdown. This delegates to the underlying queue
//! implementation.
//!
//! Note: the default implementation does nothing.
virtual void teardown() {}
//! \brief send a message into the queue
//!
@ -179,7 +191,17 @@ class Queue final : public QueueInterface {
//! \param depth: depth of queue in number of messages
//! \param messageSize: size of an individual message
//! \return: status of the creation
Status create(const Fw::ConstStringBase& name, FwSizeType depth, FwSizeType messageSize) override;
Status create(FwEnumStoreType id,
const Fw::ConstStringBase& name,
FwSizeType depth,
FwSizeType messageSize) override;
//! \brief teardown the queue
//!
//! Allow for queues to deallocate resources as part of system shutdown. This delegates to the underlying queue
//! implementation.
//! implementation.
void teardown() override;
//! \brief send a message into the queue through delegate
//!

View File

@ -8,7 +8,10 @@ namespace Os {
namespace Stub {
namespace Queue {
QueueInterface::Status StubQueue::create(const Fw::ConstStringBase& name, FwSizeType depth, FwSizeType messageSize) {
QueueInterface::Status StubQueue::create(FwEnumStoreType id,
const Fw::ConstStringBase& name,
FwSizeType depth,
FwSizeType messageSize) {
return QueueInterface::Status::UNKNOWN_ERROR;
}

View File

@ -33,11 +33,15 @@ class StubQueue : public QueueInterface {
//! \brief create queue storage
//!
//! Creates a queue ensuring sufficient storage to hold `depth` messages of `messageSize` size each.
//! \param id: identifier of queue
//! \param name: name of queue
//! \param depth: depth of queue in number of messages
//! \param messageSize: size of an individual message
//! \return: status of the creation
Status create(const Fw::ConstStringBase& name, FwSizeType depth, FwSizeType messageSize) override;
Status create(FwEnumStoreType id,
const Fw::ConstStringBase& name,
FwSizeType depth,
FwSizeType messageSize) override;
//! \brief send a message into the queue
//!

View File

@ -32,7 +32,8 @@ InjectableStlQueue::~InjectableStlQueue() {
StaticData::data.lastCalled = StaticData::LastFn::DESTRUCT_FN;
}
QueueInterface::Status InjectableStlQueue::create(const Fw::ConstStringBase& name,
QueueInterface::Status InjectableStlQueue::create(FwEnumStoreType id,
const Fw::ConstStringBase& name,
FwSizeType depth,
FwSizeType messageSize) {
StaticData::data.lastCalled = StaticData::LastFn::CREATE_FN;

View File

@ -107,11 +107,15 @@ class InjectableStlQueue : public QueueInterface {
//! \brief create queue storage
//!
//! Creates a queue ensuring sufficient storage to hold `depth` messages of `messageSize` size each.
//! \param id: identifier of queue
//! \param name: name of queue
//! \param depth: depth of queue in number of messages
//! \param messageSize: size of an individual message
//! \return: status of the creation
Status create(const Fw::ConstStringBase& name, FwSizeType depth, FwSizeType messageSize) override;
Status create(FwEnumStoreType id,
const Fw::ConstStringBase& name,
FwSizeType depth,
FwSizeType messageSize) override;
//! \brief send a message into the queue
//!

View File

@ -42,7 +42,7 @@ TEST(Interface, Create) {
STest::Random::lowerUpper(std::numeric_limits<FwSizeType>::min(),
FW_MIN(std::numeric_limits<FwSizeType>::max(), std::numeric_limits<U32>::max()));
Os::Stub::Queue::Test::StaticData::data.createStatus = Os::QueueInterface::Status::INVALID_PRIORITY;
Os::QueueInterface::Status status = queue.create(name, depth, messageSize);
Os::QueueInterface::Status status = queue.create(0, name, depth, messageSize);
ASSERT_EQ(Os::Stub::Queue::Test::StaticData::data.lastCalled, Os::Stub::Queue::Test::StaticData::CREATE_FN);
ASSERT_EQ(Os::QueueInterface::Status::INVALID_PRIORITY, status);
ASSERT_STREQ(name.toChar(), Os::Stub::Queue::Test::StaticData::data.name.toChar());
@ -62,7 +62,7 @@ TEST(Interface, SendPointer) {
const FwQueuePriorityType priority = STest::Random::lowerUpper(
0, FW_MIN(std::numeric_limits<FwQueuePriorityType>::max(), std::numeric_limits<U32>::max()));
U8 buffer[messageSize];
ASSERT_EQ(Os::QueueInterface::Status::OP_OK, queue.create(name, depth, messageSize));
ASSERT_EQ(Os::QueueInterface::Status::OP_OK, queue.create(0, name, depth, messageSize));
ASSERT_STREQ(name.toChar(), queue.getName().toChar());
Os::Stub::Queue::Test::StaticData::data.sendStatus = Os::QueueInterface::Status::EMPTY;
Os::QueueInterface::Status status =
@ -93,7 +93,7 @@ TEST(Interface, SendBuffer) {
Fw::String message = "hello";
buffer.serializeFrom(message);
ASSERT_EQ(Os::QueueInterface::Status::OP_OK, queue.create(name, depth, messageSize));
ASSERT_EQ(Os::QueueInterface::Status::OP_OK, queue.create(0, name, depth, messageSize));
Os::Stub::Queue::Test::StaticData::data.sendStatus = Os::QueueInterface::Status::UNKNOWN_ERROR;
Os::QueueInterface::Status status = queue.send(buffer, priority, Os::QueueInterface::BlockingType::NONBLOCKING);
ASSERT_EQ(Os::Stub::Queue::Test::StaticData::data.lastCalled, Os::Stub::Queue::Test::StaticData::SEND_FN);
@ -123,7 +123,7 @@ TEST(Interface, ReceivePointer) {
FwQueuePriorityType priority;
U8 storage[size];
ASSERT_EQ(Os::QueueInterface::Status::OP_OK, queue.create(name, depth, size));
ASSERT_EQ(Os::QueueInterface::Status::OP_OK, queue.create(0, name, depth, size));
Os::Stub::Queue::Test::StaticData::data.receiveStatus = Os::QueueInterface::Status::FULL;
Os::Stub::Queue::Test::StaticData::data.size = sizeOut;
Os::Stub::Queue::Test::StaticData::data.priority = priorityOut;
@ -159,7 +159,7 @@ TEST(Interface, ReceiveBuffer) {
U8 storage[size];
Fw::ExternalSerializeBuffer buffer(storage, sizeof storage);
ASSERT_EQ(Os::QueueInterface::Status::OP_OK, queue.create(name, depth, size));
ASSERT_EQ(Os::QueueInterface::Status::OP_OK, queue.create(0, name, depth, size));
Os::Stub::Queue::Test::StaticData::data.receiveStatus = Os::QueueInterface::Status::FULL;
Os::Stub::Queue::Test::StaticData::data.size = sizeOut;
Os::Stub::Queue::Test::StaticData::data.priority = priorityOut;
@ -186,7 +186,7 @@ TEST(Interface, MessageCount) {
const FwSizeType messages =
STest::Random::lowerUpper(std::numeric_limits<FwSizeType>::min(),
FW_MIN(std::numeric_limits<FwSizeType>::max(), std::numeric_limits<U32>::max()));
ASSERT_EQ(Os::QueueInterface::Status::OP_OK, queue.create(name, depth, messageSize));
ASSERT_EQ(Os::QueueInterface::Status::OP_OK, queue.create(0, name, depth, messageSize));
Os::Stub::Queue::Test::StaticData::data.messages = messages;
ASSERT_EQ(queue.getMessagesAvailable(), messages);
@ -201,7 +201,7 @@ TEST(Interface, MessageHighWaterMarkCount) {
const FwSizeType highWater =
STest::Random::lowerUpper(std::numeric_limits<FwSizeType>::min(),
FW_MIN(std::numeric_limits<FwSizeType>::max(), std::numeric_limits<U32>::max()));
ASSERT_EQ(Os::QueueInterface::Status::OP_OK, queue.create(name, depth, messageSize));
ASSERT_EQ(Os::QueueInterface::Status::OP_OK, queue.create(0, name, depth, messageSize));
Os::Stub::Queue::Test::StaticData::data.highWaterMark = highWater;
ASSERT_EQ(queue.getMessageHighWaterMark(), highWater);

View File

@ -136,6 +136,7 @@ TEST(InterfaceUninitialized, SendBuffer) {
Os::QueueInterface::Status status = queue.send(buffer, priority, Os::QueueInterface::BlockingType::BLOCKING);
ASSERT_EQ(Os::QueueInterface::Status::UNINITIALIZED, status);
queue.teardown();
}
TEST(InterfaceUninitialized, ReceivePointer) {
@ -148,6 +149,7 @@ TEST(InterfaceUninitialized, ReceivePointer) {
Os::QueueInterface::Status status =
queue.receive(storage, sizeof storage, Os::QueueInterface::BlockingType::NONBLOCKING, size, priority);
ASSERT_EQ(Os::QueueInterface::Status::UNINITIALIZED, status);
queue.teardown();
}
TEST(InterfaceUninitialized, ReceiveBuffer) {
@ -160,18 +162,21 @@ TEST(InterfaceUninitialized, ReceiveBuffer) {
Os::QueueInterface::Status status = queue.receive(buffer, Os::QueueInterface::BlockingType::NONBLOCKING, priority);
ASSERT_EQ(Os::QueueInterface::Status::UNINITIALIZED, status);
queue.teardown();
}
TEST(InterfaceInvalid, CreateInvalidDepth) {
Os::Queue queue;
Fw::String name = "My queue";
ASSERT_DEATH_IF_SUPPORTED(queue.create(name, 0, 10), "Assert:.*Queue\\.cpp");
ASSERT_DEATH_IF_SUPPORTED(queue.create(0, name, 0, 10), "Assert:.*Queue\\.cpp");
queue.teardown();
}
TEST(InterfaceInvalid, CreateInvalidSize) {
Os::Queue queue;
Fw::String name = "My queue";
ASSERT_DEATH_IF_SUPPORTED(queue.create(name, 10, 0), "Assert:.*Queue\\.cpp");
ASSERT_DEATH_IF_SUPPORTED(queue.create(0, name, 10, 0), "Assert:.*Queue\\.cpp");
queue.teardown();
}
TEST(InterfaceInvalid, SendPointerNull) {
@ -181,6 +186,7 @@ TEST(InterfaceInvalid, SendPointerNull) {
const FwQueuePriorityType priority = 127;
ASSERT_DEATH_IF_SUPPORTED(queue.send(nullptr, messageSize, priority, Os::QueueInterface::BlockingType::BLOCKING),
"Assert:.*Queue\\.cpp");
queue.teardown();
}
TEST(InterfaceInvalid, SendInvalidEnum) {
@ -191,6 +197,7 @@ TEST(InterfaceInvalid, SendInvalidEnum) {
Os::QueueInterface::BlockingType blockingType =
static_cast<Os::QueueInterface::BlockingType>(Os::QueueInterface::BlockingType::BLOCKING + 1);
ASSERT_DEATH_IF_SUPPORTED(queue.send(nullptr, messageSize, priority, blockingType), "Assert:.*Queue\\.cpp");
queue.teardown();
}
TEST(InterfaceInvalid, ReceivePointerNull) {
@ -201,6 +208,7 @@ TEST(InterfaceInvalid, ReceivePointerNull) {
ASSERT_DEATH_IF_SUPPORTED(
queue.receive(nullptr, size, Os::QueueInterface::BlockingType::NONBLOCKING, size, priority),
"Assert:.*Queue\\.cpp");
queue.teardown();
}
TEST(InterfaceInvalid, ReceiveInvalidEnum) {
@ -211,6 +219,7 @@ TEST(InterfaceInvalid, ReceiveInvalidEnum) {
Os::QueueInterface::BlockingType blockingType =
static_cast<Os::QueueInterface::BlockingType>(Os::QueueInterface::BlockingType::BLOCKING + 1);
ASSERT_DEATH_IF_SUPPORTED(queue.receive(nullptr, size, blockingType, size, priority), "Assert:.*Queue\\.cpp");
queue.teardown();
}
TEST(BasicRules, Create) {

View File

@ -61,7 +61,7 @@ void Os::Test::Queue::Tester::Create::action(Os::Test::Queue::Tester& state //!
FwSizeType depth = STest::Random::lowerUpper(1, QUEUE_DEPTH_UPPER_BOUND);
FwSizeType messageSize = STest::Random::lowerUpper(1, QUEUE_MESSAGE_SIZE_UPPER_BOUND);
QueueInterface::Status status = state.shadow_create(depth, messageSize);
QueueInterface::Status test_status = state.queue.create(name, depth, messageSize);
QueueInterface::Status test_status = state.queue.create(0, name, depth, messageSize);
ASSERT_EQ(status, created ? QueueInterface::Status::ALREADY_CREATED : QueueInterface::Status::OP_OK);
ASSERT_EQ(status, test_status);
ASSERT_EQ(name, state.queue.getName());

View File

@ -27,7 +27,7 @@ struct Tester {
public:
//! Constructor
Tester() = default;
virtual ~Tester() = default;
virtual ~Tester() { queue.teardown(); };
struct QueueMessage {
U8 data[QUEUE_MESSAGE_SIZE_UPPER_BOUND];

View File

@ -18,7 +18,9 @@ BlockDriverTester ::BlockDriverTester()
this->connectPorts();
}
BlockDriverTester ::~BlockDriverTester() {}
BlockDriverTester ::~BlockDriverTester() {
this->component.deinit();
}
// ----------------------------------------------------------------------
// Tests

View File

@ -24,7 +24,9 @@ SignalGenTester ::SignalGenTester() : SignalGenGTestBase("Tester", MAX_HISTORY_S
this->m_reqDpBuff.set(this->m_dpBuff, sizeof(this->m_dpBuff));
}
SignalGenTester ::~SignalGenTester() {}
SignalGenTester ::~SignalGenTester() {
this->component.deinit();
}
// ----------------------------------------------------------------------
// Tests

View File

@ -79,7 +79,9 @@ ActivePhaserTester ::ActivePhaserTester()
this->connectPorts();
}
ActivePhaserTester ::~ActivePhaserTester() {}
ActivePhaserTester ::~ActivePhaserTester() {
this->component.deinit();
}
// ----------------------------------------------------------------------
// Test helpers

View File

@ -32,7 +32,9 @@ void ActiveRateGroupTester::clearPortCalls() {
this->m_callOrder = 0;
}
ActiveRateGroupTester::~ActiveRateGroupTester() {}
ActiveRateGroupTester::~ActiveRateGroupTester() {
this->m_impl.deinit();
}
void ActiveRateGroupTester::from_RateGroupMemberOut_handler(FwIndexType portNum, U32 context) {
ASSERT_TRUE(portNum < static_cast<FwIndexType>(FW_NUM_ARRAY_ELEMENTS(m_impl.m_RateGroupMemberOut_OutputPort)));

View File

@ -23,7 +23,9 @@ ActiveTextLoggerTester ::ActiveTextLoggerTester()
this->connectPorts();
}
ActiveTextLoggerTester ::~ActiveTextLoggerTester() {}
ActiveTextLoggerTester ::~ActiveTextLoggerTester() {
this->component.deinit();
}
// ----------------------------------------------------------------------
// Tests

View File

@ -55,6 +55,7 @@ BufferAccumulatorTester ::~BufferAccumulatorTester() {
Fw::MallocAllocator buffAccumMallocator;
this->component.deallocateQueue(buffAccumMallocator);
}
this->component.deinit();
}
// ----------------------------------------------------------------------

View File

@ -43,7 +43,9 @@ BufferLoggerTester ::BufferLoggerTester(bool doInitLog)
}
}
BufferLoggerTester ::~BufferLoggerTester() {}
BufferLoggerTester ::~BufferLoggerTester() {
this->component.deinit();
}
// ----------------------------------------------------------------------
// Tests

View File

@ -22,7 +22,9 @@ namespace Svc {
CommandDispatcherTester::CommandDispatcherTester(Svc::CommandDispatcherImpl& inst)
: CommandDispatcherGTestBase("testerbase", 100), m_impl(inst) {}
CommandDispatcherTester::~CommandDispatcherTester() {}
CommandDispatcherTester::~CommandDispatcherTester() {
this->m_impl.deinit();
}
void CommandDispatcherTester::from_compCmdSend_handler(FwIndexType portNum,
FwOpcodeType opCode,

View File

@ -38,6 +38,7 @@ CmdSequencerTester ::CmdSequencerTester(const SequenceFiles::File::Format::t a_f
CmdSequencerTester ::~CmdSequencerTester() {
this->component.deallocateBuffer(this->mallocator);
this->component.deinit();
}
// ----------------------------------------------------------------------

View File

@ -21,7 +21,9 @@ ComAggregatorTester ::ComAggregatorTester()
this->connectPorts();
}
ComAggregatorTester ::~ComAggregatorTester() {}
ComAggregatorTester ::~ComAggregatorTester() {
this->component.deinit();
}
// ----------------------------------------------------------------------
// Tests

View File

@ -28,7 +28,9 @@ ComLoggerTester ::ComLoggerTester(const char* const compName, bool standardCLIni
(void)standardCLInit;
}
ComLoggerTester ::~ComLoggerTester() {}
ComLoggerTester ::~ComLoggerTester() {
this->comLogger.deinit();
}
void ComLoggerTester ::connectPorts() {
comLogger.set_cmdRegOut_OutputPort(0, this->get_from_cmdRegOut(0));

View File

@ -24,7 +24,9 @@ ComQueueTester ::ComQueueTester() : ComQueueGTestBase("Tester", MAX_HISTORY_SIZE
this->connectPorts();
}
ComQueueTester ::~ComQueueTester() {}
ComQueueTester ::~ComQueueTester() {
this->component.deinit();
}
void ComQueueTester ::dispatchAll() {
while (this->component.m_queue.getMessagesAvailable() > 0) {

View File

@ -26,7 +26,9 @@ DpCatalogTester ::DpCatalogTester()
this->connectPorts();
}
DpCatalogTester ::~DpCatalogTester() {}
DpCatalogTester ::~DpCatalogTester() {
this->component.deinit();
}
// ----------------------------------------------------------------------
// Tests

View File

@ -18,7 +18,9 @@ DpManagerTester ::DpManagerTester()
this->connectPorts();
}
DpManagerTester ::~DpManagerTester() {}
DpManagerTester ::~DpManagerTester() {
this->component.deinit();
}
// ----------------------------------------------------------------------
// Handlers for typed from ports

View File

@ -23,7 +23,9 @@ DpWriterTester ::DpWriterTester()
Os::Stub::File::Test::StaticData::data.pointer = 0;
}
DpWriterTester ::~DpWriterTester() {}
DpWriterTester ::~DpWriterTester() {
this->component.deinit();
}
// ----------------------------------------------------------------------
// Handlers for typed from ports

View File

@ -25,7 +25,9 @@ EventManagerTester::EventManagerTester(Svc::EventManager& inst)
m_receivedPacket(false),
m_receivedFatalEvent(false) {}
EventManagerTester::~EventManagerTester() {}
EventManagerTester::~EventManagerTester() {
this->m_impl.deinit();
}
void EventManagerTester::from_PktSend_handler(const FwIndexType portNum, //!< The port number
Fw::ComBuffer& data, //!< Buffer containing packet data

View File

@ -46,11 +46,16 @@ void FileDownlink ::configure(U32 timeout, U32 cooldown, U32 cycleTime, U32 file
this->m_configured = true;
Os::Queue::Status stat =
m_fileQueue.create(Os::QueueString("fileDownlinkQueue"), static_cast<FwSizeType>(fileQueueDepth),
static_cast<FwSizeType>(sizeof(struct FileEntry)));
m_fileQueue.create(this->getInstance(), Os::QueueString("fileDownlinkQueue"),
static_cast<FwSizeType>(fileQueueDepth), static_cast<FwSizeType>(sizeof(struct FileEntry)));
FW_ASSERT(stat == Os::Queue::OP_OK, static_cast<FwAssertArgType>(stat));
}
void FileDownlink ::deinit() {
this->m_fileQueue.teardown();
FileDownlinkComponentBase::deinit();
}
void FileDownlink ::preamble() {
FW_ASSERT(this->m_configured == true);
}

View File

@ -229,6 +229,9 @@ class FileDownlink final : public FileDownlinkComponentBase {
U32 fileQueueDepth //!< Max number of items in file downlink queue
);
//! Cleans up file queue before dispatching to underlying component
void deinit();
//! Start FileDownlink component
//! The component must be configured with configure() before starting.
//!

View File

@ -39,6 +39,7 @@ FileDownlinkTester ::~FileDownlinkTester() {
for (U32 i = 0; i < buffers_index; i++) {
delete[] buffers[i];
}
this->component.deinit();
}
// ----------------------------------------------------------------------

View File

@ -31,7 +31,9 @@ FileManagerTester ::FileManagerTester() : FileManagerGTestBase("Tester", MAX_HIS
this->initComponents();
}
FileManagerTester ::~FileManagerTester() {}
FileManagerTester ::~FileManagerTester() {
this->component.deinit();
}
// ----------------------------------------------------------------------
// Tests

View File

@ -37,6 +37,7 @@ FileUplinkTester ::FileUplinkTester()
FileUplinkTester ::~FileUplinkTester() {
this->component.m_file.osFile.close();
this->component.deinit();
}
// ----------------------------------------------------------------------

View File

@ -23,7 +23,9 @@ FpySequencerTester ::FpySequencerTester()
clearSeq();
}
FpySequencerTester ::~FpySequencerTester() {}
FpySequencerTester ::~FpySequencerTester() {
this->component.deinit();
}
// dispatches events from the queue until the cmp reaches the given state
void FpySequencerTester::dispatchUntilState(State state, U32 bound) {

View File

@ -33,7 +33,9 @@ HealthTester ::HealthTester() : HealthGTestBase("Tester", MAX_HISTORY_SIZE), com
this->initComponents();
}
HealthTester ::~HealthTester() {}
HealthTester ::~HealthTester() {
this->component.deinit();
}
// ----------------------------------------------------------------------
// Handlers for typed from ports

View File

@ -1341,7 +1341,9 @@ PrmDbTester::PrmDbTester(Svc::PrmDbImpl& inst) : PrmDbGTestBase("testerbase", 10
PrmDbTester::PrmDbTestFile::setTester(this);
}
PrmDbTester::~PrmDbTester() {}
PrmDbTester::~PrmDbTester() {
this->m_impl.deinit();
}
void PrmDbTester ::from_pingOut_handler(const FwIndexType portNum, U32 key) {
this->pushFromPortEntry_pingOut(key);

View File

@ -18,7 +18,9 @@ SeqDispatcherTester ::SeqDispatcherTester()
this->initComponents();
}
SeqDispatcherTester ::~SeqDispatcherTester() {}
SeqDispatcherTester ::~SeqDispatcherTester() {
this->component.deinit();
}
// ----------------------------------------------------------------------
// Tests

View File

@ -30,7 +30,9 @@ TlmChanTester ::TlmChanTester()
this->connectPorts();
}
TlmChanTester ::~TlmChanTester() {}
TlmChanTester ::~TlmChanTester() {
this->component.deinit();
}
// ----------------------------------------------------------------------
// Tests

View File

@ -28,7 +28,9 @@ TlmPacketizerTester ::TlmPacketizerTester()
this->connectPorts();
}
TlmPacketizerTester ::~TlmPacketizerTester() {}
TlmPacketizerTester ::~TlmPacketizerTester() {
this->component.deinit();
}
// ----------------------------------------------------------------------
// Tests

View File

@ -12,6 +12,7 @@ register_fprime_config(
"${CMAKE_CURRENT_LIST_DIR}/FpConstants.fpp"
"${CMAKE_CURRENT_LIST_DIR}/FpySequencerCfg.fpp"
"${CMAKE_CURRENT_LIST_DIR}/MemoryAllocation.fpp"
"${CMAKE_CURRENT_LIST_DIR}/MemoryAllocation.hpp"
"${CMAKE_CURRENT_LIST_DIR}/PlatformCfg.fpp"
"${CMAKE_CURRENT_LIST_DIR}/PolyDbCfg.fpp"
"${CMAKE_CURRENT_LIST_DIR}/VersionCfg.fpp"

View File

@ -0,0 +1,20 @@
// ======================================================================
// \title config/MemoryAllocation.hpp
// \author lestarch
// \brief hpp file for memory allocation configuration
//
// \copyright
// Copyright 2024, by the California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship
// acknowledged.
// ======================================================================
#ifndef CONFIG_MEMORY_ALLOCATION_HPP
#define CONFIG_MEMORY_ALLOCATION_HPP
#include <Fw/Types/MallocAllocator.hpp>
namespace Fw {
namespace MemoryAllocation {
using DefaultMemoryAllocatorType = Fw::MallocAllocator;
} // namespace MemoryAllocation
} // namespace Fw
#endif // CONFIG_MEMORY_ALLOCATION_HPP

View File

@ -15,7 +15,7 @@ constant FW_FILE_HANDLE_MAX_SIZE = 16
constant FW_MUTEX_HANDLE_MAX_SIZE = 72
@ Maximum size of a handle for Os::Queue
constant FW_QUEUE_HANDLE_MAX_SIZE = 352
constant FW_QUEUE_HANDLE_MAX_SIZE = 368
@ Maximum size of a handle for Os::Directory
constant FW_DIRECTORY_HANDLE_MAX_SIZE = 16