238 lines
6.2 KiB
C++
238 lines
6.2 KiB
C++
#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* getUnusedData (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_unusedData;
|
|
|
|
// 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
|