1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef CHRE_UTIL_SYSTEM_SYNCHRONIZED_EXPANDABLE_MEMORY_POOL_H_ 18 #define CHRE_UTIL_SYSTEM_SYNCHRONIZED_EXPANDABLE_MEMORY_POOL_H_ 19 20 #include "chre/platform/mutex.h" 21 #include "chre/util/fixed_size_vector.h" 22 #include "chre/util/memory_pool.h" 23 #include "chre/util/unique_ptr.h" 24 25 namespace chre { 26 27 /** 28 * This is a similar data structure to chre::SynchronizedMemoryPool with a more 29 * optimized memory usage. This data structure will allocate new storage as 30 * needed and in segments as appose to SynchronizedMemoryPool that allocates the 31 * entire storage once and as a continuous block. It will also deallocates 32 * storage once it's not used for a long time to balance memory usage and 33 * thrashing. These properties lead to a lower memory usage in average time and 34 * also prevents heap fragmentation. 35 * 36 * @tparam ElementType the element to store in ths expandable memory pool. 37 * @tparam kMemoryPoolSize the size of each element pool (each block). 38 * @tparam kMaxMemoryPoolCount the maximum number of memory blocks. 39 */ 40 template <typename ElementType, size_t kMemoryPoolSize, 41 size_t kMaxMemoryPoolCount> 42 class SynchronizedExpandableMemoryPool : public NonCopyable { 43 using Block = ::chre::MemoryPool<ElementType, kMemoryPoolSize>; 44 static_assert(kMemoryPoolSize > 0); 45 46 public: 47 /** 48 * Construct a new Synchronized Expandable Memory Pool object. 49 * The maximum memory that this pool will allocate is maxMemoryPoolCount 50 * kMemoryPoolSize * sizeof(ElementType). 51 * 52 * @param staticBlockCount the number of blocks that will be allocate in the 53 * constructor and will only be deallocate by the destructor. Needs to be 54 * bigger than zero to avoid thrashing. 55 */ 56 SynchronizedExpandableMemoryPool(size_t staticBlockCount = 1); 57 58 /** 59 * Allocates space for an object, constructs it and returns the pointer to 60 * that object. This method is thread-safe and a lock will be acquired 61 * upon entry to this method. 62 * 63 * @param The arguments to be forwarded to the constructor of the object. 64 * @return A pointer to a constructed object or nullptr if the allocation 65 * fails. 66 */ 67 template <typename... Args> 68 ElementType *allocate(Args &&...args); 69 70 /** 71 * Releases the memory of a previously allocated element. The pointer provided 72 * here must be one that was produced by a previous call to the allocate() 73 * function. The destructor is invoked on the object. This method is 74 * thread-safe and a lock will be acquired upon entry to this method. 75 * 76 * @param A pointer to an element that was previously allocated by the 77 * allocate() function. 78 */ 79 void deallocate(ElementType *element); 80 81 /** 82 * @return the number of new element that this memory pool can add. 83 */ 84 size_t getFreeSpaceCount(); 85 86 /** 87 * @return size_t Return the number of blocks currently in the memory pool. 88 */ 89 size_t getBlockCount(); 90 91 /** 92 * @return if the memory pool is full. 93 */ 94 inline bool full(); 95 96 private: 97 //! Number of blocks that will be allocate in the beginning and will only be 98 //! deallocate by the destructor. 99 const size_t kStaticBlockCount; 100 101 //! Number of elements that this memory pool currently hold. 102 size_t mSize = 0; 103 104 //! The mutex used to guard access to this memory pool. 105 Mutex mMutex; 106 107 //! A fixed sized container that wraps around non-synchronized 108 //! MemoryPools used to implement this thread-safe and expandable version 109 //! version. 110 FixedSizeVector<UniquePtr<Block>, kMaxMemoryPoolCount> mMemoryPoolPtrs; 111 112 /** 113 * Push one memory pool to the end of the vector. 114 * 115 * @return true if a new memory pool can be allocated. 116 */ 117 bool pushOneBlock(); 118 119 /** 120 * @return true if this block is more than half full. 121 */ 122 bool isHalfFullBlock(Block *block); 123 }; 124 125 } // namespace chre 126 127 #include "chre/util/system/synchronized_expandable_memory_pool_impl.h" // IWYU pragma: export 128 129 #endif // CHRE_UTIL_SYSTEM_SYNCHRONIZED_EXPANDABLE_MEMORY_POOL_H_ 130