xref: /aosp_15_r20/system/chre/util/include/chre/util/system/synchronized_expandable_memory_pool.h (revision 84e339476a462649f82315436d70fd732297a399)
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