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 56 { 57 return m_result; 58 } 59 60 private: 61 volatile Result m_result; 62 volatile int m_waiterCount; 63 de::Semaphore m_waiters; 64 de::Mutex m_lock; 65 66 // Disabled 67 Event(const Event &); 68 Event &operator=(const Event &); 69 }; 70 71 // Base class for objects which modifications should be tracked between threads 72 class Object 73 { 74 public: 75 Object(const char *type, de::SharedPtr<Event> createEvent); 76 virtual ~Object(void); getType(void) const77 const char *getType(void) const 78 { 79 return m_type; 80 } 81 82 // Used by class Operation only 83 void read(de::SharedPtr<Event> event, std::vector<de::SharedPtr<Event>> &deps); 84 void modify(de::SharedPtr<Event> event, std::vector<de::SharedPtr<Event>> &deps); 85 86 private: 87 const char *m_type; 88 de::SharedPtr<Event> m_modify; 89 std::vector<de::SharedPtr<Event>> m_reads; 90 91 // Disabled 92 Object(const Object &); 93 Object &operator=(const Object &); 94 }; 95 96 class Thread; 97 98 class MessageBuilder 99 { 100 public: MessageBuilder(Thread & thread)101 MessageBuilder(Thread &thread) : m_thread(thread) 102 { 103 } MessageBuilder(const MessageBuilder & other)104 MessageBuilder(const MessageBuilder &other) : m_thread(other.m_thread), m_stream(other.m_stream.str()) 105 { 106 } 107 template <class T> operator <<(const T & t)108 MessageBuilder &operator<<(const T &t) 109 { 110 m_stream << t; 111 return *this; 112 } 113 114 class EndToken 115 { 116 public: EndToken(void)117 EndToken(void) 118 { 119 } 120 }; 121 122 void operator<<(const EndToken &); 123 124 private: 125 Thread &m_thread; 126 std::stringstream m_stream; 127 }; 128 129 class Message 130 { 131 public: Message(uint64_t time,const char * message)132 Message(uint64_t time, const char *message) : m_time(time), m_message(message) 133 { 134 } 135 getTime(void) const136 uint64_t getTime(void) const 137 { 138 return m_time; 139 } getMessage(void) const140 const std::string &getMessage(void) const 141 { 142 return m_message; 143 } 144 145 static const MessageBuilder::EndToken End; 146 147 private: 148 uint64_t m_time; 149 std::string m_message; 150 }; 151 152 // Base class for operations executed by threads 153 class Operation 154 { 155 public: 156 Operation(const char *name); 157 virtual ~Operation(void); 158 getName(void) const159 const char *getName(void) const 160 { 161 return m_name; 162 } getEvent(void)163 de::SharedPtr<Event> getEvent(void) 164 { 165 return m_event; 166 } 167 readObject(de::SharedPtr<Object> object)168 void readObject(de::SharedPtr<Object> object) 169 { 170 object->read(m_event, m_deps); 171 } modifyObject(de::SharedPtr<Object> object)172 void modifyObject(de::SharedPtr<Object> object) 173 { 174 object->modify(m_event, m_deps); 175 } 176 177 virtual void exec(Thread &thread) = 0; //!< Overwritten by inherited class to perform actual operation 178 virtual void execute( 179 Thread &thread); //!< May Be overwritten by inherited class to change how syncronization is done 180 181 protected: 182 const char *m_name; 183 std::vector<de::SharedPtr<Event>> m_deps; 184 de::SharedPtr<Event> m_event; 185 186 Operation(const Operation &); 187 Operation &operator=(const Operation &); 188 }; 189 190 class Thread : public de::Thread 191 { 192 public: 193 enum ThreadStatus 194 { 195 THREADSTATUS_NOT_STARTED = 0, 196 THREADSTATUS_INIT_FAILED, 197 THREADSTATUS_RUNNING, 198 THREADSTATUS_READY, 199 THREADSTATUS_FAILED, 200 THREADSTATUS_NOT_SUPPORTED 201 }; 202 Thread(uint32_t seed); 203 ~Thread(void); 204 init(void)205 virtual void init(void) 206 { 207 } //!< Called first before any Operation 208 209 // \todo [mika] Should the result of execution be passed to deinit? deinit(void)210 virtual void deinit(void) 211 { 212 } //!< Called after after operation 213 214 void addOperation(Operation *operation); 215 216 void exec(void); 217 218 uint8_t *getUnusedData( 219 size_t size); //!< Return data pointer that contains at least size bytes. Valid until next call 220 getStatus(void) const221 ThreadStatus getStatus(void) const 222 { 223 de::ScopedLock lock(m_statusLock); 224 return m_status; 225 } setStatus(ThreadStatus status)226 void setStatus(ThreadStatus status) 227 { 228 de::ScopedLock lock(m_statusLock); 229 m_status = status; 230 } 231 newMessage(void)232 MessageBuilder newMessage(void) 233 { 234 return MessageBuilder(*this); 235 } getRandom(void)236 de::Random &getRandom(void) 237 { 238 return m_random; 239 } 240 241 // Used to by test case to read log messages 242 int getMessageCount(void) const; 243 Message getMessage(int index) const; 244 245 // Used by message builder 246 void pushMessage(const std::string &str); 247 248 private: 249 virtual void run(void); 250 251 std::vector<Operation *> m_operations; 252 de::Random m_random; 253 254 mutable de::Mutex m_messageLock; 255 std::vector<Message> m_messages; 256 mutable de::Mutex m_statusLock; 257 ThreadStatus m_status; 258 std::vector<uint8_t> m_unusedData; 259 260 // Disabled 261 Thread(const Thread &); 262 Thread operator=(const Thread &); 263 }; 264 265 class DataBlock : public Object 266 { 267 public: 268 DataBlock(de::SharedPtr<Event> event); 269 270 void setData(size_t size, const void *data); getData(void) const271 const uint8_t *getData(void) const 272 { 273 return &(m_data[0]); 274 } getSize(void) const275 size_t getSize(void) const 276 { 277 return m_data.size(); 278 } 279 280 private: 281 std::vector<uint8_t> m_data; 282 }; 283 284 class CompareData : public Operation 285 { 286 public: 287 CompareData(de::SharedPtr<DataBlock> a, de::SharedPtr<DataBlock> b); 288 void exec(Thread &thread); 289 290 private: 291 de::SharedPtr<DataBlock> m_a; 292 de::SharedPtr<DataBlock> m_b; 293 }; 294 295 } // namespace ThreadUtil 296 } // namespace tcu 297 298 #endif // _TCUTHREADUTIL_HPP 299