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