// IsThread.cpp
// Implements the cIsThread class representing an OS-independent wrapper for a class that implements a thread.
// This class will eventually suupersede the old cThread class
#include "Globals.h"
#include "IsThread.h"
// When in MSVC, the debugger provides "thread naming" by catching special exceptions. Interface here:
#if defined(_MSC_VER) && defined(_DEBUG)
//
// Usage: SetThreadName (-1, "MainThread");
//
// Code adapted from MSDN: 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 // _MSC_VER && _DEBUG
////////////////////////////////////////////////////////////////////////////////
// cIsThread:
cIsThread::cIsThread(const AString & iThreadName) :
m_ShouldTerminate(false),
m_ThreadName(iThreadName),
m_Handle(NULL_HANDLE)
{
}
cIsThread::~cIsThread()
{
m_ShouldTerminate = true;
Wait();
}
bool cIsThread::Start(void)
{
ASSERT(m_Handle == NULL_HANDLE); // Has already started one thread?
#ifdef _WIN32
// Create the thread suspended, so that the mHandle variable is valid in the thread procedure
DWORD ThreadID = 0;
m_Handle = CreateThread(NULL, 0, thrExecute, this, CREATE_SUSPENDED, &ThreadID);
if (m_Handle == NULL)
{
LOGERROR("ERROR: Could not create thread \"%s\", GLE = %d!", m_ThreadName.c_str(), GetLastError());
return false;
}
ResumeThread(m_Handle);
#if defined(_DEBUG) && defined(_MSC_VER)
// Thread naming is available only in MSVC
if (!m_ThreadName.empty())
{
SetThreadName(ThreadID, m_ThreadName.c_str());
}
#endif // _DEBUG and _MSC_VER
#else // _WIN32
if (pthread_create(&m_Handle, NULL, thrExecute, this))
{
LOGERROR("ERROR: Could not create thread \"%s\", !", m_ThreadName.c_str());
return false;
}
#endif // else _WIN32
return true;
}
void cIsThread::Stop(void)
{
if (m_Handle == NULL_HANDLE)
{
return;
}
m_ShouldTerminate = true;
Wait();
}
bool cIsThread::Wait(void)
{
if (m_Handle == NULL_HANDLE)
{
return true;
}
#ifdef LOGD // ProtoProxy doesn't have LOGD
LOGD("Waiting for thread %s to finish", m_ThreadName.c_str());
#endif // LOGD
#ifdef _WIN32
int res = WaitForSingleObject(m_Handle, INFINITE);
m_Handle = NULL;
#ifdef LOGD // ProtoProxy doesn't have LOGD
LOGD("Thread %s finished", m_ThreadName.c_str());
#endif // LOGD
return (res == WAIT_OBJECT_0);
#else // _WIN32
int res = pthread_join(m_Handle, NULL);
m_Handle = NULL_HANDLE;
#ifdef LOGD // ProtoProxy doesn't have LOGD
LOGD("Thread %s finished", m_ThreadName.c_str());
#endif // LOGD
return (res == 0);
#endif // else _WIN32
}
unsigned long cIsThread::GetCurrentID(void)
{
#ifdef _WIN32
return (unsigned long) GetCurrentThreadId();
#else
return (unsigned long) pthread_self();
#endif
}