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 
Event(void)37 Event::Event (void)
38 	: m_result		(RESULT_NOT_READY)
39 	, m_waiterCount	(0)
40 	, m_waiters		(0, 0)
41 {
42 }
43 
~Event(void)44 Event::~Event (void)
45 {
46 }
47 
setResult(Result result)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 
waitReady(void)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 
Object(const char * type,SharedPtr<Event> e)78 Object::Object (const char* type, SharedPtr<Event> e)
79 	: m_type	(type)
80 	, m_modify	(e)
81 {
82 }
83 
~Object(void)84 Object::~Object	(void)
85 {
86 }
87 
read(SharedPtr<Event> event,std::vector<SharedPtr<Event>> & deps)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 
modify(SharedPtr<Event> event,std::vector<SharedPtr<Event>> & deps)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 
Operation(const char * name)113 Operation::Operation (const char* name)
114 	: m_name	(name)
115 	, m_event	(new Event)
116 {
117 }
118 
~Operation(void)119 Operation::~Operation (void)
120 {
121 }
122 
execute(Thread & thread)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 
operator <<(const EndToken &)161 void MessageBuilder::operator<< (const EndToken&)
162 {
163 	m_thread.pushMessage(m_stream.str());
164 }
165 
Thread(deUint32 seed)166 Thread::Thread (deUint32 seed)
167 	: m_random	(seed)
168 	, m_status	(THREADSTATUS_NOT_STARTED)
169 {
170 }
171 
~Thread(void)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 
getDummyData(size_t size)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 
addOperation(Operation * operation)190 void Thread::addOperation (Operation* operation)
191 {
192 	m_operations.push_back(operation);
193 }
194 
run(void)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 
exec(void)238 void Thread::exec (void)
239 {
240 	start();
241 }
242 
pushMessage(const std::string & str)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 
getMessageCount(void) const249 int Thread::getMessageCount	 (void) const
250 {
251 	de::ScopedLock lock(m_messageLock);
252 	return (int)(m_messages.size());
253 }
254 
getMessage(int index) const255 Message Thread::getMessage (int index) const
256 {
257 	de::ScopedLock lock(m_messageLock);
258 	return m_messages[index];
259 }
260 
261 
DataBlock(SharedPtr<Event> event)262 DataBlock::DataBlock (SharedPtr<Event> event)
263 	: Object("DataBlock", event)
264 {
265 }
266 
setData(size_t size,const void * data)267 void DataBlock::setData (size_t size, const void* data)
268 {
269 	m_data = std::vector<deUint8>(size);
270 	deMemcpy(&(m_data[0]), data, size);
271 }
272 
CompareData(SharedPtr<DataBlock> a,SharedPtr<DataBlock> b)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 
exec(Thread & thread)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