Home | History | Annotate | Download | only in executor
      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 
     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 
     40 CallQueue::CallQueue (void)
     41 	: m_callSem		(0)
     42 	, m_callQueue	(64)
     43 {
     44 }
     45 
     46 CallQueue::~CallQueue (void)
     47 {
     48 	// Destroy all calls.
     49 	for (vector<Call*>::iterator i = m_calls.begin(); i != m_calls.end(); i++)
     50 		delete *i;
     51 }
     52 
     53 void CallQueue::callNext (void)
     54 {
     55 	Call* call = DE_NULL;
     56 
     57 	// Wait for a call.
     58 	m_callSem.decrement();
     59 
     60 	// Acquire call from buffer.
     61 	{
     62 		de::ScopedLock lock(m_lock);
     63 		call = m_callQueue.popBack();
     64 	}
     65 
     66 	try
     67 	{
     68 		// \note Enqueue lock is not held during call so it is possible to enqueue more work from dispatched call.
     69 		call->getFunction()(CallReader(call));
     70 		call->clear();
     71 	}
     72 	catch (const std::exception&)
     73 	{
     74 		try
     75 		{
     76 			// Try to push call into free calls list.
     77 			de::ScopedLock lock(m_lock);
     78 			m_freeCalls.push_back(call);
     79 		}
     80 		catch (const std::exception&)
     81 		{
     82 			// We can't do anything but ignore this.
     83 		}
     84 
     85 		throw;
     86 	}
     87 
     88 	// Push back to free calls list.
     89 	{
     90 		de::ScopedLock lock(m_lock);
     91 		m_freeCalls.push_back(call);
     92 	}
     93 }
     94 
     95 Call* CallQueue::getEmptyCall (void)
     96 {
     97 	de::ScopedLock	lock	(m_lock);
     98 	Call*			call	= DE_NULL;
     99 
    100 	// Try to get from free calls list.
    101 	if (!m_freeCalls.empty())
    102 	{
    103 		call = m_freeCalls.back();
    104 		m_freeCalls.pop_back();
    105 	}
    106 
    107 	// If no free calls were available, create a new.
    108 	if (!call)
    109 	{
    110 		m_calls.reserve(m_calls.size()+1);
    111 		call = new Call();
    112 		m_calls.push_back(call);
    113 	}
    114 
    115 	return call;
    116 }
    117 
    118 void CallQueue::enqueue (Call* call)
    119 {
    120 	de::ScopedLock lock(m_lock);
    121 
    122 	if (m_callQueue.getNumFree() == 0)
    123 	{
    124 		// Call queue must be grown.
    125 		m_callQueue.resize(getNextQueueSize(m_callQueue.getSize(), m_callQueue.getSize()+1));
    126 	}
    127 
    128 	m_callQueue.pushFront(call);
    129 	m_callSem.increment();
    130 }
    131 
    132 void CallQueue::freeCall (Call* call)
    133 {
    134 	de::ScopedLock lock(m_lock);
    135 	m_freeCalls.push_back(call);
    136 }
    137 
    138 // Call
    139 
    140 Call::Call (void)
    141 	: m_func(DE_NULL)
    142 {
    143 }
    144 
    145 Call::~Call (void)
    146 {
    147 }
    148 
    149 void Call::clear (void)
    150 {
    151 	m_func = DE_NULL;
    152 	m_data.clear();
    153 }
    154 
    155 // CallReader
    156 
    157 CallReader::CallReader (Call* call)
    158 	: m_call	(call)
    159 	, m_curPos	(0)
    160 {
    161 }
    162 
    163 void CallReader::read (deUint8* bytes, int numBytes)
    164 {
    165 	DE_ASSERT(m_curPos + numBytes <= m_call->getDataSize());
    166 	deMemcpy(bytes, m_call->getData()+m_curPos, numBytes);
    167 	m_curPos += numBytes;
    168 }
    169 
    170 const deUint8* CallReader::getDataBlock (int numBytes)
    171 {
    172 	DE_ASSERT(m_curPos + numBytes <= m_call->getDataSize());
    173 
    174 	const deUint8* ptr = m_call->getData()+m_curPos;
    175 	m_curPos += numBytes;
    176 
    177 	return ptr;
    178 }
    179 
    180 CallReader& operator>> (CallReader& reader, std::string& value)
    181 {
    182 	value.clear();
    183 	for (;;)
    184 	{
    185 		char c;
    186 		reader.read((deUint8*)&c, sizeof(char));
    187 		if (c != 0)
    188 			value.push_back(c);
    189 		else
    190 			break;
    191 	}
    192 
    193 	return reader;
    194 }
    195 
    196 // CallWriter
    197 
    198 CallWriter::CallWriter (CallQueue* queue, Call::Function function)
    199 	: m_queue		(queue)
    200 	, m_call		(queue->getEmptyCall())
    201 	, m_enqueued	(false)
    202 {
    203 	m_call->setFunction(function);
    204 }
    205 
    206 CallWriter::~CallWriter (void)
    207 {
    208 	if (!m_enqueued)
    209 		m_queue->freeCall(m_call);
    210 }
    211 
    212 void CallWriter::write (const deUint8* bytes, int numBytes)
    213 {
    214 	DE_ASSERT(!m_enqueued);
    215 	int curPos = m_call->getDataSize();
    216 	m_call->setDataSize(curPos+numBytes);
    217 	deMemcpy(m_call->getData()+curPos, bytes, numBytes);
    218 }
    219 
    220 void CallWriter::enqueue (void)
    221 {
    222 	DE_ASSERT(!m_enqueued);
    223 	m_queue->enqueue(m_call);
    224 	m_enqueued = true;
    225 }
    226 
    227 CallWriter& operator<< (CallWriter& writer, const char* str)
    228 {
    229 	int pos = 0;
    230 	for (;;)
    231 	{
    232 		writer.write((const deUint8*)str + pos, sizeof(char));
    233 		if (str[pos] == 0)
    234 			break;
    235 		pos += 1;
    236 	}
    237 
    238 	return writer;
    239 }
    240 
    241 } // xe
    242