• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 { de::ScopedLock lock(m_statusLock); return m_status; }
setStatus(ThreadStatus status)180 	void				setStatus			(ThreadStatus status) { de::ScopedLock lock(m_statusLock); m_status = status; }
181 
newMessage(void)182 	MessageBuilder			newMessage			(void) { return MessageBuilder(*this); }
getRandom(void)183 	de::Random&				getRandom			(void) { return m_random; }
184 
185 	// Used to by test case to read log messages
186 	int						getMessageCount		(void) const;
187 	Message					getMessage			(int index) const;
188 
189 	// Used by message builder
190 	void					pushMessage			(const std::string& str);
191 
192 private:
193 	virtual void			run					(void);
194 
195 	std::vector<Operation*>	m_operations;
196 	de::Random				m_random;
197 
198 	mutable de::Mutex		m_messageLock;
199 	std::vector<Message>	m_messages;
200 	mutable de::Mutex		m_statusLock;
201 	ThreadStatus			m_status;
202 	std::vector<deUint8>	m_dummyData;
203 
204 	// Disabled
205 							Thread				(const Thread&);
206 	Thread					operator=			(const Thread&);
207 };
208 
209 class DataBlock : public Object
210 {
211 public:
212 					DataBlock	(de::SharedPtr<Event> event);
213 
214 	void			setData		(size_t size, const void* data);
getData(void) const215 	const deUint8*	getData		(void) const { return &(m_data[0]); }
getSize(void) const216 	size_t			getSize		(void) const { return m_data.size(); }
217 
218 private:
219 	std::vector<deUint8> m_data;
220 };
221 
222 
223 class CompareData : public Operation
224 {
225 public:
226 			CompareData	(de::SharedPtr<DataBlock> a, de::SharedPtr<DataBlock> b);
227 	void	exec		(Thread& thread);
228 
229 private:
230 	de::SharedPtr<DataBlock>	m_a;
231 	de::SharedPtr<DataBlock>	m_b;
232 };
233 
234 } // ThreadUtil
235 } // tcu
236 
237 #endif // _TCUTHREADUTIL_HPP
238