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