• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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