• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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