#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 (int 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 { return m_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; 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