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