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
21 namespace {
22 constexpr int32_t MAX_MEM_SIZE = 100 * 1024 * 1024;
23 }
24
25 namespace OHOS {
26 namespace Media {
AVSharedMemoryPool(const std::string & name)27 AVSharedMemoryPool::AVSharedMemoryPool(const std::string &name) : name_(name)
28 {
29 MEDIA_LOG_D("enter ctor, 0x%{public}06" PRIXPTR ", name: %{public}s", FAKE_POINTER(this), name_.c_str());
30 }
31
~AVSharedMemoryPool()32 AVSharedMemoryPool::~AVSharedMemoryPool()
33 {
34 MEDIA_LOG_D("enter dtor, 0x%{public}06" PRIXPTR ", name: %{public}s", FAKE_POINTER(this), name_.c_str());
35 Reset();
36 }
37
Init(const InitializeOption & option)38 int32_t AVSharedMemoryPool::Init(const InitializeOption &option)
39 {
40 std::unique_lock<std::mutex> lock(mutex_);
41
42 FALSE_RETURN_V_MSG_E(!inited_, -1, "memory pool has inited.");
43 FALSE_RETURN_V_MSG_E(option.memSize < MAX_MEM_SIZE, -1, "memSize is larger than MAX_MEM_SIZE.");
44 FALSE_RETURN_V_MSG_E(option.maxMemCnt != 0, -1, "maxMemCnt is equal to zero.");
45
46 option_ = option;
47 option_.preAllocMemCnt = std::min(option.preAllocMemCnt, option.maxMemCnt);
48
49 MEDIA_LOG_I("name: %{public}s, init option: preAllocMemCnt = %{public}u, memSize = %{public}d, "
50 "maxMemCnt = %{public}u, enableFixedSize = %{public}d",
51 name_.c_str(), option_.preAllocMemCnt, option_.memSize, option_.maxMemCnt,
52 option_.enableFixedSize);
53 for (uint32_t i = 0; i < option_.preAllocMemCnt; ++i) {
54 auto memory = AllocMemory(option_.memSize);
55 FALSE_RETURN_V_MSG_E(memory != nullptr, -1, "failed to AllocMemory");
56 idleList_.push_back(memory);
57 }
58
59 inited_ = true;
60 notifier_ = option.notifier;
61 return 0;
62 }
63
AllocMemory(int32_t size)64 AVSharedMemory *AVSharedMemoryPool::AllocMemory(int32_t size)
65 {
66 AVSharedMemoryBase *memory = new (std::nothrow) AVSharedMemoryBase(size, option_.flags, name_);
67 FALSE_RETURN_V_MSG_E(memory != nullptr, nullptr, "create object failed");
68 ON_SCOPE_EXIT(0) { delete memory; };
69 memory->Init();
70 int32_t ret = memory->Init();
71 FALSE_RETURN_V_MSG_E(ret == 0, nullptr, "init avsharedmemorybase failed");
72
73 CANCEL_SCOPE_EXIT_GUARD(0);
74 return memory;
75 }
76
ReleaseMemory(AVSharedMemory * memory)77 void AVSharedMemoryPool::ReleaseMemory(AVSharedMemory *memory)
78 {
79 FALSE_LOG_MSG(memory != nullptr, "memory is nullptr");
80 std::unique_lock<std::mutex> lock(mutex_);
81
82 for (auto iter = busyList_.begin(); iter != busyList_.end(); ++iter) {
83 if (*iter != memory) {
84 continue;
85 }
86
87 busyList_.erase(iter);
88 idleList_.push_back(memory);
89 cond_.notify_all();
90 MEDIA_LOG_D("0x%{public}06" PRIXPTR " released back to pool %{public}s",
91 FAKE_POINTER(memory), name_.c_str());
92
93 lock.unlock();
94 if (notifier_ != nullptr) {
95 notifier_();
96 }
97 return;
98 }
99
100 MEDIA_LOG_E("0x%{public}06" PRIXPTR " is no longer managed by this pool", FAKE_POINTER(memory));
101 delete memory;
102 }
103
DoAcquireMemory(int32_t size,AVSharedMemory ** outMemory)104 bool AVSharedMemoryPool::DoAcquireMemory(int32_t size, AVSharedMemory **outMemory)
105 {
106 MEDIA_LOG_D("busylist size " PUBLIC_LOG_ZU ", idlelist size " PUBLIC_LOG_ZU, busyList_.size(), idleList_.size());
107
108 AVSharedMemory *result = nullptr;
109 std::list<AVSharedMemory *>::iterator minSizeIdleMem = idleList_.end();
110 int32_t minIdleSize = std::numeric_limits<int32_t>::max();
111
112 for (auto iter = idleList_.begin(); iter != idleList_.end(); ++iter) {
113 if ((*iter)->GetSize() >= size) {
114 result = *iter;
115 idleList_.erase(iter);
116 break;
117 }
118
119 if ((*iter)->GetSize() < minIdleSize) {
120 minIdleSize = (*iter)->GetSize();
121 minSizeIdleMem = iter;
122 }
123 }
124
125 if (result == nullptr) {
126 auto totalCnt = busyList_.size() + idleList_.size();
127 if (totalCnt < option_.maxMemCnt) {
128 result = AllocMemory(size);
129 FALSE_RETURN_V_MSG_E(result != nullptr, false, "result is nullptr");
130 FALSE_RETURN_V(result != nullptr, false);
131 }
132
133 if (!option_.enableFixedSize && minSizeIdleMem != idleList_.end()) {
134 delete *minSizeIdleMem;
135 *minSizeIdleMem = nullptr;
136 idleList_.erase(minSizeIdleMem);
137 result = AllocMemory(size);
138 FALSE_RETURN_V_MSG_E(result != nullptr, false, "result is nullptr");
139 FALSE_RETURN_V(result != nullptr, false);
140 }
141 }
142
143 *outMemory = result;
144 return true;
145 }
146
CheckSize(int32_t size)147 bool AVSharedMemoryPool::CheckSize(int32_t size)
148 {
149 if (size <= 0 && size != -1) {
150 return false;
151 }
152
153 if (!option_.enableFixedSize && size == -1) {
154 return false;
155 }
156
157 if (option_.enableFixedSize) {
158 if (size > option_.memSize) {
159 return false;
160 }
161
162 if (size <= 0 && size != -1) {
163 return false;
164 }
165 }
166
167 return true;
168 }
169
AcquireMemory(int32_t size,bool blocking)170 std::shared_ptr<AVSharedMemory> AVSharedMemoryPool::AcquireMemory(int32_t size, bool blocking)
171 {
172 MEDIA_LOG_D("acquire memory for size: %{public}d from pool %{public}s, blocking: %{public}d",
173 size, name_.c_str(), blocking);
174
175 std::unique_lock<std::mutex> lock(mutex_);
176 FALSE_RETURN_V_MSG_E(CheckSize(size), nullptr, "invalid size: %{public}d", size);
177
178 if (option_.enableFixedSize) {
179 size = option_.memSize;
180 }
181
182 AVSharedMemory *memory = nullptr;
183 do {
184 if (!DoAcquireMemory(size, &memory) || memory != nullptr) {
185 break;
186 }
187
188 if (!blocking || forceNonBlocking_) {
189 break;
190 }
191
192 cond_.wait(lock);
193 } while (inited_ && !forceNonBlocking_);
194
195 FALSE_RETURN_V_MSG_E(memory != nullptr, nullptr, "acquire memory failed for size: %{public}d", size);
196 busyList_.push_back(memory);
197
198 auto result = std::shared_ptr<AVSharedMemory>(memory, [weakPool = weak_from_this()](AVSharedMemory *memory) {
199 std::shared_ptr<AVSharedMemoryPool> pool = weakPool.lock();
200 if (pool != nullptr) {
201 pool->ReleaseMemory(memory);
202 } else {
203 MEDIA_LOG_I("release memory 0x%{public}06" PRIXPTR ", but the pool is destroyed", FAKE_POINTER(memory));
204 delete memory;
205 }
206 });
207
208 MEDIA_LOG_D("0x%{public}06" PRIXPTR " acquired from pool", FAKE_POINTER(memory));
209 return result;
210 }
211
SetNonBlocking(bool enable)212 void AVSharedMemoryPool::SetNonBlocking(bool enable)
213 {
214 std::unique_lock<std::mutex> lock(mutex_);
215 MEDIA_LOG_D("SetNonBlocking: %{public}d", enable);
216 forceNonBlocking_ = enable;
217 if (forceNonBlocking_) {
218 cond_.notify_all();
219 }
220 }
221
Reset()222 void AVSharedMemoryPool::Reset()
223 {
224 MEDIA_LOG_D("Reset");
225
226 std::unique_lock<std::mutex> lock(mutex_);
227 for (auto &memory : idleList_) {
228 delete memory;
229 memory = nullptr;
230 }
231 idleList_.clear();
232 inited_ = false;
233 forceNonBlocking_ = false;
234 notifier_ = nullptr;
235 cond_.notify_all();
236 // for busylist, the memory will be released when the refcount of shared_ptr is zero.
237 }
238 } // namespace Media
239 } // namespace OHOS