#include #include #include #ifdef _MSC_VER //begin Microsoft Visual C++ specific code #include #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 _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 > 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()); }