| #ifndef _TCUTHREADUTIL_HPP |
| #define _TCUTHREADUTIL_HPP |
| /*------------------------------------------------------------------------- |
| * drawElements Quality Program Tester Core |
| * ---------------------------------------- |
| * |
| * Copyright 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| *//*! |
| * \file |
| * \brief Thread test utilities |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "tcuDefs.hpp" |
| #include "deSharedPtr.hpp" |
| #include "deMutex.hpp" |
| #include "deSemaphore.hpp" |
| #include "deThread.hpp" |
| #include "deRandom.hpp" |
| |
| #include <vector> |
| #include <sstream> |
| |
| namespace tcu |
| { |
| namespace ThreadUtil |
| { |
| // Event object for synchronizing threads |
| class Event |
| { |
| public: |
| enum Result |
| { |
| RESULT_NOT_READY = 0, |
| RESULT_OK, |
| RESULT_FAILED |
| }; |
| |
| Event (void); |
| ~Event (void); |
| void setResult (Result result); |
| Result waitReady (void); |
| Result getResult (void) const { return m_result; } |
| |
| private: |
| volatile Result m_result; |
| volatile int m_waiterCount; |
| de::Semaphore m_waiters; |
| de::Mutex m_lock; |
| |
| // Disabled |
| Event (const Event&); |
| Event& operator= (const Event&); |
| }; |
| |
| // Base class for objects which modifications should be tracked between threads |
| class Object |
| { |
| public: |
| Object (const char* type, de::SharedPtr<Event> createEvent); |
| virtual ~Object (void); |
| const char* getType (void) const { return m_type; } |
| |
| // Used by class Operation only |
| void read (de::SharedPtr<Event> event, std::vector<de::SharedPtr<Event> >& deps); |
| void modify (de::SharedPtr<Event> event, std::vector<de::SharedPtr<Event> >& deps); |
| |
| private: |
| const char* m_type; |
| de::SharedPtr<Event> m_modify; |
| std::vector<de::SharedPtr<Event> > m_reads; |
| |
| // Disabled |
| Object (const Object&); |
| Object& operator= (const Object&); |
| }; |
| |
| class Thread; |
| |
| class MessageBuilder |
| { |
| public: |
| MessageBuilder (Thread& thread) : m_thread(thread) {} |
| MessageBuilder (const MessageBuilder& other) : m_thread(other.m_thread), m_stream(other.m_stream.str()) {} |
| template<class T> |
| MessageBuilder& operator<< (const T& t) { m_stream << t; return *this; } |
| |
| class EndToken |
| { |
| public: |
| EndToken (void) {} |
| }; |
| |
| void operator<< (const EndToken&); |
| |
| private: |
| Thread& m_thread; |
| std::stringstream m_stream; |
| }; |
| |
| class Message |
| { |
| public: |
| Message (deUint64 time, const char* message) : m_time(time), m_message(message) {} |
| |
| deUint64 getTime (void) const { return m_time; } |
| const std::string& getMessage (void) const { return m_message; } |
| |
| static const MessageBuilder::EndToken End; |
| |
| private: |
| deUint64 m_time; |
| std::string m_message; |
| }; |
| |
| // Base class for operations executed by threads |
| class Operation |
| { |
| public: |
| Operation (const char* name); |
| virtual ~Operation (void); |
| |
| const char* getName (void) const { return m_name; } |
| de::SharedPtr<Event> getEvent (void) { return m_event; } |
| |
| void readObject (de::SharedPtr<Object> object) { object->read(m_event, m_deps); } |
| void modifyObject (de::SharedPtr<Object> object) { object->modify(m_event, m_deps); } |
| |
| virtual void exec (Thread& thread) = 0; //!< Overwritten by inherited class to perform actual operation |
| virtual void execute (Thread& thread); //!< May Be overwritten by inherited class to change how syncronization is done |
| |
| protected: |
| const char* m_name; |
| std::vector<de::SharedPtr<Event> > m_deps; |
| de::SharedPtr<Event> m_event; |
| |
| Operation (const Operation&); |
| Operation& operator= (const Operation&); |
| }; |
| |
| class Thread : public de::Thread |
| { |
| public: |
| enum ThreadStatus |
| { |
| THREADSTATUS_NOT_STARTED = 0, |
| THREADSTATUS_INIT_FAILED, |
| THREADSTATUS_RUNNING, |
| THREADSTATUS_READY, |
| THREADSTATUS_FAILED, |
| THREADSTATUS_NOT_SUPPORTED |
| }; |
| Thread (deUint32 seed); |
| ~Thread (void); |
| |
| virtual void init (void) {} //!< Called first before any Operation |
| |
| // \todo [mika] Should the result of execution be passed to deinit? |
| virtual void deinit (void) {} //!< Called after after operation |
| |
| void addOperation (Operation* operation); |
| |
| void exec (void); |
| |
| deUint8* getDummyData (size_t size); //!< Return data pointer that contains at least size bytes. Valid until next call |
| |
| ThreadStatus getStatus (void) const { de::ScopedLock lock(m_statusLock); return m_status; } |
| void setStatus (ThreadStatus status) { de::ScopedLock lock(m_statusLock); m_status = status; } |
| |
| MessageBuilder newMessage (void) { return MessageBuilder(*this); } |
| de::Random& getRandom (void) { return m_random; } |
| |
| // Used to by test case to read log messages |
| int getMessageCount (void) const; |
| Message getMessage (int index) const; |
| |
| // Used by message builder |
| void pushMessage (const std::string& str); |
| |
| private: |
| virtual void run (void); |
| |
| std::vector<Operation*> m_operations; |
| de::Random m_random; |
| |
| mutable de::Mutex m_messageLock; |
| std::vector<Message> m_messages; |
| mutable de::Mutex m_statusLock; |
| ThreadStatus m_status; |
| std::vector<deUint8> m_dummyData; |
| |
| // Disabled |
| Thread (const Thread&); |
| Thread operator= (const Thread&); |
| }; |
| |
| class DataBlock : public Object |
| { |
| public: |
| DataBlock (de::SharedPtr<Event> event); |
| |
| void setData (size_t size, const void* data); |
| const deUint8* getData (void) const { return &(m_data[0]); } |
| size_t getSize (void) const { return m_data.size(); } |
| |
| private: |
| std::vector<deUint8> m_data; |
| }; |
| |
| |
| class CompareData : public Operation |
| { |
| public: |
| CompareData (de::SharedPtr<DataBlock> a, de::SharedPtr<DataBlock> b); |
| void exec (Thread& thread); |
| |
| private: |
| de::SharedPtr<DataBlock> m_a; |
| de::SharedPtr<DataBlock> m_b; |
| }; |
| |
| } // ThreadUtil |
| } // tcu |
| |
| #endif // _TCUTHREADUTIL_HPP |