1fb299fa2Sopenharmony_ci/*
2fb299fa2Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
3fb299fa2Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4fb299fa2Sopenharmony_ci * you may not use this file except in compliance with the License.
5fb299fa2Sopenharmony_ci * You may obtain a copy of the License at
6fb299fa2Sopenharmony_ci *
7fb299fa2Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8fb299fa2Sopenharmony_ci *
9fb299fa2Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10fb299fa2Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11fb299fa2Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12fb299fa2Sopenharmony_ci * See the License for the specific language governing permissions and
13fb299fa2Sopenharmony_ci * limitations under the License.
14fb299fa2Sopenharmony_ci */
15fb299fa2Sopenharmony_ci#include <iostream>
16fb299fa2Sopenharmony_ci#include <cstring>
17fb299fa2Sopenharmony_ci#include <string>
18fb299fa2Sopenharmony_ci#include <thread>
19fb299fa2Sopenharmony_ci
20fb299fa2Sopenharmony_ci#include "log.h"
21fb299fa2Sopenharmony_ci#include "securec.h"
22fb299fa2Sopenharmony_ci#include "ring_buffer.h"
23fb299fa2Sopenharmony_ci
24fb299fa2Sopenharmony_cinamespace Updater {
25fb299fa2Sopenharmony_ciRingBuffer::~RingBuffer()
26fb299fa2Sopenharmony_ci{
27fb299fa2Sopenharmony_ci    Release();
28fb299fa2Sopenharmony_ci}
29fb299fa2Sopenharmony_ci
30fb299fa2Sopenharmony_cibool RingBuffer::Init(uint32_t singleSize, uint32_t num)
31fb299fa2Sopenharmony_ci{
32fb299fa2Sopenharmony_ci    if (singleSize == 0 || num == 0 || (num & (num - 1)) != 0) { // power of 2
33fb299fa2Sopenharmony_ci        LOG(ERROR) << "singleSize:" <<  singleSize << " num:" << num << " error";
34fb299fa2Sopenharmony_ci        return false;
35fb299fa2Sopenharmony_ci    }
36fb299fa2Sopenharmony_ci    bufArray_ = new (std::nothrow) uint8_t* [num] {};
37fb299fa2Sopenharmony_ci    lenArray_ = new (std::nothrow) uint32_t [num] {};
38fb299fa2Sopenharmony_ci    if (bufArray_ == nullptr || lenArray_ == nullptr) {
39fb299fa2Sopenharmony_ci        LOG(ERROR) << "new buf or len " << num << " error";
40fb299fa2Sopenharmony_ci        return false;
41fb299fa2Sopenharmony_ci    }
42fb299fa2Sopenharmony_ci    for (uint32_t i = 0; i < num; i++) {
43fb299fa2Sopenharmony_ci        bufArray_[i] = new (std::nothrow) uint8_t [singleSize] {};
44fb299fa2Sopenharmony_ci        if (bufArray_[i] == nullptr) {
45fb299fa2Sopenharmony_ci            LOG(ERROR) << "new buf " << i << " size " << singleSize << " error";
46fb299fa2Sopenharmony_ci            return false;
47fb299fa2Sopenharmony_ci        }
48fb299fa2Sopenharmony_ci    }
49fb299fa2Sopenharmony_ci
50fb299fa2Sopenharmony_ci    writeIndex_ = 0;
51fb299fa2Sopenharmony_ci    readIndex_ = 0;
52fb299fa2Sopenharmony_ci    num_ = num;
53fb299fa2Sopenharmony_ci    singleSize_ = singleSize;
54fb299fa2Sopenharmony_ci    return true;
55fb299fa2Sopenharmony_ci}
56fb299fa2Sopenharmony_ci
57fb299fa2Sopenharmony_civoid RingBuffer::Reset()
58fb299fa2Sopenharmony_ci{
59fb299fa2Sopenharmony_ci    isStop_ = false;
60fb299fa2Sopenharmony_ci    writeIndex_ = 0;
61fb299fa2Sopenharmony_ci    readIndex_ = 0;
62fb299fa2Sopenharmony_ci    for (uint32_t i = 0; i < num_; ++i) {
63fb299fa2Sopenharmony_ci        lenArray_[i] = 0;
64fb299fa2Sopenharmony_ci    }
65fb299fa2Sopenharmony_ci}
66fb299fa2Sopenharmony_ci
67fb299fa2Sopenharmony_cibool RingBuffer::IsFull()
68fb299fa2Sopenharmony_ci{
69fb299fa2Sopenharmony_ci    // writeIndex readIndex real size: 0 ~ num_ -1, logic size: 0 ~ 2num_ - 1
70fb299fa2Sopenharmony_ci    // when writeIndex_ - readIndex_ == n means full
71fb299fa2Sopenharmony_ci    return writeIndex_ == (readIndex_ ^ num_);
72fb299fa2Sopenharmony_ci}
73fb299fa2Sopenharmony_ci
74fb299fa2Sopenharmony_cibool RingBuffer::IsEmpty()
75fb299fa2Sopenharmony_ci{
76fb299fa2Sopenharmony_ci    // writeIndex readIndex real size: 0 ~ num_ -1, logic size: 0 ~ 2num_ - 1
77fb299fa2Sopenharmony_ci    // when same means empty
78fb299fa2Sopenharmony_ci    return writeIndex_ == readIndex_;
79fb299fa2Sopenharmony_ci}
80fb299fa2Sopenharmony_ci
81fb299fa2Sopenharmony_cibool RingBuffer::Push(uint8_t *buf, uint32_t len)
82fb299fa2Sopenharmony_ci{
83fb299fa2Sopenharmony_ci    if (buf == nullptr || len == 0 || len > singleSize_) {
84fb299fa2Sopenharmony_ci        LOG(ERROR) << "RingBuffer push error, len:" << len << " singleSize:" << singleSize_;
85fb299fa2Sopenharmony_ci        return false;
86fb299fa2Sopenharmony_ci    }
87fb299fa2Sopenharmony_ci    if (IsFull()) {
88fb299fa2Sopenharmony_ci        std::unique_lock<std::mutex> pushLock(notifyMtx_);
89fb299fa2Sopenharmony_ci        while (IsFull()) {
90fb299fa2Sopenharmony_ci            if (isStop_) {
91fb299fa2Sopenharmony_ci                LOG(WARNING) << "RingBuffer push stopped";
92fb299fa2Sopenharmony_ci                return false;
93fb299fa2Sopenharmony_ci            }
94fb299fa2Sopenharmony_ci            LOG(DEBUG) << "RingBuffer full, wait !!!";
95fb299fa2Sopenharmony_ci            notFull_.wait(pushLock);
96fb299fa2Sopenharmony_ci        }
97fb299fa2Sopenharmony_ci    }
98fb299fa2Sopenharmony_ci
99fb299fa2Sopenharmony_ci    uint32_t index = writeIndex_ & (num_ - 1);
100fb299fa2Sopenharmony_ci    if (memcpy_s(bufArray_[index], singleSize_, buf, len) != EOK) {
101fb299fa2Sopenharmony_ci        LOG(ERROR) << "memcpy error, len:" << len;
102fb299fa2Sopenharmony_ci        return false;
103fb299fa2Sopenharmony_ci    }
104fb299fa2Sopenharmony_ci    lenArray_[index] = len;
105fb299fa2Sopenharmony_ci    writeIndex_ = (writeIndex_ + 1) & (2 * num_ - 1); // 2: logic buffer size
106fb299fa2Sopenharmony_ci
107fb299fa2Sopenharmony_ci    std::unique_lock<std::mutex> popLock(notifyMtx_);
108fb299fa2Sopenharmony_ci    notEmpty_.notify_all();
109fb299fa2Sopenharmony_ci    return true;
110fb299fa2Sopenharmony_ci}
111fb299fa2Sopenharmony_ci
112fb299fa2Sopenharmony_cibool RingBuffer::Pop(uint8_t *buf, uint32_t maxLen, uint32_t &len)
113fb299fa2Sopenharmony_ci{
114fb299fa2Sopenharmony_ci    if (buf == nullptr) {
115fb299fa2Sopenharmony_ci        LOG(ERROR) << "RingBuffer pop para error";
116fb299fa2Sopenharmony_ci        return false;
117fb299fa2Sopenharmony_ci    }
118fb299fa2Sopenharmony_ci    if (IsEmpty()) {
119fb299fa2Sopenharmony_ci        std::unique_lock<std::mutex> popLock(notifyMtx_);
120fb299fa2Sopenharmony_ci        while (IsEmpty()) {
121fb299fa2Sopenharmony_ci            if (isStop_) {
122fb299fa2Sopenharmony_ci                LOG(WARNING) << "RingBuffer pop stopped";
123fb299fa2Sopenharmony_ci                return false;
124fb299fa2Sopenharmony_ci            }
125fb299fa2Sopenharmony_ci            LOG(DEBUG) << "RingBuffer empty, wait !!!";
126fb299fa2Sopenharmony_ci            notEmpty_.wait(popLock);
127fb299fa2Sopenharmony_ci        }
128fb299fa2Sopenharmony_ci    }
129fb299fa2Sopenharmony_ci
130fb299fa2Sopenharmony_ci    uint32_t index = readIndex_ & (num_ - 1);
131fb299fa2Sopenharmony_ci    if (memcpy_s(buf, maxLen, bufArray_[index], lenArray_[index]) != EOK) {
132fb299fa2Sopenharmony_ci        LOG(ERROR) << "memcpy error, len:" << lenArray_[index];
133fb299fa2Sopenharmony_ci        return false;
134fb299fa2Sopenharmony_ci    }
135fb299fa2Sopenharmony_ci    len = lenArray_[index];
136fb299fa2Sopenharmony_ci    readIndex_ = (readIndex_ + 1) & (2 * num_ - 1); // 2: logic buffer size
137fb299fa2Sopenharmony_ci
138fb299fa2Sopenharmony_ci    std::unique_lock<std::mutex> popLock(notifyMtx_);
139fb299fa2Sopenharmony_ci    notFull_.notify_all();
140fb299fa2Sopenharmony_ci    return true;
141fb299fa2Sopenharmony_ci}
142fb299fa2Sopenharmony_ci
143fb299fa2Sopenharmony_civoid RingBuffer::Stop()
144fb299fa2Sopenharmony_ci{
145fb299fa2Sopenharmony_ci    isStop_ = true;
146fb299fa2Sopenharmony_ci    notFull_.notify_all();
147fb299fa2Sopenharmony_ci    notEmpty_.notify_all();
148fb299fa2Sopenharmony_ci}
149fb299fa2Sopenharmony_ci
150fb299fa2Sopenharmony_civoid RingBuffer::StopPush()
151fb299fa2Sopenharmony_ci{
152fb299fa2Sopenharmony_ci    {
153fb299fa2Sopenharmony_ci        std::unique_lock<std::mutex> pushLock(notifyMtx_);
154fb299fa2Sopenharmony_ci        isStop_ = true;
155fb299fa2Sopenharmony_ci    }
156fb299fa2Sopenharmony_ci    notFull_.notify_all();
157fb299fa2Sopenharmony_ci}
158fb299fa2Sopenharmony_ci
159fb299fa2Sopenharmony_civoid RingBuffer::StopPop()
160fb299fa2Sopenharmony_ci{
161fb299fa2Sopenharmony_ci    {
162fb299fa2Sopenharmony_ci        std::unique_lock<std::mutex> popLock(notifyMtx_);
163fb299fa2Sopenharmony_ci        isStop_ = true;
164fb299fa2Sopenharmony_ci    }
165fb299fa2Sopenharmony_ci    notEmpty_.notify_all();
166fb299fa2Sopenharmony_ci}
167fb299fa2Sopenharmony_ci
168fb299fa2Sopenharmony_civoid RingBuffer::Release()
169fb299fa2Sopenharmony_ci{
170fb299fa2Sopenharmony_ci    if (lenArray_ != nullptr) {
171fb299fa2Sopenharmony_ci        delete[] lenArray_;
172fb299fa2Sopenharmony_ci        lenArray_ = nullptr;
173fb299fa2Sopenharmony_ci    }
174fb299fa2Sopenharmony_ci
175fb299fa2Sopenharmony_ci    if (bufArray_ != nullptr) {
176fb299fa2Sopenharmony_ci        for (uint32_t i = 0; i < num_ && bufArray_[i] != nullptr; i++) {
177fb299fa2Sopenharmony_ci            delete[] bufArray_[i];
178fb299fa2Sopenharmony_ci            bufArray_[i] = nullptr;
179fb299fa2Sopenharmony_ci        }
180fb299fa2Sopenharmony_ci        delete[] bufArray_;
181fb299fa2Sopenharmony_ci        bufArray_ = nullptr;
182fb299fa2Sopenharmony_ci    }
183fb299fa2Sopenharmony_ci}
184fb299fa2Sopenharmony_ci} // namespace Updater
185