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 "circle_buffer.h"
17 #include "base.h"
18 #ifdef CONFIG_USE_JEMALLOC_DFX_INIF
19 #include <malloc.h>
20 #endif
21
22 namespace Hdc {
CircleBuffer()23 CircleBuffer::CircleBuffer()
24 {
25 run_ = false;
26 TimerStart();
27 #ifdef CONFIG_USE_JEMALLOC_DFX_INIF
28 mallopt(M_DELAYED_FREE, M_DELAYED_FREE_DISABLE);
29 mallopt(M_SET_THREAD_CACHE, M_THREAD_CACHE_DISABLE);
30 #endif
31 }
32
~CircleBuffer()33 CircleBuffer::~CircleBuffer()
34 {
35 TimerStop();
36 for (auto iter = buffers_.begin(); iter != buffers_.end();) {
37 Data *data = iter->second;
38 delete[] data->buf;
39 delete data;
40 iter = buffers_.erase(iter);
41 }
42 }
43
Malloc()44 uint8_t *CircleBuffer::Malloc()
45 {
46 const size_t bufSize = static_cast<size_t>(Base::GetUsbffsBulkSize());
47 uint8_t *buf = nullptr;
48 std::unique_lock<std::mutex> lock(mutex_);
49 for (auto iter = buffers_.begin(); iter != buffers_.end(); ++iter) {
50 Data *data = iter->second;
51 if (data->used == false) {
52 data->used = true;
53 data->begin = std::chrono::steady_clock::now();
54 buf = data->buf;
55 break;
56 }
57 }
58 if (buf == nullptr) {
59 Data *data = new(std::nothrow) Data();
60 if (data == nullptr) {
61 return nullptr;
62 }
63 data->used = true;
64 data->begin = std::chrono::steady_clock::now();
65 data->buf = new(std::nothrow) uint8_t[bufSize];
66 if (data->buf == nullptr) {
67 delete data;
68 return nullptr;
69 }
70 uint64_t key = reinterpret_cast<uint64_t>(data->buf);
71 buffers_[key] = data;
72 buf = data->buf;
73 }
74 (void)memset_s(buf, bufSize, 0, bufSize);
75 return buf;
76 }
77
Free(const uint8_t *buf)78 void CircleBuffer::Free(const uint8_t *buf)
79 {
80 std::unique_lock<std::mutex> lock(mutex_);
81 uint64_t key = reinterpret_cast<uint64_t>(buf);
82 Data *data = buffers_[key];
83 if (data != nullptr) {
84 data->used = false;
85 data->begin = std::chrono::steady_clock::now();
86 } else {
87 WRITE_LOG(LOG_FATAL, "Free data is nullptr.");
88 }
89 }
90
FreeMemory()91 void CircleBuffer::FreeMemory()
92 {
93 std::unique_lock<std::mutex> lock(mutex_);
94 constexpr int64_t decreaseTime = 5; // 5s
95 auto end = std::chrono::steady_clock::now();
96 for (auto iter = buffers_.begin(); iter != buffers_.end();) {
97 bool remove = false;
98 Data *data = iter->second;
99 if (data->used == false) {
100 auto begin = data->begin;
101 auto duration = std::chrono::duration_cast<std::chrono::seconds>(end - begin);
102 if (duration.count() > decreaseTime) {
103 remove = true;
104 }
105 }
106 if (remove) {
107 delete[] data->buf;
108 delete data;
109 iter = buffers_.erase(iter);
110 } else {
111 ++iter;
112 }
113 }
114 }
115
Timer(void *object)116 void CircleBuffer::Timer(void *object)
117 {
118 #ifdef CONFIG_USE_JEMALLOC_DFX_INIF
119 mallopt(M_DELAYED_FREE, M_DELAYED_FREE_DISABLE);
120 mallopt(M_SET_THREAD_CACHE, M_THREAD_CACHE_DISABLE);
121 #endif
122 CircleBuffer *cirbuf = reinterpret_cast<CircleBuffer *>(object);
123 while (cirbuf->run_) {
124 cirbuf->FreeMemory();
125 cirbuf->TimerSleep();
126 }
127 }
128
TimerStart()129 void CircleBuffer::TimerStart()
130 {
131 #ifndef HDC_HOST
132 if (!run_) {
133 run_ = true;
134 thread_ = std::thread([this]() { Timer(this); });
135 }
136 #endif
137 }
138
TimerStop()139 void CircleBuffer::TimerStop()
140 {
141 #ifndef HDC_HOST
142 if (run_) {
143 run_ = false;
144 TimerNotify();
145 thread_.join();
146 }
147 #endif
148 }
149
TimerSleep()150 void CircleBuffer::TimerSleep()
151 {
152 std::unique_lock<std::mutex> lock(timerMutex_);
153 timerCv_.wait_for(lock, std::chrono::seconds(1));
154 }
155
TimerNotify()156 void CircleBuffer::TimerNotify()
157 {
158 std::unique_lock<std::mutex> lock(timerMutex_);
159 timerCv_.notify_one();
160 }
161 }
162