1fa7767c5Sopenharmony_ci/*
2fa7767c5Sopenharmony_ci * Copyright (C) 2023 Huawei Device Co., Ltd.
3fa7767c5Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4fa7767c5Sopenharmony_ci * you may not use this file except in compliance with the License.
5fa7767c5Sopenharmony_ci * You may obtain a copy of the License at
6fa7767c5Sopenharmony_ci *
7fa7767c5Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8fa7767c5Sopenharmony_ci *
9fa7767c5Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10fa7767c5Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11fa7767c5Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12fa7767c5Sopenharmony_ci * See the License for the specific language governing permissions and
13fa7767c5Sopenharmony_ci * limitations under the License.
14fa7767c5Sopenharmony_ci */
15fa7767c5Sopenharmony_ci
16fa7767c5Sopenharmony_ci#include "buffer/avsharedmemorybase.h"
17fa7767c5Sopenharmony_ci#include "common/avsharedmemorypool.h"
18fa7767c5Sopenharmony_ci#include "common/log.h"
19fa7767c5Sopenharmony_ci#include "scope_guard.h"
20fa7767c5Sopenharmony_ci
21fa7767c5Sopenharmony_cinamespace {
22fa7767c5Sopenharmony_ciconstexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_FOUNDATION, "AVSharedMemoryPool" };
23fa7767c5Sopenharmony_ci}
24fa7767c5Sopenharmony_ci
25fa7767c5Sopenharmony_cinamespace {
26fa7767c5Sopenharmony_ci    constexpr int32_t MAX_MEM_SIZE = 100 * 1024 * 1024;
27fa7767c5Sopenharmony_ci}
28fa7767c5Sopenharmony_ci
29fa7767c5Sopenharmony_cinamespace OHOS {
30fa7767c5Sopenharmony_cinamespace Media {
31fa7767c5Sopenharmony_ciAVSharedMemoryPool::AVSharedMemoryPool(const std::string &name) : name_(name)
32fa7767c5Sopenharmony_ci{
33fa7767c5Sopenharmony_ci    MEDIA_LOG_D("enter ctor, 0x%{public}06" PRIXPTR ", name: %{public}s", FAKE_POINTER(this), name_.c_str());
34fa7767c5Sopenharmony_ci}
35fa7767c5Sopenharmony_ci
36fa7767c5Sopenharmony_ciAVSharedMemoryPool::~AVSharedMemoryPool()
37fa7767c5Sopenharmony_ci{
38fa7767c5Sopenharmony_ci    MEDIA_LOG_D("enter dtor, 0x%{public}06" PRIXPTR ", name: %{public}s", FAKE_POINTER(this), name_.c_str());
39fa7767c5Sopenharmony_ci    Reset();
40fa7767c5Sopenharmony_ci}
41fa7767c5Sopenharmony_ci
42fa7767c5Sopenharmony_ciint32_t AVSharedMemoryPool::Init(const InitializeOption &option)
43fa7767c5Sopenharmony_ci{
44fa7767c5Sopenharmony_ci    std::unique_lock<std::mutex> lock(mutex_);
45fa7767c5Sopenharmony_ci
46fa7767c5Sopenharmony_ci    FALSE_RETURN_V_MSG_E(!inited_, -1, "memory pool has inited.");
47fa7767c5Sopenharmony_ci    FALSE_RETURN_V_MSG_E(option.memSize < MAX_MEM_SIZE, -1, "memSize is larger than MAX_MEM_SIZE.");
48fa7767c5Sopenharmony_ci    FALSE_RETURN_V_MSG_E(option.maxMemCnt != 0, -1, "maxMemCnt is equal to zero.");
49fa7767c5Sopenharmony_ci
50fa7767c5Sopenharmony_ci    option_ = option;
51fa7767c5Sopenharmony_ci    option_.preAllocMemCnt = std::min(option.preAllocMemCnt, option.maxMemCnt);
52fa7767c5Sopenharmony_ci
53fa7767c5Sopenharmony_ci    MEDIA_LOG_I("name: %{public}s, init option: preAllocMemCnt = %{public}u, memSize = %{public}d, "
54fa7767c5Sopenharmony_ci        "maxMemCnt = %{public}u, enableFixedSize = %{public}d",
55fa7767c5Sopenharmony_ci        name_.c_str(), option_.preAllocMemCnt, option_.memSize, option_.maxMemCnt,
56fa7767c5Sopenharmony_ci        option_.enableFixedSize);
57fa7767c5Sopenharmony_ci    for (uint32_t i = 0; i < option_.preAllocMemCnt; ++i) {
58fa7767c5Sopenharmony_ci        auto memory = AllocMemory(option_.memSize);
59fa7767c5Sopenharmony_ci        FALSE_RETURN_V_MSG_E(memory != nullptr, -1, "failed to AllocMemory");
60fa7767c5Sopenharmony_ci        idleList_.push_back(memory);
61fa7767c5Sopenharmony_ci    }
62fa7767c5Sopenharmony_ci
63fa7767c5Sopenharmony_ci    inited_ = true;
64fa7767c5Sopenharmony_ci    notifier_ = option.notifier;
65fa7767c5Sopenharmony_ci    return 0;
66fa7767c5Sopenharmony_ci}
67fa7767c5Sopenharmony_ci
68fa7767c5Sopenharmony_ciAVSharedMemory *AVSharedMemoryPool::AllocMemory(int32_t size)
69fa7767c5Sopenharmony_ci{
70fa7767c5Sopenharmony_ci    AVSharedMemoryBase *memory = new (std::nothrow) AVSharedMemoryBase(size, option_.flags, name_);
71fa7767c5Sopenharmony_ci    FALSE_RETURN_V_MSG_E(memory != nullptr, nullptr, "create object failed");
72fa7767c5Sopenharmony_ci    ON_SCOPE_EXIT(0) { delete memory; };
73fa7767c5Sopenharmony_ci    memory->Init();
74fa7767c5Sopenharmony_ci    int32_t ret = memory->Init();
75fa7767c5Sopenharmony_ci    FALSE_RETURN_V_MSG_E(ret == 0, nullptr, "init avsharedmemorybase failed");
76fa7767c5Sopenharmony_ci
77fa7767c5Sopenharmony_ci    CANCEL_SCOPE_EXIT_GUARD(0);
78fa7767c5Sopenharmony_ci    return memory;
79fa7767c5Sopenharmony_ci}
80fa7767c5Sopenharmony_ci
81fa7767c5Sopenharmony_civoid AVSharedMemoryPool::ReleaseMemory(AVSharedMemory *memory)
82fa7767c5Sopenharmony_ci{
83fa7767c5Sopenharmony_ci    FALSE_LOG_MSG(memory != nullptr, "memory is nullptr");
84fa7767c5Sopenharmony_ci    std::unique_lock<std::mutex> lock(mutex_);
85fa7767c5Sopenharmony_ci
86fa7767c5Sopenharmony_ci    for (auto iter = busyList_.begin(); iter != busyList_.end(); ++iter) {
87fa7767c5Sopenharmony_ci        if (*iter != memory) {
88fa7767c5Sopenharmony_ci            continue;
89fa7767c5Sopenharmony_ci        }
90fa7767c5Sopenharmony_ci
91fa7767c5Sopenharmony_ci        busyList_.erase(iter);
92fa7767c5Sopenharmony_ci        idleList_.push_back(memory);
93fa7767c5Sopenharmony_ci        cond_.notify_all();
94fa7767c5Sopenharmony_ci        MEDIA_LOG_D("0x%{public}06" PRIXPTR " released back to pool %{public}s",
95fa7767c5Sopenharmony_ci                    FAKE_POINTER(memory), name_.c_str());
96fa7767c5Sopenharmony_ci
97fa7767c5Sopenharmony_ci        lock.unlock();
98fa7767c5Sopenharmony_ci        if (notifier_ != nullptr) {
99fa7767c5Sopenharmony_ci            notifier_();
100fa7767c5Sopenharmony_ci        }
101fa7767c5Sopenharmony_ci        return;
102fa7767c5Sopenharmony_ci    }
103fa7767c5Sopenharmony_ci
104fa7767c5Sopenharmony_ci    MEDIA_LOG_E("0x%{public}06" PRIXPTR " is no longer managed by this pool", FAKE_POINTER(memory));
105fa7767c5Sopenharmony_ci    delete memory;
106fa7767c5Sopenharmony_ci}
107fa7767c5Sopenharmony_ci
108fa7767c5Sopenharmony_cibool AVSharedMemoryPool::DoAcquireMemory(int32_t size, AVSharedMemory **outMemory)
109fa7767c5Sopenharmony_ci{
110fa7767c5Sopenharmony_ci    MEDIA_LOG_D("busylist size " PUBLIC_LOG_ZU ", idlelist size " PUBLIC_LOG_ZU, busyList_.size(), idleList_.size());
111fa7767c5Sopenharmony_ci
112fa7767c5Sopenharmony_ci    AVSharedMemory *result = nullptr;
113fa7767c5Sopenharmony_ci    std::list<AVSharedMemory *>::iterator minSizeIdleMem = idleList_.end();
114fa7767c5Sopenharmony_ci    int32_t minIdleSize = std::numeric_limits<int32_t>::max();
115fa7767c5Sopenharmony_ci
116fa7767c5Sopenharmony_ci    for (auto iter = idleList_.begin(); iter != idleList_.end(); ++iter) {
117fa7767c5Sopenharmony_ci        if ((*iter)->GetSize() >= size) {
118fa7767c5Sopenharmony_ci            result = *iter;
119fa7767c5Sopenharmony_ci            idleList_.erase(iter);
120fa7767c5Sopenharmony_ci            break;
121fa7767c5Sopenharmony_ci        }
122fa7767c5Sopenharmony_ci
123fa7767c5Sopenharmony_ci        if ((*iter)->GetSize() < minIdleSize) {
124fa7767c5Sopenharmony_ci            minIdleSize = (*iter)->GetSize();
125fa7767c5Sopenharmony_ci            minSizeIdleMem = iter;
126fa7767c5Sopenharmony_ci        }
127fa7767c5Sopenharmony_ci    }
128fa7767c5Sopenharmony_ci
129fa7767c5Sopenharmony_ci    if (result == nullptr) {
130fa7767c5Sopenharmony_ci        auto totalCnt = busyList_.size() + idleList_.size();
131fa7767c5Sopenharmony_ci        if (totalCnt < option_.maxMemCnt) {
132fa7767c5Sopenharmony_ci            result = AllocMemory(size);
133fa7767c5Sopenharmony_ci            FALSE_RETURN_V_MSG_E(result != nullptr, false, "result is nullptr");
134fa7767c5Sopenharmony_ci            FALSE_RETURN_V(result != nullptr, false);
135fa7767c5Sopenharmony_ci        }
136fa7767c5Sopenharmony_ci
137fa7767c5Sopenharmony_ci        if (!option_.enableFixedSize && minSizeIdleMem != idleList_.end()) {
138fa7767c5Sopenharmony_ci            delete *minSizeIdleMem;
139fa7767c5Sopenharmony_ci            *minSizeIdleMem = nullptr;
140fa7767c5Sopenharmony_ci            idleList_.erase(minSizeIdleMem);
141fa7767c5Sopenharmony_ci            result = AllocMemory(size);
142fa7767c5Sopenharmony_ci            FALSE_RETURN_V_MSG_E(result != nullptr, false, "result is nullptr");
143fa7767c5Sopenharmony_ci            FALSE_RETURN_V(result != nullptr, false);
144fa7767c5Sopenharmony_ci        }
145fa7767c5Sopenharmony_ci    }
146fa7767c5Sopenharmony_ci
147fa7767c5Sopenharmony_ci    *outMemory = result;
148fa7767c5Sopenharmony_ci    return true;
149fa7767c5Sopenharmony_ci}
150fa7767c5Sopenharmony_ci
151fa7767c5Sopenharmony_cibool AVSharedMemoryPool::CheckSize(int32_t size)
152fa7767c5Sopenharmony_ci{
153fa7767c5Sopenharmony_ci    if (size <= 0 && size != -1) {
154fa7767c5Sopenharmony_ci        return false;
155fa7767c5Sopenharmony_ci    }
156fa7767c5Sopenharmony_ci
157fa7767c5Sopenharmony_ci    if (!option_.enableFixedSize && size == -1) {
158fa7767c5Sopenharmony_ci        return false;
159fa7767c5Sopenharmony_ci    }
160fa7767c5Sopenharmony_ci
161fa7767c5Sopenharmony_ci    if (option_.enableFixedSize) {
162fa7767c5Sopenharmony_ci        if (size > option_.memSize) {
163fa7767c5Sopenharmony_ci            return false;
164fa7767c5Sopenharmony_ci        }
165fa7767c5Sopenharmony_ci
166fa7767c5Sopenharmony_ci        if (size <= 0 && size != -1) {
167fa7767c5Sopenharmony_ci            return false;
168fa7767c5Sopenharmony_ci        }
169fa7767c5Sopenharmony_ci    }
170fa7767c5Sopenharmony_ci
171fa7767c5Sopenharmony_ci    return true;
172fa7767c5Sopenharmony_ci}
173fa7767c5Sopenharmony_ci
174fa7767c5Sopenharmony_cistd::shared_ptr<AVSharedMemory> AVSharedMemoryPool::AcquireMemory(int32_t size, bool blocking)
175fa7767c5Sopenharmony_ci{
176fa7767c5Sopenharmony_ci    MEDIA_LOG_D("acquire memory for size: %{public}d from pool %{public}s, blocking: %{public}d",
177fa7767c5Sopenharmony_ci        size, name_.c_str(), blocking);
178fa7767c5Sopenharmony_ci
179fa7767c5Sopenharmony_ci    std::unique_lock<std::mutex> lock(mutex_);
180fa7767c5Sopenharmony_ci    FALSE_RETURN_V_MSG_E(CheckSize(size), nullptr, "invalid size: %{public}d", size);
181fa7767c5Sopenharmony_ci
182fa7767c5Sopenharmony_ci    if (option_.enableFixedSize) {
183fa7767c5Sopenharmony_ci        size = option_.memSize;
184fa7767c5Sopenharmony_ci    }
185fa7767c5Sopenharmony_ci
186fa7767c5Sopenharmony_ci    AVSharedMemory *memory = nullptr;
187fa7767c5Sopenharmony_ci    do {
188fa7767c5Sopenharmony_ci        if (!DoAcquireMemory(size, &memory) || memory != nullptr) {
189fa7767c5Sopenharmony_ci            break;
190fa7767c5Sopenharmony_ci        }
191fa7767c5Sopenharmony_ci
192fa7767c5Sopenharmony_ci        if (!blocking || forceNonBlocking_) {
193fa7767c5Sopenharmony_ci            break;
194fa7767c5Sopenharmony_ci        }
195fa7767c5Sopenharmony_ci
196fa7767c5Sopenharmony_ci        cond_.wait(lock);
197fa7767c5Sopenharmony_ci    } while (inited_ && !forceNonBlocking_);
198fa7767c5Sopenharmony_ci
199fa7767c5Sopenharmony_ci    FALSE_RETURN_V_MSG_E(memory != nullptr, nullptr, "acquire memory failed for size: %{public}d", size);
200fa7767c5Sopenharmony_ci    busyList_.push_back(memory);
201fa7767c5Sopenharmony_ci
202fa7767c5Sopenharmony_ci    auto result = std::shared_ptr<AVSharedMemory>(memory, [weakPool = weak_from_this()](AVSharedMemory *memory) {
203fa7767c5Sopenharmony_ci        std::shared_ptr<AVSharedMemoryPool> pool = weakPool.lock();
204fa7767c5Sopenharmony_ci        if (pool != nullptr) {
205fa7767c5Sopenharmony_ci            pool->ReleaseMemory(memory);
206fa7767c5Sopenharmony_ci        } else {
207fa7767c5Sopenharmony_ci            MEDIA_LOG_I("release memory 0x%{public}06" PRIXPTR ", but the pool is destroyed", FAKE_POINTER(memory));
208fa7767c5Sopenharmony_ci            delete memory;
209fa7767c5Sopenharmony_ci        }
210fa7767c5Sopenharmony_ci    });
211fa7767c5Sopenharmony_ci
212fa7767c5Sopenharmony_ci    MEDIA_LOG_D("0x%{public}06" PRIXPTR " acquired from pool", FAKE_POINTER(memory));
213fa7767c5Sopenharmony_ci    return result;
214fa7767c5Sopenharmony_ci}
215fa7767c5Sopenharmony_ci
216fa7767c5Sopenharmony_civoid AVSharedMemoryPool::SetNonBlocking(bool enable)
217fa7767c5Sopenharmony_ci{
218fa7767c5Sopenharmony_ci    std::unique_lock<std::mutex> lock(mutex_);
219fa7767c5Sopenharmony_ci    MEDIA_LOG_D("SetNonBlocking: %{public}d", enable);
220fa7767c5Sopenharmony_ci    forceNonBlocking_ = enable;
221fa7767c5Sopenharmony_ci    if (forceNonBlocking_) {
222fa7767c5Sopenharmony_ci        cond_.notify_all();
223fa7767c5Sopenharmony_ci    }
224fa7767c5Sopenharmony_ci}
225fa7767c5Sopenharmony_ci
226fa7767c5Sopenharmony_civoid AVSharedMemoryPool::Reset()
227fa7767c5Sopenharmony_ci{
228fa7767c5Sopenharmony_ci    MEDIA_LOG_D("Reset");
229fa7767c5Sopenharmony_ci
230fa7767c5Sopenharmony_ci    std::unique_lock<std::mutex> lock(mutex_);
231fa7767c5Sopenharmony_ci    for (auto &memory : idleList_) {
232fa7767c5Sopenharmony_ci        delete memory;
233fa7767c5Sopenharmony_ci        memory = nullptr;
234fa7767c5Sopenharmony_ci    }
235fa7767c5Sopenharmony_ci    idleList_.clear();
236fa7767c5Sopenharmony_ci    inited_ = false;
237fa7767c5Sopenharmony_ci    forceNonBlocking_ = false;
238fa7767c5Sopenharmony_ci    notifier_ = nullptr;
239fa7767c5Sopenharmony_ci    cond_.notify_all();
240fa7767c5Sopenharmony_ci    // for busylist, the memory will be released when the refcount of shared_ptr is zero.
241fa7767c5Sopenharmony_ci}
242fa7767c5Sopenharmony_ci} // namespace Media
243fa7767c5Sopenharmony_ci} // namespace OHOS