Home | History | Annotate | Download | only in common
      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