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