1#ifndef _TCUTHREADUTIL_HPP
2#define _TCUTHREADUTIL_HPP
3/*-------------------------------------------------------------------------
4 * drawElements Quality Program Tester Core
5 * ----------------------------------------
6 *
7 * Copyright 2014 The Android Open Source Project
8 *
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 *
21 *//*!
22 * \file
23 * \brief Thread test utilities
24 *//*--------------------------------------------------------------------*/
25
26#include "tcuDefs.hpp"
27#include "deSharedPtr.hpp"
28#include "deMutex.hpp"
29#include "deSemaphore.hpp"
30#include "deThread.hpp"
31#include "deRandom.hpp"
32
33#include <vector>
34#include <sstream>
35
36namespace tcu
37{
38namespace ThreadUtil
39{
40// Event object for synchronizing threads
41class Event
42{
43public:
44	enum Result
45	{
46		RESULT_NOT_READY = 0,
47		RESULT_OK,
48		RESULT_FAILED
49	};
50
51					Event 		(void);
52					~Event		(void);
53	void			setResult	(Result result);
54	Result			waitReady	(void);
55	Result			getResult	(void) const { return m_result; }
56
57private:
58	volatile Result	m_result;
59	volatile int	m_waiterCount;
60	de::Semaphore	m_waiters;
61	de::Mutex		m_lock;
62
63	// Disabled
64					Event		(const Event&);
65	Event&			operator=	(const Event&);
66};
67
68// Base class for objects which modifications should be tracked between threads
69class Object
70{
71public:
72										Object		(const char* type, de::SharedPtr<Event> createEvent);
73	virtual								~Object		(void);
74	const char*							getType		(void) const { return m_type; }
75
76	// Used by class Operation only
77	void								read		(de::SharedPtr<Event> event, std::vector<de::SharedPtr<Event> >& deps);
78	void								modify		(de::SharedPtr<Event> event, std::vector<de::SharedPtr<Event> >& deps);
79
80private:
81	const char*							m_type;
82	de::SharedPtr<Event>				m_modify;
83	std::vector<de::SharedPtr<Event> >	m_reads;
84
85	// Disabled
86										Object		(const Object&);
87	Object&								operator=	(const Object&);
88};
89
90class Thread;
91
92class MessageBuilder
93{
94public:
95						MessageBuilder		(Thread& thread) : m_thread(thread) {}
96						MessageBuilder		(const MessageBuilder& other) : m_thread(other.m_thread), m_stream(other.m_stream.str()) {}
97	template<class T>
98	MessageBuilder&		operator<<			(const T& t) { m_stream << t; return *this; }
99
100	class EndToken
101	{
102	public:
103						EndToken			(void) {}
104	};
105
106	void 				operator<<			(const EndToken&);
107
108private:
109	Thread&				m_thread;
110	std::stringstream	m_stream;
111};
112
113class Message
114{
115public:
116						Message		(deUint64 time, const char* message) : m_time(time), m_message(message) {}
117
118	deUint64			getTime		(void) const { return m_time; }
119	const std::string&	getMessage	(void) const { return m_message; }
120
121	static const MessageBuilder::EndToken End;
122
123private:
124	deUint64			m_time;
125	std::string			m_message;
126};
127
128// Base class for operations executed by threads
129class Operation
130{
131public:
132											Operation		(const char* name);
133	virtual									~Operation		(void);
134
135	const char*								getName			(void) const { return m_name; }
136	de::SharedPtr<Event>					getEvent		(void) { return m_event; }
137
138	void									readObject		(de::SharedPtr<Object> object) { object->read(m_event, m_deps); }
139	void									modifyObject	(de::SharedPtr<Object> object) { object->modify(m_event, m_deps); }
140
141	virtual void							exec			(Thread& thread) = 0;	//!< Overwritten by inherited class to perform actual operation
142	virtual void							execute			(Thread& thread);		//!< May Be overwritten by inherited class to change how syncronization is done
143
144protected:
145	const char*								m_name;
146	std::vector<de::SharedPtr<Event> >		m_deps;
147	de::SharedPtr<Event>					m_event;
148
149											Operation		(const Operation&);
150	Operation&								operator=		(const Operation&);
151};
152
153class Thread : public de::Thread
154{
155public:
156	enum ThreadStatus
157	{
158		THREADSTATUS_NOT_STARTED = 0,
159		THREADSTATUS_INIT_FAILED,
160		THREADSTATUS_RUNNING,
161		THREADSTATUS_READY,
162		THREADSTATUS_FAILED,
163		THREADSTATUS_NOT_SUPPORTED
164	};
165							Thread				(deUint32 seed);
166							~Thread				(void);
167
168	virtual void			init				(void) {}	//!< Called first before any Operation
169
170	// \todo [mika] Should the result of execution be passed to deinit?
171	virtual void			deinit				(void) {}	//!< Called after after operation
172
173	void					addOperation		(Operation* operation);
174
175	void					exec				(void);
176
177	deUint8*				getDummyData		(size_t size);	//!< Return data pointer that contains at least size bytes. Valid until next call
178
179	ThreadStatus			getStatus			(void) const { return m_status; }
180
181	MessageBuilder			newMessage			(void) { return MessageBuilder(*this); }
182	de::Random&				getRandom			(void) { return m_random; }
183
184	// Used to by test case to read log messages
185	int						getMessageCount		(void) const;
186	Message					getMessage			(int index) const;
187
188	// Used by message builder
189	void					pushMessage			(const std::string& str);
190
191private:
192	virtual void			run					(void);
193
194	std::vector<Operation*>	m_operations;
195	de::Random				m_random;
196
197	mutable de::Mutex		m_messageLock;
198	std::vector<Message>	m_messages;
199	ThreadStatus			m_status;
200	std::vector<deUint8>	m_dummyData;
201
202	// Disabled
203							Thread				(const Thread&);
204	Thread					operator=			(const Thread&);
205};
206
207class DataBlock : public Object
208{
209public:
210					DataBlock	(de::SharedPtr<Event> event);
211
212	void			setData		(size_t size, const void* data);
213	const deUint8*	getData		(void) const { return &(m_data[0]); }
214	size_t			getSize		(void) const { return m_data.size(); }
215
216private:
217	std::vector<deUint8> m_data;
218};
219
220
221class CompareData : public Operation
222{
223public:
224			CompareData	(de::SharedPtr<DataBlock> a, de::SharedPtr<DataBlock> b);
225	void	exec		(Thread& thread);
226
227private:
228	de::SharedPtr<DataBlock>	m_a;
229	de::SharedPtr<DataBlock>	m_b;
230};
231
232} // ThreadUtil
233} // tcu
234
235#endif // _TCUTHREADUTIL_HPP
236