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