1/*------------------------------------------------------------------------- 2 * drawElements Quality Program Tester Core 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 Thread test utilities 22 *//*--------------------------------------------------------------------*/ 23 24#include "tcuThreadUtil.hpp" 25 26#include "deClock.h" 27#include "deMemory.h" 28 29using std::vector; 30using de::SharedPtr; 31 32namespace tcu 33{ 34namespace ThreadUtil 35{ 36 37Event::Event (void) 38 : m_result (RESULT_NOT_READY) 39 , m_waiterCount (0) 40 , m_waiters (0, 0) 41{ 42} 43 44Event::~Event (void) 45{ 46} 47 48void Event::setResult (Result result) 49{ 50 m_lock.lock(); 51 DE_ASSERT(m_result == RESULT_NOT_READY); 52 m_result = result; 53 m_lock.unlock(); 54 55 for (int i = 0; i < m_waiterCount; i++) 56 m_waiters.increment(); 57} 58 59Event::Result Event::waitReady (void) 60{ 61 m_lock.lock(); 62 63 if (m_result == RESULT_NOT_READY) 64 m_waiterCount++; 65 else 66 { 67 m_lock.unlock(); 68 return m_result; 69 } 70 71 m_lock.unlock(); 72 73 m_waiters.decrement(); 74 75 return m_result; 76} 77 78Object::Object (const char* type, SharedPtr<Event> e) 79 : m_type (type) 80 , m_modify (e) 81{ 82} 83 84Object::~Object (void) 85{ 86} 87 88void Object::read (SharedPtr<Event> event, std::vector<SharedPtr<Event> >& deps) 89{ 90 // Make call depend on last modifying call 91 deps.push_back(m_modify); 92 93 // Add read dependency 94 m_reads.push_back(event); 95} 96 97void Object::modify (SharedPtr<Event> event, std::vector<SharedPtr<Event> >& deps) 98{ 99 // Make call depend on all reads 100 for (int readNdx = 0; readNdx < (int)m_reads.size(); readNdx++) 101 { 102 deps.push_back(m_reads[readNdx]); 103 } 104 deps.push_back(m_modify); 105 106 // Update last modifying call 107 m_modify = event; 108 109 // Clear read dependencies of last "version" of this object 110 m_reads.clear(); 111} 112 113Operation::Operation (const char* name) 114 : m_name (name) 115 , m_event (new Event) 116{ 117} 118 119Operation::~Operation (void) 120{ 121} 122 123void Operation::execute (Thread& thread) 124{ 125 bool success = true; 126 127 // Wait for dependencies and check that they succeeded 128 for (int depNdx = 0; depNdx < (int)m_deps.size(); depNdx++) 129 { 130 if (m_deps[depNdx]->waitReady() != Event::RESULT_OK) 131 success = false; 132 } 133 134 // Try execute operation 135 if (success) 136 { 137 try 138 { 139 exec(thread); 140 } 141 catch (...) 142 { 143 // Got exception event failed 144 m_event->setResult(Event::RESULT_FAILED); 145 throw; 146 } 147 148 m_event->setResult(Event::RESULT_OK); 149 } 150 else 151 // Some dependencies failed 152 m_event->setResult(Event::RESULT_FAILED); 153 154 // Release resources 155 m_deps.clear(); 156 m_event = SharedPtr<Event>(); 157} 158 159const MessageBuilder::EndToken Message::End = MessageBuilder::EndToken(); 160 161void MessageBuilder::operator<< (const EndToken&) 162{ 163 m_thread.pushMessage(m_stream.str()); 164} 165 166Thread::Thread (int seed) 167 : m_random (seed) 168 , m_status (THREADSTATUS_NOT_STARTED) 169{ 170} 171 172Thread::~Thread (void) 173{ 174 for (int operationNdx = 0; operationNdx < (int)m_operations.size(); operationNdx++) 175 delete m_operations[operationNdx]; 176 177 m_operations.clear(); 178} 179 180deUint8* Thread::getDummyData (size_t size) 181{ 182 if (m_dummyData.size() < size) 183 { 184 m_dummyData.resize(size); 185 } 186 187 return &(m_dummyData[0]); 188} 189 190void Thread::addOperation (Operation* operation) 191{ 192 m_operations.push_back(operation); 193} 194 195void Thread::run (void) 196{ 197 m_status = THREADSTATUS_RUNNING; 198 bool initOk = false; 199 200 // Reserve at least two messages for each operation 201 m_messages.reserve(m_operations.size()*2); 202 try 203 { 204 init(); 205 initOk = true; 206 for (int operationNdx = 0; operationNdx < (int)m_operations.size(); operationNdx++) 207 m_operations[operationNdx]->execute(*this); 208 209 deinit(); 210 m_status = THREADSTATUS_READY; 211 } 212 catch (const tcu::NotSupportedError& e) 213 { 214 newMessage() << "tcu::NotSupportedError '" << e.what() << "'" << Message::End; 215 deinit(); 216 m_status = (initOk ? THREADSTATUS_NOT_SUPPORTED : THREADSTATUS_INIT_FAILED); 217 } 218 catch (const tcu::Exception& e) 219 { 220 newMessage() << "tcu::Exception '" << e.what() << "'" << Message::End; 221 deinit(); 222 m_status = (initOk ? THREADSTATUS_FAILED : THREADSTATUS_INIT_FAILED); 223 } 224 catch (const std::exception& error) 225 { 226 newMessage() << "std::exception '" << error.what() << "'" << Message::End; 227 deinit(); 228 m_status = (initOk ? THREADSTATUS_FAILED : THREADSTATUS_INIT_FAILED); 229 } 230 catch (...) 231 { 232 newMessage() << "Unkown exception" << Message::End; 233 deinit(); 234 m_status = (initOk ? THREADSTATUS_FAILED : THREADSTATUS_INIT_FAILED); 235 } 236} 237 238void Thread::exec (void) 239{ 240 start(); 241} 242 243void Thread::pushMessage (const std::string& str) 244{ 245 de::ScopedLock lock(m_messageLock); 246 m_messages.push_back(Message(deGetMicroseconds(), str.c_str())); 247} 248 249int Thread::getMessageCount (void) const 250{ 251 de::ScopedLock lock(m_messageLock); 252 return (int)(m_messages.size()); 253} 254 255Message Thread::getMessage (int index) const 256{ 257 de::ScopedLock lock(m_messageLock); 258 return m_messages[index]; 259} 260 261 262DataBlock::DataBlock (SharedPtr<Event> event) 263 : Object("DataBlock", event) 264{ 265} 266 267void DataBlock::setData (size_t size, const void* data) 268{ 269 m_data = std::vector<deUint8>(size); 270 deMemcpy(&(m_data[0]), data, (int)size); 271} 272 273CompareData::CompareData (SharedPtr<DataBlock> a, SharedPtr<DataBlock> b) 274 : Operation ("CompareData") 275 , m_a (a) 276 , m_b (b) 277{ 278 readObject(SharedPtr<Object>(a)); 279 readObject(SharedPtr<Object>(b)); 280} 281 282void CompareData::exec (Thread& thread) 283{ 284 bool result = true; 285 DE_ASSERT(m_a->getSize() == m_b->getSize()); 286 287 thread.newMessage() << "Begin -- CompareData" << Message::End; 288 289 for (int byteNdx = 0; byteNdx < (int)m_a->getSize(); byteNdx++) 290 { 291 if (m_a->getData()[byteNdx] != m_b->getData()[byteNdx]) 292 { 293 result = false; 294 thread.newMessage() << "CompareData failed at offset :" << byteNdx << Message::End; 295 break; 296 } 297 } 298 299 if (result) 300 thread.newMessage() << "CompareData passed" << Message::End; 301 else 302 TCU_FAIL("Data comparision failed"); 303 304 thread.newMessage() << "End -- CompareData" << Message::End; 305} 306 307} // ThreadUtil 308} // tcu 309