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