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