xref: /aosp_15_r20/system/chre/util/include/chre/util/system/synchronized_expandable_memory_pool_impl.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_IMPL_H_
18 #define CHRE_UTIL_SYSTEM_SYNCHRONIZED_EXPANDABLE_MEMORY_POOL_IMPL_H_
19 
20 // IWYU pragma: private
21 #include <algorithm>
22 
23 #include "chre/util/lock_guard.h"
24 #include "chre/util/memory_pool.h"
25 #include "chre/util/system/synchronized_expandable_memory_pool.h"
26 
27 namespace chre {
28 
29 template <typename ElementType, size_t kMemoryPoolSize,
30           size_t kMaxMemoryPoolCount>
31 SynchronizedExpandableMemoryPool<ElementType, kMemoryPoolSize,
32                                  kMaxMemoryPoolCount>::
SynchronizedExpandableMemoryPool(size_t staticBlockCount)33     SynchronizedExpandableMemoryPool(size_t staticBlockCount)
34     : kStaticBlockCount(staticBlockCount) {
35   CHRE_ASSERT(staticBlockCount > 0);
36   CHRE_ASSERT(kMaxMemoryPoolCount >= staticBlockCount);
37   for (uint8_t i = 0; i < kStaticBlockCount; i++) {
38     pushOneBlock();
39   }
40 }
41 
42 template <typename ElementType, size_t kMemoryPoolSize,
43           size_t kMaxMemoryPoolCount>
44 template <typename... Args>
45 ElementType *SynchronizedExpandableMemoryPool<
46     ElementType, kMemoryPoolSize,
allocate(Args &&...args)47     kMaxMemoryPoolCount>::allocate(Args &&...args) {
48   LockGuard<Mutex> lock(mMutex);
49   ElementType *result = nullptr;
50 
51   // TODO(b/259286151): Optimizing using pointer to a non-full block
52   for (UniquePtr<Block> &memoryPool : mMemoryPoolPtrs) {
53     result = memoryPool->allocate(args...);
54     if (result != nullptr) {
55       break;
56     }
57   }
58 
59   if (result == nullptr && pushOneBlock()) {
60     result = mMemoryPoolPtrs.back()->allocate(args...);
61   }
62 
63   if (result != nullptr) {
64     ++mSize;
65   }
66 
67   return result;
68 }
69 
70 template <typename ElementType, size_t kMemoryPoolSize,
71           size_t kMaxMemoryPoolCount>
72 void SynchronizedExpandableMemoryPool<
73     ElementType, kMemoryPoolSize,
deallocate(ElementType * element)74     kMaxMemoryPoolCount>::deallocate(ElementType *element) {
75   bool success = false;
76   LockGuard<Mutex> lock(mMutex);
77   for (UniquePtr<Block> &memoryPool : mMemoryPoolPtrs) {
78     if (memoryPool->containsAddress(element)) {
79       success = true;
80       memoryPool->deallocate(element);
81       break;
82     }
83   }
84   if (!success) {
85     CHRE_ASSERT(false);
86   } else {
87     --mSize;
88     while (
89         mMemoryPoolPtrs.size() > std::max(kStaticBlockCount, size_t(1)) &&
90         mMemoryPoolPtrs.back()->empty() &&
91         !isHalfFullBlock(mMemoryPoolPtrs[mMemoryPoolPtrs.size() - 2].get())) {
92       mMemoryPoolPtrs.pop_back();
93     }
94   }
95 }
96 
97 template <typename ElementType, size_t kMemoryPoolSize,
98           size_t kMaxMemoryPoolCount>
99 size_t SynchronizedExpandableMemoryPool<
getFreeSpaceCount()100     ElementType, kMemoryPoolSize, kMaxMemoryPoolCount>::getFreeSpaceCount() {
101   LockGuard<Mutex> lock(mMutex);
102   return kMaxMemoryPoolCount * kMemoryPoolSize - mSize;
103 }
104 
105 template <typename ElementType, size_t kMemoryPoolSize,
106           size_t kMaxMemoryPoolCount>
107 bool SynchronizedExpandableMemoryPool<ElementType, kMemoryPoolSize,
full()108                                       kMaxMemoryPoolCount>::full() {
109   LockGuard<Mutex> lock(mMutex);
110   return kMaxMemoryPoolCount * kMemoryPoolSize == mSize;
111 }
112 
113 template <typename ElementType, size_t kMemoryPoolSize,
114           size_t kMaxMemoryPoolCount>
115 size_t SynchronizedExpandableMemoryPool<ElementType, kMemoryPoolSize,
getBlockCount()116                                         kMaxMemoryPoolCount>::getBlockCount() {
117   LockGuard<Mutex> lock(mMutex);
118   return mMemoryPoolPtrs.size();
119 }
120 
121 template <typename ElementType, size_t kMemoryPoolSize,
122           size_t kMaxMemoryPoolCount>
123 bool SynchronizedExpandableMemoryPool<ElementType, kMemoryPoolSize,
pushOneBlock()124                                       kMaxMemoryPoolCount>::pushOneBlock() {
125   bool success = false;
126   if (mMemoryPoolPtrs.size() < kMaxMemoryPoolCount) {
127     auto newBlock = MakeUnique<Block>();
128     if (!newBlock.isNull()) {
129       success = true;
130       mMemoryPoolPtrs.push_back(std::move(newBlock));
131     }
132   }
133 
134   if (!success) {
135     LOG_OOM();
136   }
137 
138   return success;
139 }
140 
141 template <typename ElementType, size_t kMemoryPoolSize,
142           size_t kMaxMemoryPoolCount>
143 bool SynchronizedExpandableMemoryPool<
144     ElementType, kMemoryPoolSize,
isHalfFullBlock(Block * block)145     kMaxMemoryPoolCount>::isHalfFullBlock(Block *block) {
146   return block->getFreeBlockCount() < kMemoryPoolSize / 2;
147 }
148 }  // namespace chre
149 
150 #endif  // CHRE_UTIL_SYSTEM_SYNCHRONIZED_EXPANDABLE_MEMORY_POOL_IMPL_H_
151