tge/engine/platformX86UNIX/x86UNIXThread.cc
2017-04-17 06:17:10 -06:00

148 lines
3.7 KiB
C++
Executable File

//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "platform/platformThread.h"
#include "platformX86UNIX/platformX86UNIX.h"
#include "platform/platformSemaphore.h"
#include <SDL/SDL.h>
#include <SDL/SDL_thread.h>
#include "pthread.h"
//--------------------------------------------------------------------------
struct x86UNIXThreadData
{
ThreadRunFunction mRunFunc;
S32 mRunArg;
Thread * mThread;
void * mSemaphore;
SDL_Thread *mTheThread;
x86UNIXThreadData()
{
mRunFunc = 0;
mRunArg = 0;
mThread = 0;
mSemaphore = 0;
};
};
//--------------------------------------------------------------------------
Thread::Thread(ThreadRunFunction func, S32 arg, bool start_thread)
{
x86UNIXThreadData * threadData = new x86UNIXThreadData();
threadData->mRunFunc = func;
threadData->mRunArg = arg;
threadData->mThread = this;
threadData->mSemaphore = Semaphore::createSemaphore();
threadData->mTheThread = NULL;
mData = reinterpret_cast<void*>(threadData);
if (start_thread)
start();
}
Thread::~Thread()
{
join();
x86UNIXThreadData * threadData = reinterpret_cast<x86UNIXThreadData*>(mData);
Semaphore::destroySemaphore(threadData->mSemaphore);
delete threadData;
}
static int ThreadRunHandler(void * arg)
{
x86UNIXThreadData * threadData = reinterpret_cast<x86UNIXThreadData*>(arg);
threadData->mThread->run(threadData->mRunArg);
Semaphore::releaseSemaphore(threadData->mSemaphore);
return 0;
}
void Thread::start()
{
if(isAlive())
return;
x86UNIXThreadData *threadData = reinterpret_cast<x86UNIXThreadData*>(mData);
Semaphore::acquireSemaphore(threadData->mSemaphore);
threadData->mTheThread = SDL_CreateThread(ThreadRunHandler, mData);
}
bool Thread::join()
{
if(!isAlive())
return(false);
x86UNIXThreadData * threadData = reinterpret_cast<x86UNIXThreadData*>(mData);
//
// (SDL 1.2.7) Even after the procedure started in the thread returns, there
// still exist some resources allocated to the thread. To free these
// resources, use SDL_WaitThread to wait for the thread to finish and
// obtain the status code of the thread. If not done so, SDL_CreateThread
// will hang after about 1010 successfully created threads
// (tested on GNU/Linux).
//
SDL_WaitThread(threadData->mTheThread, NULL);
threadData->mTheThread = NULL;
return (Semaphore::acquireSemaphore(threadData->mSemaphore, true));
}
void Thread::run(S32 arg)
{
x86UNIXThreadData * threadData = reinterpret_cast<x86UNIXThreadData*>(mData);
if(threadData->mRunFunc)
threadData->mRunFunc(arg);
}
bool Thread::isAlive()
{
x86UNIXThreadData * threadData = reinterpret_cast<x86UNIXThreadData*>(mData);
if (threadData->mTheThread)
{
bool signal = Semaphore::acquireSemaphore(threadData->mSemaphore, false);
if (signal)
Semaphore::releaseSemaphore(threadData->mSemaphore);
return (!signal);
}
return false;
}
U32 Thread::getCurrentThreadId()
{
return (U32)SDL_ThreadID();
}
class PlatformThreadStorage
{
public:
pthread_key_t mThreadKey;
};
ThreadStorage::ThreadStorage()
{
mThreadStorage = (PlatformThreadStorage *) mStorage;
constructInPlace(mThreadStorage);
pthread_key_create(&mThreadStorage->mThreadKey, NULL);
}
ThreadStorage::~ThreadStorage()
{
pthread_key_delete(mThreadStorage->mThreadKey);
}
void *ThreadStorage::get()
{
return pthread_getspecific(mThreadStorage->mThreadKey);
}
void ThreadStorage::set(void *value)
{
pthread_setspecific(mThreadStorage->mThreadKey, value);
}