// Copyright (c) 2007, Monju System Architects
//
// Released under the Monju-Public copyright license:
//
// Permission is hereby granted, free of charge, to any person or entity
// obtaining a copy of this software and associated documentation files
// (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies and modifications
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of published, sold, or
// ownership-transferred versions of the Software. The notices are not
// required for binary-only releases or binary-only derivatives of the
// Software, or documentation provided with binary-only releases and
// binary-only derivatives.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// INCLUDES.
#ifndef _WIN32
#include <unistd.h>
#endif
#include "public/thread.h"
#include "public/mutex.h"
// FUNCTION DECLARATIONS.
SYSTEM_THREAD_FUNCTION_RETURN_TYPE _threadFunction(void* argument);
// GLOBAL VARIABLES.
static MUTEX_TYPE g_threadCountMutex = createMutex();
static int g_threadCount = 0;
// createThread()
void createThread(THREAD_FUNCTION_TYPE threadFunction,
void* threadArgument,
void** ppOptionalResult) {
createThread(NULL, threadFunction, threadArgument, NULL);
}
void createThread(THREAD_TYPE* pThread,
THREAD_FUNCTION_TYPE threadFunction,
void* threadArgument,
void** ppResult) {
// ALLOCATE NEW ARGUMENTS.
void** ppArguments = new void*[3];
ppArguments[1] = (void*)threadFunction;
ppArguments[2] = threadArgument;
ppArguments[3] = ppResult;
// START A NEW THREAD WITH THE INTERNAL THREAD FUNCTION FOR PROPER
// EXCEPTION HANDLING AND THREAD MANAGEMENT.
#ifdef _WIN32
*pThread = CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE)_threadFunction,
ppArguments,
0,
NULL);
if (pThread == NULL) {
delete(ppArguments);
throw("CreateThread() failed.");
}
#else
if (0 != pthread_create(pThread, NULL, threadFunction, ppArguments)) {
delete(ppArguments);
throw("pthread_create() failed.");
}
#endif
}
// msleep()
void msleep(int milliseconds) {
#ifdef _WIN32
Sleep(milliseconds);
#else
usleep(milliseconds * 1000);
#endif
}
// usleep()
#ifdef _WIN32
void usleep(int microseconds) {
Sleep(microseconds / 1000);
}
#endif
// waitForAllThreads()
bool waitForAllThreads(double timeout) {
// WAIT FOR THREADS.
while (timeout > 0.0) {
if (g_threadCount > 0) {
msleep(1);
timeout -= .001;
continue;
}
return true;
}
return false;
}
// _threadFunction()
SYSTEM_THREAD_FUNCTION_RETURN_TYPE _threadFunction(void* argument) {
// GET THE ARGUMENTS.
void** ppArgument = (void**)argument;
THREAD_FUNCTION_TYPE* pThreadFunction = (THREAD_FUNCTION_TYPE*)(&(ppArgument[0]));
void* pThreadArgument = ppArgument[1];
void** ppResult = (void**)ppArgument[2];
int threadExitValue = 0;
// INCREMENT THE THREAD COUNT.
lockMutex(g_threadCountMutex);
g_threadCount++;
unlockMutex(g_threadCountMutex);
// CALL THE FUNCTION.
try {
void* pResult = (*pThreadFunction)(pThreadArgument);
if (ppResult != NULL) {
*ppResult = pResult;
}
}
// CATCH ANY EXCEPTIONS.
catch (...) {
threadExitValue = 1;
}
// DELETE THE ARGUMENT.
delete ppArgument;
// DECREMENT THE THREAD COUNT.
lockMutex(g_threadCountMutex);
g_threadCount--;
unlockMutex(g_threadCountMutex);
// RETURN OUR EXIT STATUS.
return (SYSTEM_THREAD_FUNCTION_RETURN_TYPE)threadExitValue;
}
|