* Copyright (C) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "circle_buffer.h"
#include "base.h"
#ifdef CONFIG_USE_JEMALLOC_DFX_INIF
#include <malloc.h>
#endif
namespace Hdc {
CircleBuffer::CircleBuffer()
{
run_ = false;
TimerStart();
#ifdef CONFIG_USE_JEMALLOC_DFX_INIF
mallopt(M_DELAYED_FREE, M_DELAYED_FREE_DISABLE);
mallopt(M_SET_THREAD_CACHE, M_THREAD_CACHE_DISABLE);
#endif
}
CircleBuffer::~CircleBuffer()
{
TimerStop();
for (auto iter = buffers_.begin(); iter != buffers_.end();) {
Data *data = iter->second;
delete[] data->buf;
delete data;
iter = buffers_.erase(iter);
}
}
uint8_t *CircleBuffer::Malloc()
{
const size_t bufSize = static_cast<size_t>(Base::GetUsbffsBulkSize());
uint8_t *buf = nullptr;
std::unique_lock<std::mutex> lock(mutex_);
for (auto iter = buffers_.begin(); iter != buffers_.end(); ++iter) {
Data *data = iter->second;
if (data->used == false) {
data->used = true;
data->begin = std::chrono::steady_clock::now();
buf = data->buf;
break;
}
}
if (buf == nullptr) {
Data *data = new(std::nothrow) Data();
if (data == nullptr) {
return nullptr;
}
data->used = true;
data->begin = std::chrono::steady_clock::now();
data->buf = new(std::nothrow) uint8_t[bufSize];
if (data->buf == nullptr) {
delete data;
return nullptr;
}
uint64_t key = reinterpret_cast<uint64_t>(data->buf);
buffers_[key] = data;
buf = data->buf;
}
(void)memset_s(buf, bufSize, 0, bufSize);
return buf;
}
void CircleBuffer::Free(const uint8_t *buf)
{
std::unique_lock<std::mutex> lock(mutex_);
uint64_t key = reinterpret_cast<uint64_t>(buf);
auto findData = buffers_.find(key);
if (findData == buffers_.end()) {
WRITE_LOG(LOG_FATAL, "Free data not found.");
return;
}
Data *data = findData->second;
if (data != nullptr) {
data->used = false;
data->begin = std::chrono::steady_clock::now();
} else {
WRITE_LOG(LOG_FATAL, "Free data is nullptr.");
}
}
void CircleBuffer::FreeMemory()
{
std::unique_lock<std::mutex> lock(mutex_);
constexpr int64_t decreaseTime = 5;
auto end = std::chrono::steady_clock::now();
for (auto iter = buffers_.begin(); iter != buffers_.end();) {
bool remove = false;
Data *data = iter->second;
if (data->used == false) {
auto begin = data->begin;
auto duration = std::chrono::duration_cast<std::chrono::seconds>(end - begin);
if (duration.count() > decreaseTime) {
remove = true;
}
}
if (remove) {
delete[] data->buf;
delete data;
iter = buffers_.erase(iter);
} else {
++iter;
}
}
}
void CircleBuffer::Timer(void *object)
{
#ifdef CONFIG_USE_JEMALLOC_DFX_INIF
mallopt(M_DELAYED_FREE, M_DELAYED_FREE_DISABLE);
mallopt(M_SET_THREAD_CACHE, M_THREAD_CACHE_DISABLE);
#endif
CircleBuffer *cirbuf = reinterpret_cast<CircleBuffer *>(object);
while (cirbuf->run_) {
cirbuf->FreeMemory();
cirbuf->TimerSleep();
}
}
void CircleBuffer::TimerStart()
{
#ifndef HDC_HOST
if (!run_) {
run_ = true;
thread_ = std::thread([this]() { Timer(this); });
}
#endif
}
void CircleBuffer::TimerStop()
{
#ifndef HDC_HOST
if (run_) {
run_ = false;
TimerNotify();
thread_.join();
}
#endif
}
void CircleBuffer::TimerSleep()
{
std::unique_lock<std::mutex> lock(timerMutex_);
timerCv_.wait_for(lock, std::chrono::seconds(1));
}
void CircleBuffer::TimerNotify()
{
std::unique_lock<std::mutex> lock(timerMutex_);
timerCv_.notify_one();
}
}