1 /*
2 * Copyright (c) 2025 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 <cstdio>
17 #include "hpae_no_lock_queue.h"
18 #include "audio_engine_log.h"
19
20 namespace OHOS {
21 namespace AudioStandard {
22 namespace HPAE {
23 constexpr uint32_t MAX_REQUEST_COUNT = 10000000;
24 constexpr uint32_t INVALID_REQUEST_ID = std::numeric_limits<uint32_t>::max();
25 constexpr uint64_t SHIFT_32_OFFSET = 32;
HpaeNoLockQueue(size_t maxRequestCount)26 HpaeNoLockQueue::HpaeNoLockQueue(size_t maxRequestCount)
27 {
28 if (maxRequestCount > MAX_REQUEST_COUNT) {
29 AUDIO_WARNING_LOG("[HpaeNoLockQueue] maxRequestCount %{public}zu is beyound Max Count", maxRequestCount);
30 maxRequestCount = MAX_REQUEST_COUNT;
31 }
32 InitQueue(maxRequestCount);
33 }
34
~HpaeNoLockQueue()35 HpaeNoLockQueue::~HpaeNoLockQueue()
36 {
37 AUDIO_INFO_LOG("HpaeNoLockQueue destroyed");
38 }
InitQueue(size_t maxRequestCount)39 void HpaeNoLockQueue::InitQueue(size_t maxRequestCount)
40 {
41 CHECK_AND_RETURN_LOG(maxRequestCount > 0, "maxRequestCount = 0");
42 requestQueue_.resize(maxRequestCount);
43 tempRequestQueue_.reserve(maxRequestCount);
44
45 freeRequestHeadIndex_ = 0;
46 for (size_t i = 0; i < maxRequestCount - 1; ++i) {
47 requestQueue_[i].nextRequestIndex = i + 1;
48 }
49 requestQueue_[maxRequestCount - 1].nextRequestIndex = INVALID_REQUEST_ID;
50 requestHeadIndex_ = INVALID_REQUEST_ID;
51 AUDIO_INFO_LOG("Init Queue size is %{public}zu", maxRequestCount);
52 }
PushRequest(Request && request)53 void HpaeNoLockQueue::PushRequest(Request &&request)
54 {
55 const uint64_t freeRequestIndex = GetRequestNode(&freeRequestHeadIndex_);
56 if (GetRequsetIndex(freeRequestIndex) == INVALID_REQUEST_ID) {
57 AUDIO_WARNING_LOG("reached Queue Capacity: drop this request");
58 return;
59 }
60 requestQueue_[GetRequsetIndex(freeRequestIndex)].request = std::move(request);
61 PushRequestNode(&requestHeadIndex_, freeRequestIndex);
62 }
63
HandleRequests()64 void HpaeNoLockQueue::HandleRequests()
65 {
66 uint64_t oldRequestFlag;
67 uint64_t requestHeadindex;
68 do {
69 requestHeadindex = requestHeadIndex_.load();
70 oldRequestFlag = (GetRequsetFlag(requestHeadindex) << SHIFT_32_OFFSET) + INVALID_REQUEST_ID;
71 } while (!std::atomic_compare_exchange_strong(&requestHeadIndex_, &requestHeadindex, oldRequestFlag));
72 ProcessRequests(requestHeadindex, true);
73 }
74
Reset()75 void HpaeNoLockQueue::Reset()
76 {
77 const uint64_t oldRequestFlag = (GetRequsetFlag(requestHeadIndex_) << SHIFT_32_OFFSET) + INVALID_REQUEST_ID;
78 const uint64_t oldRequestHeadindex = requestHeadIndex_.exchange(oldRequestFlag);
79 ProcessRequests(oldRequestHeadindex, false);
80 }
81
IncRequsetIndex(uint64_t requestIndex)82 uint64_t HpaeNoLockQueue::IncRequsetIndex(uint64_t requestIndex)
83 {
84 return requestIndex + (static_cast<uint64_t>(1) << SHIFT_32_OFFSET);
85 }
86
GetRequsetIndex(uint64_t requestIndex)87 uint64_t HpaeNoLockQueue::GetRequsetIndex(uint64_t requestIndex)
88 {
89 return requestIndex & std::numeric_limits<uint32_t>::max();
90 }
91
GetRequsetFlag(uint64_t requestFlag)92 uint64_t HpaeNoLockQueue::GetRequsetFlag(uint64_t requestFlag)
93 {
94 return requestFlag >> SHIFT_32_OFFSET;
95 }
96
PushRequestNode(std::atomic<uint64_t> * pRequestHeadIndex,uint64_t index)97 void HpaeNoLockQueue::PushRequestNode(std::atomic<uint64_t> *pRequestHeadIndex, uint64_t index)
98 {
99 if (pRequestHeadIndex == nullptr) {
100 return;
101 }
102 uint64_t requestHeadIndex;
103 do {
104 requestHeadIndex = pRequestHeadIndex->load();
105 requestQueue_[GetRequsetIndex(index)].nextRequestIndex = requestHeadIndex;
106 } while (!std::atomic_compare_exchange_strong(pRequestHeadIndex, &requestHeadIndex, index));
107 }
108
GetRequestNode(std::atomic<uint64_t> * pRequestHeadIndex)109 uint64_t HpaeNoLockQueue::GetRequestNode(std::atomic<uint64_t> *pRequestHeadIndex)
110 {
111 if (pRequestHeadIndex == nullptr) {
112 return std::numeric_limits<uint64_t>::max();
113 }
114 uint64_t requestHeadIndex;
115 uint64_t nextRequestIndex;
116 do {
117 requestHeadIndex = pRequestHeadIndex->load();
118 if (GetRequsetIndex(requestHeadIndex) == INVALID_REQUEST_ID) {
119 return INVALID_REQUEST_ID;
120 }
121 nextRequestIndex = requestQueue_[GetRequsetIndex(requestHeadIndex)].nextRequestIndex;
122 } while (!std::atomic_compare_exchange_strong(pRequestHeadIndex, &requestHeadIndex, nextRequestIndex));
123 return IncRequsetIndex(requestHeadIndex);
124 }
125
ProcessRequests(uint64_t requestHeadIndex,bool isProcess)126 void HpaeNoLockQueue::ProcessRequests(uint64_t requestHeadIndex, bool isProcess)
127 {
128 uint64_t tempIndex = requestHeadIndex;
129 while (GetRequsetIndex(tempIndex) != INVALID_REQUEST_ID) {
130 RequestNode *tempRequest = &requestQueue_[GetRequsetIndex(tempIndex)];
131 uint64_t nextRequest = tempRequest->nextRequestIndex;
132 tempRequestQueue_.emplace_back(std::move(tempRequest->request));
133 tempRequest->request = nullptr;
134 PushRequestNode(&freeRequestHeadIndex_, tempIndex);
135 tempIndex = nextRequest;
136 }
137
138 if (isProcess) {
139 for (std::vector<Request>::reverse_iterator requestIter = tempRequestQueue_.rbegin();
140 requestIter != tempRequestQueue_.rend();
141 ++requestIter) {
142 if (*requestIter != nullptr) {
143 (*requestIter)();
144 }
145 }
146 }
147 tempRequestQueue_.clear();
148 }
149
IsFinishProcess()150 bool HpaeNoLockQueue::IsFinishProcess()
151 {
152 if (GetRequsetIndex(requestHeadIndex_) == INVALID_REQUEST_ID) {
153 return true;
154 } else {
155 return false;
156 }
157 }
158 } // namespace HPAE
159 } // namespace AudioStandard
160 } // namespace OHOS
161