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