1/* 2 * Copyright (C) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "buffer/avsharedmemorybase.h" 17#include "common/avsharedmemorypool.h" 18#include "common/log.h" 19#include "scope_guard.h" 20 21namespace { 22constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_FOUNDATION, "AVSharedMemoryPool" }; 23} 24 25namespace { 26 constexpr int32_t MAX_MEM_SIZE = 100 * 1024 * 1024; 27} 28 29namespace OHOS { 30namespace Media { 31AVSharedMemoryPool::AVSharedMemoryPool(const std::string &name) : name_(name) 32{ 33 MEDIA_LOG_D("enter ctor, 0x%{public}06" PRIXPTR ", name: %{public}s", FAKE_POINTER(this), name_.c_str()); 34} 35 36AVSharedMemoryPool::~AVSharedMemoryPool() 37{ 38 MEDIA_LOG_D("enter dtor, 0x%{public}06" PRIXPTR ", name: %{public}s", FAKE_POINTER(this), name_.c_str()); 39 Reset(); 40} 41 42int32_t AVSharedMemoryPool::Init(const InitializeOption &option) 43{ 44 std::unique_lock<std::mutex> lock(mutex_); 45 46 FALSE_RETURN_V_MSG_E(!inited_, -1, "memory pool has inited."); 47 FALSE_RETURN_V_MSG_E(option.memSize < MAX_MEM_SIZE, -1, "memSize is larger than MAX_MEM_SIZE."); 48 FALSE_RETURN_V_MSG_E(option.maxMemCnt != 0, -1, "maxMemCnt is equal to zero."); 49 50 option_ = option; 51 option_.preAllocMemCnt = std::min(option.preAllocMemCnt, option.maxMemCnt); 52 53 MEDIA_LOG_I("name: %{public}s, init option: preAllocMemCnt = %{public}u, memSize = %{public}d, " 54 "maxMemCnt = %{public}u, enableFixedSize = %{public}d", 55 name_.c_str(), option_.preAllocMemCnt, option_.memSize, option_.maxMemCnt, 56 option_.enableFixedSize); 57 for (uint32_t i = 0; i < option_.preAllocMemCnt; ++i) { 58 auto memory = AllocMemory(option_.memSize); 59 FALSE_RETURN_V_MSG_E(memory != nullptr, -1, "failed to AllocMemory"); 60 idleList_.push_back(memory); 61 } 62 63 inited_ = true; 64 notifier_ = option.notifier; 65 return 0; 66} 67 68AVSharedMemory *AVSharedMemoryPool::AllocMemory(int32_t size) 69{ 70 AVSharedMemoryBase *memory = new (std::nothrow) AVSharedMemoryBase(size, option_.flags, name_); 71 FALSE_RETURN_V_MSG_E(memory != nullptr, nullptr, "create object failed"); 72 ON_SCOPE_EXIT(0) { delete memory; }; 73 memory->Init(); 74 int32_t ret = memory->Init(); 75 FALSE_RETURN_V_MSG_E(ret == 0, nullptr, "init avsharedmemorybase failed"); 76 77 CANCEL_SCOPE_EXIT_GUARD(0); 78 return memory; 79} 80 81void AVSharedMemoryPool::ReleaseMemory(AVSharedMemory *memory) 82{ 83 FALSE_LOG_MSG(memory != nullptr, "memory is nullptr"); 84 std::unique_lock<std::mutex> lock(mutex_); 85 86 for (auto iter = busyList_.begin(); iter != busyList_.end(); ++iter) { 87 if (*iter != memory) { 88 continue; 89 } 90 91 busyList_.erase(iter); 92 idleList_.push_back(memory); 93 cond_.notify_all(); 94 MEDIA_LOG_D("0x%{public}06" PRIXPTR " released back to pool %{public}s", 95 FAKE_POINTER(memory), name_.c_str()); 96 97 lock.unlock(); 98 if (notifier_ != nullptr) { 99 notifier_(); 100 } 101 return; 102 } 103 104 MEDIA_LOG_E("0x%{public}06" PRIXPTR " is no longer managed by this pool", FAKE_POINTER(memory)); 105 delete memory; 106} 107 108bool AVSharedMemoryPool::DoAcquireMemory(int32_t size, AVSharedMemory **outMemory) 109{ 110 MEDIA_LOG_D("busylist size " PUBLIC_LOG_ZU ", idlelist size " PUBLIC_LOG_ZU, busyList_.size(), idleList_.size()); 111 112 AVSharedMemory *result = nullptr; 113 std::list<AVSharedMemory *>::iterator minSizeIdleMem = idleList_.end(); 114 int32_t minIdleSize = std::numeric_limits<int32_t>::max(); 115 116 for (auto iter = idleList_.begin(); iter != idleList_.end(); ++iter) { 117 if ((*iter)->GetSize() >= size) { 118 result = *iter; 119 idleList_.erase(iter); 120 break; 121 } 122 123 if ((*iter)->GetSize() < minIdleSize) { 124 minIdleSize = (*iter)->GetSize(); 125 minSizeIdleMem = iter; 126 } 127 } 128 129 if (result == nullptr) { 130 auto totalCnt = busyList_.size() + idleList_.size(); 131 if (totalCnt < option_.maxMemCnt) { 132 result = AllocMemory(size); 133 FALSE_RETURN_V_MSG_E(result != nullptr, false, "result is nullptr"); 134 FALSE_RETURN_V(result != nullptr, false); 135 } 136 137 if (!option_.enableFixedSize && minSizeIdleMem != idleList_.end()) { 138 delete *minSizeIdleMem; 139 *minSizeIdleMem = nullptr; 140 idleList_.erase(minSizeIdleMem); 141 result = AllocMemory(size); 142 FALSE_RETURN_V_MSG_E(result != nullptr, false, "result is nullptr"); 143 FALSE_RETURN_V(result != nullptr, false); 144 } 145 } 146 147 *outMemory = result; 148 return true; 149} 150 151bool AVSharedMemoryPool::CheckSize(int32_t size) 152{ 153 if (size <= 0 && size != -1) { 154 return false; 155 } 156 157 if (!option_.enableFixedSize && size == -1) { 158 return false; 159 } 160 161 if (option_.enableFixedSize) { 162 if (size > option_.memSize) { 163 return false; 164 } 165 166 if (size <= 0 && size != -1) { 167 return false; 168 } 169 } 170 171 return true; 172} 173 174std::shared_ptr<AVSharedMemory> AVSharedMemoryPool::AcquireMemory(int32_t size, bool blocking) 175{ 176 MEDIA_LOG_D("acquire memory for size: %{public}d from pool %{public}s, blocking: %{public}d", 177 size, name_.c_str(), blocking); 178 179 std::unique_lock<std::mutex> lock(mutex_); 180 FALSE_RETURN_V_MSG_E(CheckSize(size), nullptr, "invalid size: %{public}d", size); 181 182 if (option_.enableFixedSize) { 183 size = option_.memSize; 184 } 185 186 AVSharedMemory *memory = nullptr; 187 do { 188 if (!DoAcquireMemory(size, &memory) || memory != nullptr) { 189 break; 190 } 191 192 if (!blocking || forceNonBlocking_) { 193 break; 194 } 195 196 cond_.wait(lock); 197 } while (inited_ && !forceNonBlocking_); 198 199 FALSE_RETURN_V_MSG_E(memory != nullptr, nullptr, "acquire memory failed for size: %{public}d", size); 200 busyList_.push_back(memory); 201 202 auto result = std::shared_ptr<AVSharedMemory>(memory, [weakPool = weak_from_this()](AVSharedMemory *memory) { 203 std::shared_ptr<AVSharedMemoryPool> pool = weakPool.lock(); 204 if (pool != nullptr) { 205 pool->ReleaseMemory(memory); 206 } else { 207 MEDIA_LOG_I("release memory 0x%{public}06" PRIXPTR ", but the pool is destroyed", FAKE_POINTER(memory)); 208 delete memory; 209 } 210 }); 211 212 MEDIA_LOG_D("0x%{public}06" PRIXPTR " acquired from pool", FAKE_POINTER(memory)); 213 return result; 214} 215 216void AVSharedMemoryPool::SetNonBlocking(bool enable) 217{ 218 std::unique_lock<std::mutex> lock(mutex_); 219 MEDIA_LOG_D("SetNonBlocking: %{public}d", enable); 220 forceNonBlocking_ = enable; 221 if (forceNonBlocking_) { 222 cond_.notify_all(); 223 } 224} 225 226void AVSharedMemoryPool::Reset() 227{ 228 MEDIA_LOG_D("Reset"); 229 230 std::unique_lock<std::mutex> lock(mutex_); 231 for (auto &memory : idleList_) { 232 delete memory; 233 memory = nullptr; 234 } 235 idleList_.clear(); 236 inited_ = false; 237 forceNonBlocking_ = false; 238 notifier_ = nullptr; 239 cond_.notify_all(); 240 // for busylist, the memory will be released when the refcount of shared_ptr is zero. 241} 242} // namespace Media 243} // namespace OHOS