| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /** | ||
| 2 | * \file | ||
| 3 | * \author Gene Merewether | ||
| 4 | * \brief A MemAllocator implementation class that uses mmap. | ||
| 5 | * | ||
| 6 | * \copyright | ||
| 7 | * Copyright 2009-2016, by the California Institute of Technology. | ||
| 8 | * ALL RIGHTS RESERVED. United States Government Sponsorship | ||
| 9 | * acknowledged. | ||
| 10 | * | ||
| 11 | */ | ||
| 12 | |||
| 13 | #ifndef TYPES_MMAPALLOCATOR_HPP_ | ||
| 14 | #define TYPES_MMAPALLOCATOR_HPP_ | ||
| 15 | |||
| 16 | #include <sys/mman.h> | ||
| 17 | #include <unistd.h> | ||
| 18 | #include <Fw/DataStructures/RedBlackTreeMap.hpp> | ||
| 19 | #include <Fw/Logger/Logger.hpp> | ||
| 20 | #include <Fw/Types/MemAllocator.hpp> | ||
| 21 | #include <cerrno> | ||
| 22 | |||
| 23 | namespace Fw { | ||
| 24 | |||
| 25 | //! Fw::MmapAllocator is an implementation of the Fw::MemAllocator interface that backs memory with a read and write | ||
| 26 | //! capable anonymous memory mapped region. | ||
| 27 | //! | ||
| 28 | //! \param C - Number of allocations supported by this allocator. | ||
| 29 | //! munmap needs the size of the original mapping. MmapAllocator keeps these sizes in a Map structure | ||
| 30 | //! with a compile time limit on allocations | ||
| 31 | //! | ||
| 32 | template <FwSizeType C> | ||
| 33 | class MmapAllocator : public MemAllocator { | ||
| 34 | public: | ||
| 35 | //! Constructor with one default argument | ||
| 36 | //! | ||
| 37 | explicit MmapAllocator(int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS); | ||
| 38 | //! Destructor with no arguments | ||
| 39 | virtual ~MmapAllocator(); | ||
| 40 | |||
| 41 | //! Allocate memory using the mmap allocator | ||
| 42 | //! \param identifier: identifier to use with allocation | ||
| 43 | //! \param size: size of memory to be allocated | ||
| 44 | //! \param recoverable: (output) is this memory recoverable after a reset. Always false for mmap. | ||
| 45 | //! \param alignment - alignment requirement for the allocation. Default: maximum alignment defined by C++. | ||
| 46 | //! \return the pointer to memory. Zero if unable to allocate | ||
| 47 | void* allocate(const FwEnumStoreType identifier, | ||
| 48 | FwSizeType& size, | ||
| 49 | bool& recoverable, | ||
| 50 | FwSizeType alignment = alignof(std::max_align_t)) override; | ||
| 51 | |||
| 52 | //! Deallocation of memory using the mmap allocator | ||
| 53 | //! \param identifier: identifier used at allocation | ||
| 54 | //! \param ptr: pointer to memory being deallocated | ||
| 55 | void deallocate(const FwEnumStoreType identifier, void* ptr) override; | ||
| 56 | |||
| 57 | private: | ||
| 58 | //! Store sizes of previous allocations to use with deallocate | ||
| 59 | RedBlackTreeMap<intptr_t, size_t, C> m_size_map; | ||
| 60 | |||
| 61 | //! Store flags to pass to mmap | ||
| 62 | const int m_mmap_flags; | ||
| 63 | }; | ||
| 64 | |||
| 65 | template <FwSizeType C> | ||
| 66 |
1/1✓ Branch 12 taken 3 times.
|
3 | MmapAllocator<C>::MmapAllocator(int mmap_flags) : m_size_map(), m_mmap_flags(mmap_flags) {} |
| 67 | |||
| 68 | template <FwSizeType C> | ||
| 69 | 6 | MmapAllocator<C>::~MmapAllocator() {} | |
| 70 | |||
| 71 | template <FwSizeType C> | ||
| 72 | 7 | void* MmapAllocator<C>::allocate(const FwEnumStoreType identifier, | |
| 73 | FwSizeType& size, | ||
| 74 | bool& recoverable, | ||
| 75 | FwSizeType alignment) { | ||
| 76 | // mmap memory is never recoverable | ||
| 77 | 7 | recoverable = false; | |
| 78 | |||
| 79 | // mmap allocates pages at a virtual boundary. Alignment is guaranteed | ||
| 80 | // up to the page size | ||
| 81 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 6 times.
|
7 | if (alignment > static_cast<FwSizeType>(sysconf(_SC_PAGESIZE))) { |
| 82 |
1/1✓ Branch 2 taken 1 times.
|
1 | Fw::Logger::log("Unable to allocate. Alignment request (%ld) > PAGE_SIZE (%ld)\n", alignment, |
| 83 | sysconf(_SC_PAGESIZE)); | ||
| 84 | 1 | size = 0; | |
| 85 | 1 | return nullptr; | |
| 86 | } | ||
| 87 | |||
| 88 |
4/4✓ Branch 6 taken 6 times.
✓ Branch 14 taken 6 times.
✓ Branch 16 taken 1 times.
✓ Branch 17 taken 5 times.
|
6 | if (m_size_map.getCapacity() == m_size_map.getSize()) { |
| 89 |
1/1✓ Branch 1 taken 1 times.
|
1 | Fw::Logger::log("Unable to allocate. MmapAllocator out of size_map slots\n"); |
| 90 | 1 | size = 0; | |
| 91 | 1 | return nullptr; | |
| 92 | } | ||
| 93 | |||
| 94 | 5 | void* addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, m_mmap_flags, -1, 0); | |
| 95 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | if (addr == MAP_FAILED) { |
| 96 | ✗ | Fw::Logger::log("Unable to allocate. mmap syscall failed. Errno (%ld)\n", errno); | |
| 97 | ✗ | size = 0; | |
| 98 | ✗ | return nullptr; | |
| 99 | } | ||
| 100 | |||
| 101 |
1/1✓ Branch 7 taken 5 times.
|
5 | Fw::Success ok = m_size_map.insert(reinterpret_cast<intptr_t>(addr), size); |
| 102 | 5 | FW_ASSERT(ok == Fw::Success::SUCCESS, ok); | |
| 103 | |||
| 104 | 5 | return addr; | |
| 105 | 5 | } | |
| 106 | |||
| 107 | template <FwSizeType C> | ||
| 108 | 5 | void MmapAllocator<C>::deallocate(const FwEnumStoreType identifier, void* ptr) { | |
| 109 | 5 | size_t alloc_size = 0; | |
| 110 |
1/1✓ Branch 6 taken 5 times.
|
5 | Fw::Success ok = m_size_map.remove(reinterpret_cast<intptr_t>(ptr), alloc_size); |
| 111 | 5 | FW_ASSERT(ok == Fw::Success::SUCCESS, ok); | |
| 112 | |||
| 113 | 5 | int stat = munmap(ptr, alloc_size); | |
| 114 | 5 | FW_ASSERT(stat == 0, stat); | |
| 115 | 10 | } | |
| 116 | |||
| 117 | } /* namespace Fw */ | ||
| 118 | |||
| 119 | #endif /* TYPES_MMAPALLOCATOR_HPP_ */ | ||
| 120 |