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 28using std::vector; 29 30static inline int getNextQueueSize (int curSize, int minNewSize) 31{ 32 return de::max(curSize*2, 1<<deLog2Ceil32(minNewSize)); 33} 34 35namespace xe 36{ 37 38// CallQueue 39 40CallQueue::CallQueue (void) 41 : m_callSem (0) 42 , m_callQueue (64) 43{ 44} 45 46CallQueue::~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 53void 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 95Call* 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 118void 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 132void CallQueue::freeCall (Call* call) 133{ 134 de::ScopedLock lock(m_lock); 135 m_freeCalls.push_back(call); 136} 137 138// Call 139 140Call::Call (void) 141 : m_func(DE_NULL) 142{ 143} 144 145Call::~Call (void) 146{ 147} 148 149void Call::clear (void) 150{ 151 m_func = DE_NULL; 152 m_data.clear(); 153} 154 155// CallReader 156 157CallReader::CallReader (Call* call) 158 : m_call (call) 159 , m_curPos (0) 160{ 161} 162 163void 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 170const 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 180CallReader& 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 198CallWriter::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 206CallWriter::~CallWriter (void) 207{ 208 if (!m_enqueued) 209 m_queue->freeCall(m_call); 210} 211 212void 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 220void CallWriter::enqueue (void) 221{ 222 DE_ASSERT(!m_enqueued); 223 m_queue->enqueue(m_call); 224 m_enqueued = true; 225} 226 227CallWriter& 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