1 /* 2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef LIBPANDABASE_MEM_MEM_POOL_H 17 #define LIBPANDABASE_MEM_MEM_POOL_H 18 19 #include <cstddef> 20 #include "macros.h" 21 #include "mem.h" 22 #include "pool_map.h" 23 24 namespace ark { 25 class Arena; 26 27 enum class OSPagesPolicy : bool { 28 NO_RETURN, 29 IMMEDIATE_RETURN, 30 }; 31 32 enum class OSPagesAllocPolicy : bool { 33 NO_POLICY, 34 ZEROED_MEMORY, 35 }; 36 37 class Pool { 38 public: Pool(size_t size,void * mem)39 explicit constexpr Pool(size_t size, void *mem) : size_(size), mem_(mem) {} Pool(std::pair<size_t,void * > pool)40 explicit Pool(std::pair<size_t, void *> pool) : size_(pool.first), mem_(pool.second) {} 41 GetSize()42 size_t GetSize() const 43 { 44 return size_; 45 } 46 GetMem()47 void *GetMem() 48 { 49 return mem_; 50 } 51 52 bool operator==(const Pool &other) const 53 { 54 return (this->size_ == other.size_) && (this->mem_ == other.mem_); 55 } 56 57 bool operator!=(const Pool &other) const 58 { 59 return !(*this == other); 60 } 61 62 ~Pool() = default; 63 64 DEFAULT_COPY_SEMANTIC(Pool); 65 DEFAULT_MOVE_SEMANTIC(Pool); 66 67 private: 68 size_t size_; 69 void *mem_; 70 }; 71 72 constexpr Pool NULLPOOL {0, nullptr}; 73 74 template <class MemPoolImplT> 75 class MemPool { 76 public: 77 virtual ~MemPool() = default; MemPool(std::string poolName)78 explicit MemPool(std::string poolName) : name_(std::move(poolName)) {} 79 DEFAULT_NOEXCEPT_MOVE_SEMANTIC(MemPool); 80 DEFAULT_COPY_SEMANTIC(MemPool); 81 82 /** 83 * Allocates arena with size bytes 84 * @tparam ArenaT - type of Arena 85 * @tparam OS_ALLOC_POLICY - allocated memory policy 86 * @param size - size of buffer in arena in bytes 87 * @param space_type - type of the space which arena allocated for 88 * @param allocator_type - type of the allocator which arena allocated for 89 * @param allocator_addr - address of the allocator header. 90 * @return pointer to allocated arena 91 */ 92 // NOTE(aemelenko): We must always define allocator_addr for AllocArena 93 // because we set up arena at the first bytes of the pool 94 template <class ArenaT = Arena, OSPagesAllocPolicy OS_ALLOC_POLICY = OSPagesAllocPolicy::NO_POLICY> 95 inline ArenaT *AllocArena(size_t size, SpaceType spaceType, AllocatorType allocatorType, 96 const void *allocatorAddr = nullptr) 97 { 98 auto *allocatedArena = static_cast<MemPoolImplT *>(this)->template AllocArenaImpl<ArenaT, OS_ALLOC_POLICY>( 99 size, spaceType, allocatorType, allocatorAddr); 100 if constexpr (IS_ZERO_CHECK_ENABLED && OS_ALLOC_POLICY == OSPagesAllocPolicy::ZEROED_MEMORY) { 101 if (allocatedArena != nullptr) { 102 CheckZeroedMemory(allocatedArena->GetMem(), allocatedArena->GetSize()); 103 } 104 } 105 return allocatedArena; 106 } 107 108 /** 109 * Frees allocated arena 110 * @tparam ArenaT - arena type 111 * @tparam OS_PAGES_POLICY - OS return pages policy 112 * @param arena - pointer to the arena 113 */ 114 template <class ArenaT = Arena, OSPagesPolicy OS_PAGES_POLICY = OSPagesPolicy::IMMEDIATE_RETURN> FreeArena(ArenaT * arena)115 inline void FreeArena(ArenaT *arena) 116 { 117 static_cast<MemPoolImplT *>(this)->template FreeArenaImpl<ArenaT, OS_PAGES_POLICY>(arena); 118 } 119 120 /** 121 * Allocates pool with at least size bytes 122 * @tparam OS_ALLOC_POLICY - allocated memory policy 123 * @param size - minimal size of a pool in bytes 124 * @param space_type - type of the space which pool allocated for 125 * @param allocator_type - type of the allocator which arena allocated for 126 * @param allocator_addr - address of the allocator header. 127 * If it is not defined, it means that allocator header will be located at the first bytes of the returned pool. 128 * @return pool info with the size and a pointer 129 */ 130 template <OSPagesAllocPolicy OS_ALLOC_POLICY = OSPagesAllocPolicy::NO_POLICY> 131 Pool AllocPool(size_t size, SpaceType spaceType, AllocatorType allocatorType, const void *allocatorAddr = nullptr) 132 { 133 Pool allocatedPool = static_cast<MemPoolImplT *>(this)->template AllocPoolImpl<OS_ALLOC_POLICY>( 134 size, spaceType, allocatorType, allocatorAddr); 135 if constexpr (IS_ZERO_CHECK_ENABLED && OS_ALLOC_POLICY == OSPagesAllocPolicy::ZEROED_MEMORY) { 136 if (allocatedPool.GetMem() != nullptr) { 137 CheckZeroedMemory(allocatedPool.GetMem(), allocatedPool.GetSize()); 138 } 139 } 140 return allocatedPool; 141 } 142 143 /** 144 * Frees allocated pool 145 * @tparam OS_PAGES_POLICY - OS return pages policy 146 * @param mem - pointer to an allocated pool 147 * @param size - size of the allocated pool in bytes 148 */ 149 template <OSPagesPolicy OS_PAGES_POLICY = OSPagesPolicy::IMMEDIATE_RETURN> FreePool(void * mem,size_t size)150 void FreePool(void *mem, size_t size) 151 { 152 static_cast<MemPoolImplT *>(this)->template FreePoolImpl<OS_PAGES_POLICY>(mem, size); 153 } 154 155 /** 156 * Get info about the allocator in which this address is used 157 * @param addr 158 * @return Allocator info with a type and pointer to the allocator header 159 */ GetAllocatorInfoForAddr(const void * addr)160 AllocatorInfo GetAllocatorInfoForAddr(const void *addr) const 161 { 162 return static_cast<const MemPoolImplT *>(this)->GetAllocatorInfoForAddrImpl(addr); 163 } 164 165 /** 166 * Get space type which this address used for 167 * @param addr 168 * @return space type 169 */ GetSpaceTypeForAddr(const void * addr)170 SpaceType GetSpaceTypeForAddr(const void *addr) const 171 { 172 return static_cast<const MemPoolImplT *>(this)->GetSpaceTypeForAddrImpl(addr); 173 } 174 175 /** 176 * Get address of pool start for input address 177 * @param addr address in pool 178 * @return address of pool start 179 */ GetStartAddrPoolForAddr(const void * addr)180 void *GetStartAddrPoolForAddr(const void *addr) const 181 { 182 return static_cast<const MemPoolImplT *>(this)->GetStartAddrPoolForAddrImpl(addr); 183 } 184 185 private: 186 #ifndef NDEBUG 187 static constexpr bool IS_ZERO_CHECK_ENABLED = true; 188 #else 189 static constexpr bool IS_ZERO_CHECK_ENABLED = false; 190 #endif 191 CheckZeroedMemory(void * mem,size_t size)192 static void CheckZeroedMemory(void *mem, size_t size) 193 { 194 // Check that the memory is zeroed: 195 [[maybe_unused]] auto iterator64 = static_cast<uint64_t *>(mem); 196 size_t it64End = size / sizeof(uint64_t); 197 [[maybe_unused]] uintptr_t endMemory = ToUintPtr(mem) + size; 198 // check by 64 byte 199 for (size_t i = 0; i < it64End; i++) { 200 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 201 ASSERT(ToUintPtr(&iterator64[i]) < endMemory); 202 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 203 ASSERT(iterator64[i] == 0); 204 } 205 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 206 [[maybe_unused]] auto iterator8 = reinterpret_cast<uint8_t *>(&iterator64[it64End]); 207 size_t it8End = size % sizeof(uint64_t); 208 // check by byte 209 for (size_t i = 0; i < it8End; i++) { 210 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 211 ASSERT(ToUintPtr(&iterator8[i]) < endMemory); 212 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 213 ASSERT(iterator8[i] == 0); 214 } 215 } 216 217 std::string name_; 218 }; 219 220 } // namespace ark 221 222 #endif // LIBPANDABASE_MEM_MEM_POOL_H 223