summaryrefslogblamecommitdiffstats
path: root/source/cIsThread.cpp
blob: 4aa25b534d38954d4800d92e64c0f3ce0cc03f02 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15














                                                                                                               
                                         


























                                                                                             
                              







































































































                                                                                                                                        

// cIsThread.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 "cIsThread.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");
//

static void SetThreadName( DWORD dwThreadID, LPCSTR szThreadName)
{
	struct
	{
		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
	} info;
	
	info.dwType = 0x1000;
	info.szName = szThreadName;
	info.dwThreadID = dwThreadID;
	info.dwFlags = 0;

	__try
	{
		RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD), (DWORD *)&info);
	}
	__except(EXCEPTION_CONTINUE_EXECUTION)
	{
	}
}
#endif  // _MSC_VER && _DEBUG





////////////////////////////////////////////////////////////////////////////////
// cIsThread:

cIsThread::cIsThread(const AString & iThreadName) :
	mThreadName(iThreadName),
	mShouldTerminate(false),
	#ifdef _WIN32
	mHandle(NULL)
	#else  // _WIN32
	mHasStarted(false)
	#endif  // else _WIN32
{
}





cIsThread::~cIsThread()
{
	Wait();
}





bool cIsThread::Start(void)
{
	#ifdef _WIN32
		assert(mHandle == NULL);  // Has already started one thread?
		
		// Create the thread suspended, so that the mHandle variable is valid in the thread procedure
		DWORD ThreadID = 0;
		HANDLE mHandle = CreateThread(NULL, 0, thrExecute, this, CREATE_SUSPENDED, &ThreadID);
		if (mHandle == NULL)
		{
			LOGERROR("ERROR: Could not create thread \"%s\", GLE = %d!", mThreadName.c_str(), GetLastError());
			return false;
		}
		ResumeThread(mHandle);

		#if defined(_DEBUG) && defined(_MSC_VER)
			// Thread naming is available only in MSVC
			if (!mThreadName.empty())
			{
				SetThreadName(ThreadID, mThreadName.c_str());
			}
		#endif  // _DEBUG and _MSC_VER
		
	#else  // _WIN32
		assert(!mHasStarted);
		
		if (pthread_create(&mHandle, NULL, thrExecute, this))
		{
			LOGERROR("ERROR: Could not create thread \"%s\", !", mThreadName.c_str());
			return false;
		}
	#endif  // else _WIN32

	return true;
}





bool cIsThread::Wait(void)
{
	#ifdef _WIN32
	
		if (mHandle == NULL)
		{
			return true;
		}
		LOG("Waiting for thread \"%s\" to terminate.", mThreadName.c_str());
		int res = WaitForSingleObject(mHandle, INFINITE);
		mHandle = NULL;
		LOG("Thread \"%s\" %s terminated, GLE = %d", mThreadName.c_str(), (res == WAIT_OBJECT_0) ? "" : "not", GetLastError());
		return (res == WAIT_OBJECT_0);
		
	#else  // _WIN32
	
		if (!mHasStarted)
		{
			return true;
		}
		LOG("Waiting for thread \"%s\" to terminate.", mThreadName.c_str());
		int res = pthread_join(mHandle, NULL);
		mHasStarted = false;
		LOG("Thread \"%s\" %s terminated, errno = %d", mThreadName.c_str(), (res == 0) ? "" : "not", errno);
		return (res == 0);
		
	#endif  // else _WIN32
}