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 29 using std::vector; 30 using de::SharedPtr; 31 32 namespace tcu 33 { 34 namespace ThreadUtil 35 { 36 37 Event::Event (void) 38 : m_result (RESULT_NOT_READY) 39 , m_waiterCount (0) 40 , m_waiters (0, 0) 41 { 42 } 43 44 Event::~Event (void) 45 { 46 } 47 48 void 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 59 Event::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 78 Object::Object (const char* type, SharedPtr<Event> e) 79 : m_type (type) 80 , m_modify (e) 81 { 82 } 83 84 Object::~Object (void) 85 { 86 } 87 88 void 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 97 void 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 113 Operation::Operation (const char* name) 114 : m_name (name) 115 , m_event (new Event) 116 { 117 } 118 119 Operation::~Operation (void) 120 { 121 } 122 123 void 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 159 const MessageBuilder::EndToken Message::End = MessageBuilder::EndToken(); 160 161 void MessageBuilder::operator<< (const EndToken&) 162 { 163 m_thread.pushMessage(m_stream.str()); 164 } 165 166 Thread::Thread (int seed) 167 : m_random (seed) 168 , m_status (THREADSTATUS_NOT_STARTED) 169 { 170 } 171 172 Thread::~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 180 deUint8* 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 190 void Thread::addOperation (Operation* operation) 191 { 192 m_operations.push_back(operation); 193 } 194 195 void 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 238 void Thread::exec (void) 239 { 240 start(); 241 } 242 243 void 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 249 int Thread::getMessageCount (void) const 250 { 251 de::ScopedLock lock(m_messageLock); 252 return (int)(m_messages.size()); 253 } 254 255 Message Thread::getMessage (int index) const 256 { 257 de::ScopedLock lock(m_messageLock); 258 return m_messages[index]; 259 } 260 261 262 DataBlock::DataBlock (SharedPtr<Event> event) 263 : Object("DataBlock", event) 264 { 265 } 266 267 void 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 273 CompareData::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 282 void 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