Home | History | Annotate | Download | only in common
      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);
     55 	Result	getResult	(void) const { return m_result; }
     56 
     57 private:
     58 	Result			m_result;
     59 	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);
     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 
     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:
     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 
    108 private:
    109 	Thread&				m_thread;
    110 	std::stringstream	m_stream;
    111 };
    112 
    113 class Message
    114 {
    115 public:
    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 
    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 
    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 
    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				(int 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 { return (int)(m_messages.size()); }
    186 	const Message&	getMessage			(int index) const { return m_messages[index]; }
    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 	std::vector<Message>	m_messages;
    198 	ThreadStatus			m_status;
    199 	std::vector<deUint8>	m_dummyData;
    200 
    201 	// Disabled
    202 					Thread				(const Thread&);
    203 	Thread			operator=			(const Thread&);
    204 };
    205 
    206 class DataBlock : public Object
    207 {
    208 public:
    209 					DataBlock	(de::SharedPtr<Event> event);
    210 
    211 	void			setData		(size_t size, const void* data);
    212 	const deUint8*	getData		(void) const { return &(m_data[0]); }
    213 	size_t			getSize		(void) const { return m_data.size(); }
    214 
    215 private:
    216 	std::vector<deUint8> m_data;
    217 };
    218 
    219 
    220 class CompareData : public Operation
    221 {
    222 public:
    223 			CompareData	(de::SharedPtr<DataBlock> a, de::SharedPtr<DataBlock> b);
    224 	void	exec		(Thread& thread);
    225 
    226 private:
    227 	de::SharedPtr<DataBlock>	m_a;
    228 	de::SharedPtr<DataBlock>	m_b;
    229 };
    230 
    231 } // ThreadUtil
    232 } // tcu
    233 
    234 #endif // _TCUTHREADUTIL_HPP
    235