mxw_wotlk_azerothcore/deps/g3dlite/source/GThread.cpp

265 lines
5.7 KiB
C++

/**
@file GThread.cpp
GThread class.
@created 2005-09-24
@edited 2010-09-22
*/
#include "G3D/GThread.h"
#include "G3D/System.h"
#include "G3D/debugAssert.h"
#include "G3D/GMutex.h"
namespace G3D {
namespace _internal {
class BasicThread: public GThread {
public:
BasicThread(const std::string& name, void (*proc)(void*), void* param):
GThread(name), m_wrapperProc(proc), m_param(param) { }
protected:
virtual void threadMain() {
m_wrapperProc(m_param);
}
private:
void (*m_wrapperProc)(void*);
void* m_param;
};
} // namespace _internal
GThread::GThread(const std::string& name):
m_status(STATUS_CREATED),
m_name(name) {
#ifdef G3D_WINDOWS
m_event = NULL;
#endif
// system-independent clear of handle
System::memset(&m_handle, 0, sizeof(m_handle));
}
GThread::~GThread() {
#ifdef _MSC_VER
# pragma warning( push )
# pragma warning( disable : 4127 )
#endif
alwaysAssertM(m_status != STATUS_RUNNING, "Deleting thread while running.");
#ifdef _MSC_VER
# pragma warning( pop )
#endif
#ifdef G3D_WINDOWS
if (m_event) {
::CloseHandle(m_event);
}
#endif
}
GThreadRef GThread::create(const std::string& name, void (*proc)(void*), void* param) {
return shared_ptr<GThread>(new _internal::BasicThread(name, proc, param));
}
bool GThread::started() const {
return m_status != STATUS_CREATED;
}
int GThread::numCores() {
return System::numCores();
}
#ifdef G3D_WINDOWS
// From http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
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)
static void SetThreadName(DWORD dwThreadID, const char* threadName) {
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = threadName;
info.dwThreadID = dwThreadID;
info.dwFlags = 0;
__try {
RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
} __except(EXCEPTION_EXECUTE_HANDLER) {}
}
#endif
bool GThread::start(SpawnBehavior behavior) {
debugAssertM(! started(), "Thread has already executed.");
if (started()) {
return false;
}
m_status = STATUS_STARTED;
if (behavior == USE_CURRENT_THREAD) {
// Run on this thread
m_status = STATUS_RUNNING;
threadMain();
m_status = STATUS_COMPLETED;
return true;
}
# ifdef G3D_WINDOWS
DWORD threadId;
m_event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
debugAssert(m_event);
m_handle = ::CreateThread(NULL, 0, &internalThreadProc, this, 0, &threadId);
if (m_handle == NULL) {
::CloseHandle(m_event);
m_event = NULL;
}
SetThreadName(threadId, m_name.c_str());
return (m_handle != NULL);
# else
if (!pthread_create(&m_handle, NULL, &internalThreadProc, this)) {
return true;
} else {
// system-independent clear of handle
System::memset(&m_handle, 0, sizeof(m_handle));
return false;
}
# endif
}
void GThread::terminate() {
if (m_handle) {
# ifdef G3D_WINDOWS
::TerminateThread(m_handle, 0);
# else
pthread_kill(m_handle, SIGSTOP);
# endif
// system-independent clear of handle
System::memset(&m_handle, 0, sizeof(m_handle));
}
}
bool GThread::running() const{
return (m_status == STATUS_RUNNING);
}
bool GThread::completed() const {
return (m_status == STATUS_COMPLETED);
}
void GThread::waitForCompletion() {
if (m_status == STATUS_COMPLETED) {
// Must be done
return;
}
# ifdef G3D_WINDOWS
debugAssert(m_event);
::WaitForSingleObject(m_event, INFINITE);
# else
debugAssert(m_handle);
pthread_join(m_handle, NULL);
# endif
}
#ifdef G3D_WINDOWS
DWORD WINAPI GThread::internalThreadProc(LPVOID param) {
GThread* current = reinterpret_cast<GThread*>(param);
debugAssert(current->m_event);
current->m_status = STATUS_RUNNING;
current->threadMain();
current->m_status = STATUS_COMPLETED;
::SetEvent(current->m_event);
return 0;
}
#else
void* GThread::internalThreadProc(void* param) {
GThread* current = reinterpret_cast<GThread*>(param);
current->m_status = STATUS_RUNNING;
current->threadMain();
current->m_status = STATUS_COMPLETED;
return (void*)NULL;
}
#endif
//GMutex implementation
GMutex::GMutex() {
#ifdef G3D_WINDOWS
::InitializeCriticalSection(&m_handle);
#else
int ret = pthread_mutexattr_init(&m_attr);
debugAssert(ret == 0);
ret = pthread_mutexattr_settype(&m_attr, PTHREAD_MUTEX_RECURSIVE);
debugAssert(ret == 0);
ret = pthread_mutex_init(&m_handle, &m_attr);
debugAssert(ret == 0);
#endif
}
GMutex::~GMutex() {
//TODO: Debug check for locked
#ifdef G3D_WINDOWS
::DeleteCriticalSection(&m_handle);
#else
int ret = pthread_mutex_destroy(&m_handle);
debugAssert(ret == 0);
ret = pthread_mutexattr_destroy(&m_attr);
debugAssert(ret == 0);
#endif
}
bool GMutex::tryLock() {
#ifdef G3D_WINDOWS
return (::TryEnterCriticalSection(&m_handle) != 0);
#else
return (pthread_mutex_trylock(&m_handle) == 0);
#endif
}
void GMutex::lock() {
#ifdef G3D_WINDOWS
::EnterCriticalSection(&m_handle);
#else
pthread_mutex_lock(&m_handle);
#endif
}
void GMutex::unlock() {
#ifdef G3D_WINDOWS
::LeaveCriticalSection(&m_handle);
#else
pthread_mutex_unlock(&m_handle);
#endif
}
} // namespace G3D