• 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 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