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