xref: /aosp_15_r20/external/deqp/executor/xeCallQueue.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program Test Executor
3  * ------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Cross-thread function call dispatcher.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "xeCallQueue.hpp"
25 #include "deInt32.h"
26 #include "deMemory.h"
27 
28 using std::vector;
29 
getNextQueueSize(int curSize,int minNewSize)30 static inline int getNextQueueSize(int curSize, int minNewSize)
31 {
32     return de::max(curSize * 2, 1 << deLog2Ceil32(minNewSize));
33 }
34 
35 namespace xe
36 {
37 
38 // CallQueue
39 
CallQueue(void)40 CallQueue::CallQueue(void) : m_canceled(false), m_callSem(0), m_callQueue(64)
41 {
42 }
43 
~CallQueue(void)44 CallQueue::~CallQueue(void)
45 {
46     // Destroy all calls.
47     for (vector<Call *>::iterator i = m_calls.begin(); i != m_calls.end(); i++)
48         delete *i;
49 }
50 
cancel(void)51 void CallQueue::cancel(void)
52 {
53     m_canceled = true;
54     m_callSem.increment();
55 }
56 
callNext(void)57 void CallQueue::callNext(void)
58 {
59     Call *call = DE_NULL;
60 
61     // Wait for a call.
62     m_callSem.decrement();
63 
64     if (m_canceled)
65         return;
66 
67     // Acquire call from buffer.
68     {
69         de::ScopedLock lock(m_lock);
70         call = m_callQueue.popBack();
71     }
72 
73     try
74     {
75         // \note Enqueue lock is not held during call so it is possible to enqueue more work from dispatched call.
76         CallReader reader(call);
77 
78         call->getFunction()(reader);
79 
80         // check callee consumed all
81         DE_ASSERT(reader.isDataConsumed());
82         call->clear();
83     }
84     catch (const std::exception &)
85     {
86         try
87         {
88             // Try to push call into free calls list.
89             de::ScopedLock lock(m_lock);
90             m_freeCalls.push_back(call);
91         }
92         catch (const std::exception &)
93         {
94             // We can't do anything but ignore this.
95         }
96 
97         throw;
98     }
99 
100     // Push back to free calls list.
101     {
102         de::ScopedLock lock(m_lock);
103         m_freeCalls.push_back(call);
104     }
105 }
106 
getEmptyCall(void)107 Call *CallQueue::getEmptyCall(void)
108 {
109     de::ScopedLock lock(m_lock);
110     Call *call = DE_NULL;
111 
112     // Try to get from free calls list.
113     if (!m_freeCalls.empty())
114     {
115         call = m_freeCalls.back();
116         m_freeCalls.pop_back();
117     }
118 
119     // If no free calls were available, create a new.
120     if (!call)
121     {
122         m_calls.reserve(m_calls.size() + 1);
123         call = new Call();
124         m_calls.push_back(call);
125     }
126 
127     return call;
128 }
129 
enqueue(Call * call)130 void CallQueue::enqueue(Call *call)
131 {
132     de::ScopedLock lock(m_lock);
133 
134     if (m_callQueue.getNumFree() == 0)
135     {
136         // Call queue must be grown.
137         m_callQueue.resize(getNextQueueSize(m_callQueue.getSize(), m_callQueue.getSize() + 1));
138     }
139 
140     m_callQueue.pushFront(call);
141     m_callSem.increment();
142 }
143 
freeCall(Call * call)144 void CallQueue::freeCall(Call *call)
145 {
146     de::ScopedLock lock(m_lock);
147     m_freeCalls.push_back(call);
148 }
149 
150 // Call
151 
Call(void)152 Call::Call(void) : m_func(DE_NULL)
153 {
154 }
155 
~Call(void)156 Call::~Call(void)
157 {
158 }
159 
clear(void)160 void Call::clear(void)
161 {
162     m_func = DE_NULL;
163     m_data.clear();
164 }
165 
166 // CallReader
167 
CallReader(Call * call)168 CallReader::CallReader(Call *call) : m_call(call), m_curPos(0)
169 {
170 }
171 
read(uint8_t * bytes,size_t numBytes)172 void CallReader::read(uint8_t *bytes, size_t numBytes)
173 {
174     DE_ASSERT(m_curPos + numBytes <= m_call->getDataSize());
175     deMemcpy(bytes, m_call->getData() + m_curPos, numBytes);
176     m_curPos += numBytes;
177 }
178 
getDataBlock(size_t numBytes)179 const uint8_t *CallReader::getDataBlock(size_t numBytes)
180 {
181     DE_ASSERT(m_curPos + numBytes <= m_call->getDataSize());
182 
183     const uint8_t *ptr = m_call->getData() + m_curPos;
184     m_curPos += numBytes;
185 
186     return ptr;
187 }
188 
isDataConsumed(void) const189 bool CallReader::isDataConsumed(void) const
190 {
191     return m_curPos == m_call->getDataSize();
192 }
193 
operator >>(CallReader & reader,std::string & value)194 CallReader &operator>>(CallReader &reader, std::string &value)
195 {
196     value.clear();
197     for (;;)
198     {
199         char c;
200         reader.read((uint8_t *)&c, sizeof(char));
201         if (c != 0)
202             value.push_back(c);
203         else
204             break;
205     }
206 
207     return reader;
208 }
209 
210 // CallWriter
211 
CallWriter(CallQueue * queue,Call::Function function)212 CallWriter::CallWriter(CallQueue *queue, Call::Function function)
213     : m_queue(queue)
214     , m_call(queue->getEmptyCall())
215     , m_enqueued(false)
216 {
217     m_call->setFunction(function);
218 }
219 
~CallWriter(void)220 CallWriter::~CallWriter(void)
221 {
222     if (!m_enqueued)
223         m_queue->freeCall(m_call);
224 }
225 
write(const uint8_t * bytes,size_t numBytes)226 void CallWriter::write(const uint8_t *bytes, size_t numBytes)
227 {
228     DE_ASSERT(!m_enqueued);
229     size_t curPos = m_call->getDataSize();
230     m_call->setDataSize(curPos + numBytes);
231     deMemcpy(m_call->getData() + curPos, bytes, numBytes);
232 }
233 
enqueue(void)234 void CallWriter::enqueue(void)
235 {
236     DE_ASSERT(!m_enqueued);
237     m_queue->enqueue(m_call);
238     m_enqueued = true;
239 }
240 
operator <<(CallWriter & writer,const char * str)241 CallWriter &operator<<(CallWriter &writer, const char *str)
242 {
243     int pos = 0;
244     for (;;)
245     {
246         writer.write((const uint8_t *)str + pos, sizeof(char));
247         if (str[pos] == 0)
248             break;
249         pos += 1;
250     }
251 
252     return writer;
253 }
254 
255 } // namespace xe
256