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