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