• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_FOUNDATION, "AVSharedMemoryPool" };
23 }
24 
25 namespace {
26     constexpr int32_t MAX_MEM_SIZE = 100 * 1024 * 1024;
27     constexpr uint32_t MAX_MEM_CNT = 10 * 1024;
28 }
29 
30 namespace OHOS {
31 namespace Media {
AVSharedMemoryPool(const std::string & name)32 AVSharedMemoryPool::AVSharedMemoryPool(const std::string &name) : name_(name)
33 {
34     MEDIA_LOG_D("enter ctor, 0x%{public}06" PRIXPTR ", name: %{public}s", FAKE_POINTER(this), name_.c_str());
35 }
36 
~AVSharedMemoryPool()37 AVSharedMemoryPool::~AVSharedMemoryPool()
38 {
39     MEDIA_LOG_D("enter dtor, 0x%{public}06" PRIXPTR ", name: %{public}s", FAKE_POINTER(this), name_.c_str());
40     Reset();
41 }
42 
Init(const InitializeOption & option)43 int32_t AVSharedMemoryPool::Init(const InitializeOption &option)
44 {
45     std::unique_lock<std::mutex> lock(mutex_);
46 
47     FALSE_RETURN_V_MSG_E(!inited_, -1, "memory pool has inited.");
48     FALSE_RETURN_V_MSG_E(option.memSize < MAX_MEM_SIZE, -1, "memSize is larger than MAX_MEM_SIZE.");
49     FALSE_RETURN_V_MSG_E(option.maxMemCnt > 0 && option.maxMemCnt <= MAX_MEM_CNT, -1, "maxMemCnt is invalid.");
50 
51     option_ = option;
52     option_.preAllocMemCnt = std::min(option.preAllocMemCnt, option.maxMemCnt);
53 
54     MEDIA_LOG_I("name: %{public}s, init option: preAllocMemCnt = %{public}u, memSize = %{public}d, "
55         "maxMemCnt = %{public}u, enableFixedSize = %{public}d",
56         name_.c_str(), option_.preAllocMemCnt, option_.memSize, option_.maxMemCnt,
57         option_.enableFixedSize);
58     for (uint32_t i = 0; i < option_.preAllocMemCnt; ++i) {
59         auto memory = AllocMemory(option_.memSize);
60         FALSE_RETURN_V_MSG_E(memory != nullptr, -1, "failed to AllocMemory");
61         idleList_.push_back(memory);
62     }
63 
64     inited_ = true;
65     notifier_ = option.notifier;
66     return 0;
67 }
68 
AllocMemory(int32_t size)69 AVSharedMemory *AVSharedMemoryPool::AllocMemory(int32_t size)
70 {
71     AVSharedMemoryBase *memory = new (std::nothrow) AVSharedMemoryBase(size, option_.flags, name_);
72     FALSE_RETURN_V_MSG_E(memory != nullptr, nullptr, "create object failed");
73     ON_SCOPE_EXIT(0) { delete memory; };
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 
ReleaseMemory(AVSharedMemory * memory)81 void 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 
DoAcquireMemory(int32_t size,AVSharedMemory ** outMemory)108 bool 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         } else if (!option_.enableFixedSize && minSizeIdleMem != idleList_.end()) {
136             delete *minSizeIdleMem;
137             *minSizeIdleMem = nullptr;
138             idleList_.erase(minSizeIdleMem);
139             result = AllocMemory(size);
140             FALSE_RETURN_V_MSG_E(result != nullptr, false, "result is nullptr");
141             FALSE_RETURN_V(result != nullptr, false);
142         }
143     }
144 
145     *outMemory = result;
146     return true;
147 }
148 
CheckSize(int32_t size)149 bool AVSharedMemoryPool::CheckSize(int32_t size)
150 {
151     if (size <= 0 && size != -1) {
152         return false;
153     }
154 
155     if (!option_.enableFixedSize && size == -1) {
156         return false;
157     }
158 
159     if (option_.enableFixedSize) {
160         if (size > option_.memSize) {
161             return false;
162         }
163 
164         if (size <= 0 && size != -1) {
165             return false;
166         }
167     }
168 
169     return true;
170 }
171 
AcquireMemory(int32_t size,bool blocking)172 std::shared_ptr<AVSharedMemory> AVSharedMemoryPool::AcquireMemory(int32_t size, bool blocking)
173 {
174     MEDIA_LOG_D("acquire memory for size: %{public}d from pool %{public}s, blocking: %{public}d",
175         size, name_.c_str(), blocking);
176 
177     std::unique_lock<std::mutex> lock(mutex_);
178     FALSE_RETURN_V_MSG_E(CheckSize(size), nullptr, "invalid size: %{public}d", size);
179 
180     if (option_.enableFixedSize) {
181         size = option_.memSize;
182     }
183 
184     AVSharedMemory *memory = nullptr;
185     do {
186         if (!DoAcquireMemory(size, &memory) || memory != nullptr) {
187             break;
188         }
189 
190         if (!blocking || forceNonBlocking_) {
191             break;
192         }
193 
194         cond_.wait(lock);
195     } while (inited_ && !forceNonBlocking_);
196 
197     FALSE_RETURN_V_MSG_E(memory != nullptr, nullptr, "acquire memory failed for size: %{public}d", size);
198     busyList_.push_back(memory);
199 
200     auto result = std::shared_ptr<AVSharedMemory>(memory, [weakPool = weak_from_this()](AVSharedMemory *memory) {
201         std::shared_ptr<AVSharedMemoryPool> pool = weakPool.lock();
202         if (pool != nullptr) {
203             pool->ReleaseMemory(memory);
204         } else {
205             MEDIA_LOG_I("release memory 0x%{public}06" PRIXPTR ", but the pool is destroyed", FAKE_POINTER(memory));
206             delete memory;
207         }
208     });
209 
210     MEDIA_LOG_D("0x%{public}06" PRIXPTR " acquired from pool", FAKE_POINTER(memory));
211     return result;
212 }
213 
SetNonBlocking(bool enable)214 void AVSharedMemoryPool::SetNonBlocking(bool enable)
215 {
216     std::unique_lock<std::mutex> lock(mutex_);
217     MEDIA_LOG_D("SetNonBlocking: %{public}d", enable);
218     forceNonBlocking_ = enable;
219     if (forceNonBlocking_) {
220         cond_.notify_all();
221     }
222 }
223 
Reset()224 void AVSharedMemoryPool::Reset()
225 {
226     MEDIA_LOG_D("Reset");
227 
228     std::unique_lock<std::mutex> lock(mutex_);
229     for (auto &memory : idleList_) {
230         delete memory;
231         memory = nullptr;
232     }
233     idleList_.clear();
234     inited_ = false;
235     forceNonBlocking_ = false;
236     notifier_ = nullptr;
237     cond_.notify_all();
238     // for busylist, the memory will be released when the refcount of shared_ptr is zero.
239 }
240 } // namespace Media
241 } // namespace OHOS