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 	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);
     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				(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 
    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);
    213 	const deUint8*	getData		(void) const { return &(m_data[0]); }
    214 	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