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 
36 namespace tcu
37 {
38 namespace ThreadUtil
39 {
40 // Event object for synchronizing threads
41 class Event
42 {
43 public:
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);
getResult(void) const55 	Result			getResult	(void) const { return m_result; }
56 
57 private:
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
69 class Object
70 {
71 public:
72 										Object		(const char* type, de::SharedPtr<Event> createEvent);
73 	virtual								~Object		(void);
getType(void) const74 	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 
80 private:
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 
90 class Thread;
91 
92 class MessageBuilder
93 {
94 public:
MessageBuilder(Thread & thread)95 						MessageBuilder		(Thread& thread) : m_thread(thread) {}
MessageBuilder(const MessageBuilder & other)96 						MessageBuilder		(const MessageBuilder& other) : m_thread(other.m_thread), m_stream(other.m_stream.str()) {}
97 	template<class T>
operator <<(const T & t)98 	MessageBuilder&		operator<<			(const T& t) { m_stream << t; return *this; }
99 
100 	class EndToken
101 	{
102 	public:
EndToken(void)103 						EndToken			(void) {}
104 	};
105 
106 	void 				operator<<			(const EndToken&);
107 
108 private:
109 	Thread&				m_thread;
110 	std::stringstream	m_stream;
111 };
112 
113 class Message
114 {
115 public:
Message(deUint64 time,const char * message)116 						Message		(deUint64 time, const char* message) : m_time(time), m_message(message) {}
117 
getTime(void) const118 	deUint64			getTime		(void) const { return m_time; }
getMessage(void) const119 	const std::string&	getMessage	(void) const { return m_message; }
120 
121 	static const MessageBuilder::EndToken End;
122 
123 private:
124 	deUint64			m_time;
125 	std::string			m_message;
126 };
127 
128 // Base class for operations executed by threads
129 class Operation
130 {
131 public:
132 											Operation		(const char* name);
133 	virtual									~Operation		(void);
134 
getName(void) const135 	const char*								getName			(void) const { return m_name; }
getEvent(void)136 	de::SharedPtr<Event>					getEvent		(void) { return m_event; }
137 
readObject(de::SharedPtr<Object> object)138 	void									readObject		(de::SharedPtr<Object> object) { object->read(m_event, m_deps); }
modifyObject(de::SharedPtr<Object> object)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 
144 protected:
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 
153 class Thread : public de::Thread
154 {
155 public:
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 
init(void)168 	virtual void			init				(void) {}	//!< Called first before any Operation
169 
170 	// \todo [mika] Should the result of execution be passed to deinit?
deinit(void)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 
getStatus(void) const179 	ThreadStatus			getStatus			(void) const { return m_status; }
180 
newMessage(void)181 	MessageBuilder			newMessage			(void) { return MessageBuilder(*this); }
getRandom(void)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 
191 private:
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 
207 class DataBlock : public Object
208 {
209 public:
210 					DataBlock	(de::SharedPtr<Event> event);
211 
212 	void			setData		(size_t size, const void* data);
getData(void) const213 	const deUint8*	getData		(void) const { return &(m_data[0]); }
getSize(void) const214 	size_t			getSize		(void) const { return m_data.size(); }
215 
216 private:
217 	std::vector<deUint8> m_data;
218 };
219 
220 
221 class CompareData : public Operation
222 {
223 public:
224 			CompareData	(de::SharedPtr<DataBlock> a, de::SharedPtr<DataBlock> b);
225 	void	exec		(Thread& thread);
226 
227 private:
228 	de::SharedPtr<DataBlock>	m_a;
229 	de::SharedPtr<DataBlock>	m_b;
230 };
231 
232 } // ThreadUtil
233 } // tcu
234 
235 #endif // _TCUTHREADUTIL_HPP
236