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