| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /** | ||
| 2 | * \file | ||
| 3 | * \author A. Tumbar | ||
| 4 | * \brief A MemAllocator implementation class that uses static memory buckets. | ||
| 5 | * | ||
| 6 | * \copyright | ||
| 7 | * Copyright 2026, by the California Institute of Technology. | ||
| 8 | * ALL RIGHTS RESERVED. United States Government Sponsorship | ||
| 9 | * acknowledged. | ||
| 10 | * | ||
| 11 | */ | ||
| 12 | |||
| 13 | #ifndef SAMD21_MALLOCALLOCATOR_HPP | ||
| 14 | #define SAMD21_MALLOCALLOCATOR_HPP | ||
| 15 | |||
| 16 | #include <Fw/Types/MemAllocator.hpp> | ||
| 17 | #include <cstddef> | ||
| 18 | #include "Fw/Types/Assert.hpp" | ||
| 19 | #include "config/FwAssertArgTypeAliasAc.h" | ||
| 20 | #include "config/FwEnumStoreTypeAliasAc.h" | ||
| 21 | |||
| 22 | namespace Samd21 { | ||
| 23 | |||
| 24 | //! \brief static memory based memory allocator | ||
| 25 | //! | ||
| 26 | //! This class implements a memory allocator that uses static memory buckets. | ||
| 27 | template <size_t BUCKET_SIZE, FwEnumStoreType IDENT> | ||
| 28 | class StaticMallocator : public Fw::MemAllocator { | ||
| 29 | public: | ||
| 30 | static_assert(BUCKET_SIZE % 8 == 0, "Bucket size must a multiple of 8"); | ||
| 31 | |||
| 32 | ✗ | StaticMallocator() = default; | |
| 33 | ✗ | virtual ~StaticMallocator() = default; | |
| 34 | |||
| 35 | //! Allocate memory | ||
| 36 | //! | ||
| 37 | //! Allocate memory using malloc(). The identifier is unused and memory is never recoverable. | ||
| 38 | //! malloc() guarantees alignment for any type and so does this allocator. It will not respect smaller alignments. | ||
| 39 | //! | ||
| 40 | //! \param identifier the allocating entity identifier (not used) | ||
| 41 | //! \param size the requested size (not changed) | ||
| 42 | //! \param recoverable - flag to indicate the memory could be recoverable (always set to false) | ||
| 43 | //! \param alignment - alignment requirement for the allocation. Default: maximum alignment defined by C++. | ||
| 44 | //! \return the pointer to memory. Zero if unable to allocate. | ||
| 45 | ✗ | void* allocate(const FwEnumStoreType identifier, | |
| 46 | FwSizeType& size, | ||
| 47 | bool& recoverable, | ||
| 48 | FwSizeType alignment = alignof(std::max_align_t)) override { | ||
| 49 | ✗ | FW_ASSERT(identifier == IDENT, static_cast<FwAssertArgType>(identifier), static_cast<FwAssertArgType>(IDENT)); | |
| 50 | ✗ | FW_ASSERT(size <= BUCKET_SIZE, static_cast<FwAssertArgType>(size), static_cast<FwAssertArgType>(BUCKET_SIZE)); | |
| 51 | // `data` is declared alignas(std::max_align_t), so the bound here is exactly the | ||
| 52 | // default argument above. It used to read `alignment <= 8`, which made the DEFAULT | ||
| 53 | // call self-inconsistent on any host where alignof(std::max_align_t) is 16 -- true | ||
| 54 | // of Linux x86-64, where `long double` is 16-byte aligned. Darwin arm64 has it at | ||
| 55 | // 8, so the bug was invisible there and only surfaced when a unit test ran on | ||
| 56 | // Linux. Keep this comparing against the same expression `data` is aligned to. | ||
| 57 | ✗ | FW_ASSERT(alignment <= alignof(std::max_align_t), static_cast<FwAssertArgType>(alignment)); | |
| 58 | ✗ | FW_ASSERT(!used); | |
| 59 | |||
| 60 | ✗ | recoverable = true; | |
| 61 | ✗ | this->used = true; | |
| 62 | ✗ | return reinterpret_cast<void*>(this->data); | |
| 63 | } | ||
| 64 | //! Deallocate memory | ||
| 65 | //! | ||
| 66 | //! Deallocate memory previously allocated by allocate() using free(). The identifier is unused but should still | ||
| 67 | //! match the original call. | ||
| 68 | //! | ||
| 69 | //! \param identifier the memory segment identifier (not used) | ||
| 70 | //! \param ptr the pointer to memory returned by allocate() | ||
| 71 | ✗ | void deallocate(const FwEnumStoreType identifier, void* ptr) override { | |
| 72 | ✗ | FW_ASSERT(identifier == IDENT, static_cast<FwAssertArgType>(identifier), static_cast<FwAssertArgType>(IDENT)); | |
| 73 | ✗ | FW_ASSERT(used); | |
| 74 | ✗ | FW_ASSERT(ptr == reinterpret_cast<void*>(this->data)); | |
| 75 | ✗ | this->used = false; | |
| 76 | ✗ | } | |
| 77 | |||
| 78 | private: | ||
| 79 | // U64 for 64-bit alignment, and alignas() on top of it so the storage really does | ||
| 80 | // satisfy the alignment this class advertises as its default argument. On the SAMD21 | ||
| 81 | // (arm-none-eabi, 32-bit) alignof(std::max_align_t) is 8 and the U64 array is already | ||
| 82 | // 8-aligned, so this costs nothing on target; it only widens the alignment on hosts | ||
| 83 | // where max_align_t is 16, i.e. in unit tests. | ||
| 84 | alignas(std::max_align_t) U64 data[BUCKET_SIZE / 8]; | ||
| 85 | bool used = false; | ||
| 86 | }; | ||
| 87 | |||
| 88 | } // namespace Samd21 | ||
| 89 | |||
| 90 | #endif /* SAMD21_MALLOCALLOCATOR_HPP */ | ||
| 91 |