Initial commit
This commit is contained in:
322
ZUtil/ZThread.cpp
Normal file
322
ZUtil/ZThread.cpp
Normal file
@@ -0,0 +1,322 @@
|
||||
#include <ZUtil/ZThread.hpp>
|
||||
#include <ZUtil/ZLog.hpp>
|
||||
#include <ZSTL/ZString.hpp>
|
||||
|
||||
#ifdef _MSC_VER //begin Microsoft Visual C++ specific code
|
||||
#include <windows.h>
|
||||
#undef CreateMutex
|
||||
#undef CreateEvent
|
||||
const DWORD MS_VC_EXCEPTION=0x406D1388;
|
||||
|
||||
#pragma pack(push,8)
|
||||
typedef struct tagTHREADNAME_INFO
|
||||
{
|
||||
DWORD dwType; // Must be 0x1000.
|
||||
LPCSTR szName; // Pointer to name (in user addr space).
|
||||
DWORD dwThreadID; // Thread ID (-1=caller thread).
|
||||
DWORD dwFlags; // Reserved for future use, must be zero.
|
||||
} THREADNAME_INFO;
|
||||
#pragma pack(pop)
|
||||
|
||||
//This disgusting little hack sets the thread's name in the MSVC debugger
|
||||
void NativeSetThreadName(const char* threadName)
|
||||
{
|
||||
THREADNAME_INFO info;
|
||||
info.dwType = 0x1000;
|
||||
info.szName = threadName;
|
||||
info.dwThreadID = (DWORD)~0;
|
||||
info.dwFlags = 0;
|
||||
|
||||
__try
|
||||
{
|
||||
RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
#define NativeSetThreadName(name)
|
||||
#endif //end Microsoft Visual C++ specific code
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZThread::ZThread(ZString _threadName)
|
||||
:
|
||||
ThreadName(_threadName),
|
||||
bShouldShutdown(false), bShouldPause(false),
|
||||
ThreadContext(),
|
||||
ThreadLock(),
|
||||
InitEvent(),
|
||||
PreviousTickCount(0), CurrentTickCount(0),
|
||||
bIsRunning(false), bIsInitialized(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZThread::~ZThread()
|
||||
{
|
||||
ShutdownThread();
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
int ZThread::InitThread(void *_runnable)
|
||||
{
|
||||
ZThread *thr = ((ZThread*)_runnable);
|
||||
|
||||
NativeSetThreadName(thr->GetThreadName().Data());
|
||||
|
||||
//TODO - hack for now, need to fix CreateThread
|
||||
thr->ThreadContext.ThreadId = ZConcurrency::GetThreadId();
|
||||
|
||||
thr->initThread();
|
||||
|
||||
thr->bIsInitialized = true;
|
||||
|
||||
thr->InitEvent.Notify();
|
||||
|
||||
thr->Run();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZThread::Run()
|
||||
{
|
||||
uint64_t dt;
|
||||
|
||||
bIsRunning = true;
|
||||
|
||||
while (!bShouldShutdown)
|
||||
{
|
||||
while (bShouldPause)
|
||||
ZConcurrency::YieldThread();
|
||||
|
||||
ExecuteThreadRequests();
|
||||
|
||||
PreviousTickCount = CurrentTickCount;
|
||||
CurrentTickCount = ZConcurrency::GetTicks();
|
||||
dt = CurrentTickCount - PreviousTickCount;
|
||||
|
||||
switch (run(dt))
|
||||
{
|
||||
case ZTR_LOOP: continue;
|
||||
case ZTR_PAUSE: bShouldPause = true; break;
|
||||
case ZTR_TERMINATE: bShouldShutdown = true; break;
|
||||
default: bShouldShutdown = true; break;
|
||||
}
|
||||
}
|
||||
|
||||
ExecuteThreadRequests();
|
||||
|
||||
shutdownThread();
|
||||
|
||||
bIsInitialized = false;
|
||||
bIsRunning = false;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZThread::AddThreadRequest(ZPtr<ZThreadRequest> _request, bool _wait)
|
||||
{
|
||||
|
||||
//If this is thread adding a request to itself, don't deadlock
|
||||
if(IsCallerTheThread()) {
|
||||
_request->Execute(this);
|
||||
return;
|
||||
}
|
||||
|
||||
ThreadLock.Acquire();
|
||||
{
|
||||
ZTRCallbacks.PushBack(_request);
|
||||
}
|
||||
ThreadLock.Release();
|
||||
|
||||
if (_wait)
|
||||
_request->Wait();
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZThread::AddCallbackRequest(ZThreadCallbackFunc function, void* arg, bool async)
|
||||
{
|
||||
ZThreadCallbackRequest req;
|
||||
|
||||
//If this is the thread adding a callback to itself, don't deadlock
|
||||
if(IsCallerTheThread()) {
|
||||
function(this, arg);
|
||||
return;
|
||||
}
|
||||
|
||||
req.arg = arg;
|
||||
req.callback = function;
|
||||
req.doneEvent = (async ? NULL : SST_Concurrency_CreateEvent());
|
||||
|
||||
ThreadLock.Acquire();
|
||||
{
|
||||
Callbacks.PushBack(req);
|
||||
}
|
||||
ThreadLock.Release();
|
||||
|
||||
//Non-async -> wait for done
|
||||
if(!async) {
|
||||
SST_Concurrency_WaitEvent(req.doneEvent, SST_WAIT_INFINITE);
|
||||
SST_Concurrency_DestroyEvent(req.doneEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZThread::ExecuteThreadRequests()
|
||||
{
|
||||
ZList< ZPtr<ZThreadRequest> > persistentRequests;
|
||||
|
||||
ThreadLock.Acquire();
|
||||
|
||||
while (!ZTRCallbacks.Empty())
|
||||
{
|
||||
//Don't execute if we are told to stop
|
||||
if (ZTRCallbacks.Front()->Stop)
|
||||
{
|
||||
ZTRCallbacks.Front()->Persist = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ZTRCallbacks.Front()->CompletedEvent.Reset();
|
||||
|
||||
ZTRCallbacks.Front()->Execute(this);
|
||||
|
||||
ZTRCallbacks.Front()->CompletedEvent.Notify();
|
||||
}
|
||||
|
||||
//If we are to persist, do so
|
||||
if (ZTRCallbacks.Front()->Persist)
|
||||
persistentRequests.PushBack(ZTRCallbacks.PopFront());
|
||||
else
|
||||
ZTRCallbacks.PopFront();
|
||||
}
|
||||
|
||||
while(!Callbacks.Empty()) {
|
||||
ZThreadCallbackRequest& req = Callbacks.Front();
|
||||
|
||||
req.callback(this, req.arg);
|
||||
if(req.doneEvent) {
|
||||
SST_Concurrency_SignalEvent(req.doneEvent);
|
||||
}
|
||||
|
||||
Callbacks.PopFront();
|
||||
}
|
||||
|
||||
|
||||
//Swap back in persistent requests
|
||||
ZTRCallbacks.Swap(persistentRequests);
|
||||
|
||||
ThreadLock.Release();
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
bool ZThread::StartThread()
|
||||
{
|
||||
bShouldShutdown = false;
|
||||
bShouldPause = false;
|
||||
|
||||
ThreadContext = ZConcurrency::CreateThread(ZThread::InitThread, this);
|
||||
|
||||
if (!ThreadContext.IsValid())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZThread::ShutdownThread()
|
||||
{
|
||||
bShouldShutdown = true;
|
||||
|
||||
if (ThreadContext.IsValid())
|
||||
{
|
||||
ZConcurrency::WaitThread(ThreadContext);
|
||||
ZConcurrency::DestroyThread(ThreadContext);
|
||||
ThreadContext.Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZThread::PauseThread()
|
||||
{
|
||||
bShouldPause = true;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZThread::RestartThread()
|
||||
{
|
||||
bShouldPause = false;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
bool ZThread::ThreadRunning()
|
||||
{
|
||||
return bIsRunning;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
bool ZThread::ThreadInitialized()
|
||||
{
|
||||
return bIsInitialized;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
uint32_t ZThread::GetThreadId()
|
||||
{
|
||||
return ThreadContext.ThreadId;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZString ZThread::GetThreadName()
|
||||
{
|
||||
ZString name;
|
||||
|
||||
ThreadLock.Acquire();
|
||||
|
||||
name = ThreadName;
|
||||
|
||||
ThreadLock.Release();
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZThread::WaitInitialized()
|
||||
{
|
||||
InitEvent.Wait();
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZThread::WaitShutdown()
|
||||
{
|
||||
if (ThreadContext.IsValid())
|
||||
ZConcurrency::WaitThread(ThreadContext);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
bool ZThread::IsCallerTheThread()
|
||||
{
|
||||
uint32_t callerThreadID = SST_Concurrency_GetThreadId();
|
||||
|
||||
return (callerThreadID == this->GetThreadId());
|
||||
}
|
||||
Reference in New Issue
Block a user