MegaGlest/source/shared_lib/sources/platform/sdl/thread.cpp

950 lines
33 KiB
C++

//This file is part of Glest Shared Library (www.glest.org)
//Copyright (C) 2005 Matthias Braun <matze@braunis.de>
//You can redistribute this code and/or modify it under
//the terms of the GNU General Public License as published by the Free Software
//Foundation; either version 2 of the License, or (at your option) any later
//version.
#include "thread.h"
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <assert.h>
#include "noimpl.h"
#include <algorithm>
#include "platform_util.h"
#include "platform_common.h"
#include "base_thread.h"
#include "time.h"
using namespace std;
namespace Shared { namespace Platform {
bool Thread::enableVerboseMode = false;
Mutex Thread::mutexthreadList;
vector<Thread *> Thread::threadList;
unsigned long Thread::mainThreadId = -1;
auto_ptr<Mutex> Mutex::mutexMutexList(new Mutex(CODE_AT_LINE));
vector<Mutex *> Mutex::mutexList;
class ThreadGarbageCollector;
class Mutex;
class MutexSafeWrapper;
static auto_ptr<ThreadGarbageCollector> cleanupThread;
static auto_ptr<Mutex> cleanupThreadMutex(new Mutex(CODE_AT_LINE));
class ThreadGarbageCollector : public BaseThread
{
protected:
Mutex mutexPendingCleanupList;
vector<Thread *> pendingCleanupList;
bool cleanupPendingThreads() {
MutexSafeWrapper safeMutex(&mutexPendingCleanupList);
if(pendingCleanupList.empty() == false) {
for(unsigned int index = 0; index < pendingCleanupList.size(); ++index) {
Thread *thread = pendingCleanupList[index];
cleanupPendingThread(thread);
}
pendingCleanupList.clear();
return true;
}
return false;
}
public:
ThreadGarbageCollector() : BaseThread() {
if(Thread::getEnableVerboseMode()) printf("In %s Line: %d this: %p\n",__FUNCTION__,__LINE__,this);
uniqueID = "ThreadGarbageCollector";
removeThreadFromList();
}
virtual ~ThreadGarbageCollector() {
if(Thread::getEnableVerboseMode()) {
printf("In %s Line: %d this: %p\n",__FUNCTION__,__LINE__,this);
string stack = PlatformExceptionHandler::getStackTrace();
printf("In %s Line: %d this: %p stack: %s\n",__FUNCTION__,__LINE__,this,stack.c_str());
}
}
virtual void execute() {
if(Thread::getEnableVerboseMode()) printf("In %s Line: %d this: %p\n",__FUNCTION__,__LINE__,this);
RunningStatusSafeWrapper runningStatus(this);
for(;getQuitStatus() == false;) {
if(cleanupPendingThreads() == false) {
if(getQuitStatus() == false) {
sleep(200);
}
}
}
if(Thread::getEnableVerboseMode()) printf("In %s Line: %d this: %p\n",__FUNCTION__,__LINE__,this);
cleanupPendingThreads();
if(Thread::getEnableVerboseMode()) printf("In %s Line: %d this: %p\n",__FUNCTION__,__LINE__,this);
}
void addThread(Thread *thread) {
if(Thread::getEnableVerboseMode()) printf("In %s Line: %d this: %p\n",__FUNCTION__,__LINE__,this);
MutexSafeWrapper safeMutex(&mutexPendingCleanupList);
pendingCleanupList.push_back(thread);
safeMutex.ReleaseLock();
if(Thread::getEnableVerboseMode()) printf("In %s Line: %d this: %p\n",__FUNCTION__,__LINE__,this);
}
static void cleanupPendingThread(Thread *thread) {
if(thread != NULL) {
BaseThread *base_thread = dynamic_cast<BaseThread *>(thread);
if(base_thread != NULL &&
(base_thread->getRunningStatus() == true || base_thread->getExecutingTask() == true)) {
if(Thread::getEnableVerboseMode()) printf("!!!! cleanupPendingThread Line: %d thread = %p [%s]\n",__LINE__,thread,(base_thread != NULL ? base_thread->getUniqueID().c_str() : "n/a"));
base_thread->signalQuit();
sleep(10);
if(Thread::getEnableVerboseMode()) printf("!!!! cleanupPendingThread Line: %d thread = %p [%s]\n",__LINE__,thread,base_thread->getUniqueID().c_str());
if(base_thread->getRunningStatus() == true || base_thread->getExecutingTask() == true) {
if(Thread::getEnableVerboseMode()) printf("\n\n\n$$$$$$$$$$$$$$$$$$$$$$$$$$$ cleanupPendingThread Line: %d thread = %p [%s]\n",__LINE__,thread,base_thread->getUniqueID().c_str());
char szBuf[8096]="";
snprintf(szBuf,8095,"In [%s::%s Line: %d] cannot delete active thread: getRunningStatus(): %d getExecutingTask: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,base_thread->getRunningStatus(),base_thread->getExecutingTask());
throw megaglest_runtime_error(szBuf);
}
}
if(Thread::getEnableVerboseMode()) printf("!!!! cleanupPendingThread Line: %d thread = %p [%s]\n",__LINE__,thread,(base_thread != NULL ? base_thread->getUniqueID().c_str() : "n/a"));
delete thread;
if(Thread::getEnableVerboseMode()) printf("!!!! cleanupPendingThread Line: %d thread = NULL [%s]\n",__LINE__,(base_thread != NULL ? base_thread->getUniqueID().c_str() : "n/a"));
}
}
};
// =====================================
// Threads
// =====================================
Thread::Thread() : thread(NULL),
mutexthreadAccessor(new Mutex(CODE_AT_LINE)),
deleteAfterExecute(false), currentState(thrsNew) {
addThreadToList();
}
unsigned long Thread::getCurrentThreadId() {
return SDL_ThreadID();
}
void Thread::setMainThreadId() {
mainThreadId = getCurrentThreadId();
}
bool Thread::isCurrentThreadMainThread() {
return getCurrentThreadId() == mainThreadId;
}
void Thread::addThreadToList() {
MutexSafeWrapper safeMutex(&Thread::mutexthreadList);
Thread::threadList.push_back(this);
safeMutex.ReleaseLock();
}
void Thread::removeThreadFromList() {
MutexSafeWrapper safeMutex(&Thread::mutexthreadList);
std::vector<Thread *>::iterator iterFind = std::find(Thread::threadList.begin(),Thread::threadList.end(),this);
if(iterFind == Thread::threadList.end()) {
if(this != cleanupThread.get()) {
char szBuf[8096]="";
snprintf(szBuf,8095,"In [%s::%s Line: %d] iterFind == Thread::threadList.end()",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
throw megaglest_runtime_error(szBuf);
}
}
else {
Thread::threadList.erase(iterFind);
}
safeMutex.ReleaseLock();
}
void Thread::shutdownThreads() {
MutexSafeWrapper safeMutex(&Thread::mutexthreadList);
for(unsigned int index = 0; index < Thread::threadList.size(); ++index) {
BaseThread *thread = dynamic_cast<BaseThread *>(Thread::threadList[index]);
if(thread && thread->getRunningStatus() == true) {
thread->signalQuit();
}
}
safeMutex.ReleaseLock();
if(Thread::getEnableVerboseMode()) printf("In Thread::shutdownThreads Line: %d\n",__LINE__);
if(cleanupThread.get() != 0) {
//printf("In Thread::shutdownThreads Line: %d\n",__LINE__);
sleep(0);
cleanupThread->signalQuit();
//printf("In Thread::shutdownThreads Line: %d\n",__LINE__);
time_t elapsed = time(NULL);
for(;cleanupThread->getRunningStatus() == true &&
difftime((long int)time(NULL),elapsed) <= 5;) {
sleep(100);
}
//printf("In Thread::shutdownThreads Line: %d\n",__LINE__);
//sleep(100);
MutexSafeWrapper safeMutex(cleanupThreadMutex.get());
cleanupThread.reset(0);
//printf("In Thread::shutdownThreads Line: %d\n",__LINE__);
}
}
bool Thread::isThreadExecuteCompleteStatus() {
MutexSafeWrapper safeMutex(mutexthreadAccessor);
return (currentState == thrsExecuteComplete);
}
Thread::~Thread() {
BaseThread *base_thread = dynamic_cast<BaseThread *>(this);
string uniqueId = (base_thread ? base_thread->getUniqueID() : "new_base_thread_prev_null");
if(Thread::getEnableVerboseMode()) printf("In ~Thread Line: %d [%p] thread = %p uniqueId [%s]\n",__LINE__,this,thread,uniqueId.c_str());
MutexSafeWrapper safeMutex(mutexthreadAccessor);
if(thread != NULL) {
safeMutex.ReleaseLock();
if(isThreadExecuteCompleteStatus() == false) {
printf("**WARNING** thread destructor delayed, trying to exit...\n");
time_t elapsed = time(NULL);
for(;difftime((long int)time(NULL),elapsed) <= 5;) {
sleep(0);
if(isThreadExecuteCompleteStatus() == true) {
break;
}
}
}
if(isThreadExecuteCompleteStatus() == false) {
printf("**WARNING** thread destructor will KILL thread [%p]...\n",thread);
//SDL_KillThread(thread);
}
else {
if(Thread::getEnableVerboseMode()) printf("In ~Thread Line: %d [%p] thread = %p uniqueId [%s]\n",__LINE__,this,thread,uniqueId.c_str());
SDL_WaitThread(thread, NULL);
}
thread = NULL;
}
else {
safeMutex.ReleaseLock();
}
if(Thread::getEnableVerboseMode()) printf("In ~Thread Line: %d [%p] thread = %p\n",__LINE__,this,thread);
removeThreadFromList();
delete mutexthreadAccessor;
mutexthreadAccessor = NULL;
if(Thread::getEnableVerboseMode()) printf("In ~Thread Line: %d [%p] thread = %p\n",__LINE__,this,thread);
}
std::vector<Thread *> Thread::getThreadList() {
std::vector<Thread *> result;
MutexSafeWrapper safeMutex(&Thread::mutexthreadList);
result = threadList;
safeMutex.ReleaseLock();
return result;
}
void Thread::start() {
if(Thread::getEnableVerboseMode()) printf("In Thread::execute Line: %d\n",__LINE__);
MutexSafeWrapper safeMutex(mutexthreadAccessor);
currentState = thrsStarting;
BaseThread *base_thread = dynamic_cast<BaseThread *>(this);
if(base_thread) base_thread->setStarted(true);
string uniqueId = (base_thread ? base_thread->getUniqueID() : "new_base_thread_prev_null");
if(Thread::getEnableVerboseMode()) printf("In Thread::execute Line: %d\n",__LINE__);
thread = SDL_CreateThread(beginExecution, uniqueId.c_str(), this);
if(Thread::getEnableVerboseMode()) printf("In Thread::execute Line: %d thread = %p uniqueId [%s]\n",__LINE__,thread,uniqueId.c_str());
if(thread == NULL) {
if(Thread::getEnableVerboseMode()) printf("In Thread::execute Line: %d\n",__LINE__);
if(base_thread) base_thread->setStarted(false);
char szBuf[8096]="";
snprintf(szBuf,8095,"In [%s::%s Line: %d] thread == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
throw megaglest_runtime_error(szBuf);
}
if(Thread::getEnableVerboseMode()) printf("In Thread::execute Line: %d\n",__LINE__);
//printf("In Thread::start Line: %d [%p] thread = %p\n",__LINE__,this,thread);
}
bool Thread::threadObjectValid() {
MutexSafeWrapper safeMutex(mutexthreadAccessor);
return (thread != NULL);
}
void Thread::setPriority(Thread::Priority threadPriority) {
NOIMPL;
}
int Thread::beginExecution(void* data) {
Thread* thread = static_cast<Thread*> (data);
if(thread == NULL) {
char szBuf[8096]="";
snprintf(szBuf,8095,"In [%s::%s Line: %d] thread == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
printf("%s",szBuf);
throw megaglest_runtime_error(szBuf);
}
MutexSafeWrapper safeMutex(thread->mutexthreadAccessor);
thread->currentState = thrsExecuteStart;
safeMutex.ReleaseLock(true);
BaseThread *base_thread = dynamic_cast<BaseThread *>(thread);
//ThreadGarbageCollector *garbage_collector = dynamic_cast<ThreadGarbageCollector *>(thread);
if(Thread::getEnableVerboseMode()) printf("In Thread::execute Line: %d thread = %p base_thread = %p [%s]\n",__LINE__,thread,base_thread,(base_thread != NULL ? base_thread->getUniqueID().c_str() : "n/a"));
if(thread->threadObjectValid() == true) {
safeMutex.Lock();
thread->currentState = thrsExecuting;
safeMutex.ReleaseLock(true);
thread->execute();
safeMutex.Lock();
thread->currentState = thrsExecuted;
safeMutex.ReleaseLock(true);
}
if(Thread::getEnableVerboseMode()) printf("In Thread::execute Line: %d thread = %p base_thread = %p [%s]\n",__LINE__,thread,base_thread,(base_thread != NULL ? base_thread->getUniqueID().c_str() : "n/a"));
if(thread->threadObjectValid() == true) {
safeMutex.Lock();
thread->currentState = thrsExecuteAutoClean;
safeMutex.ReleaseLock();
thread->queueAutoCleanThread();
}
if(Thread::getEnableVerboseMode()) printf("In Thread::execute Line: %d\n",__LINE__);
MutexSafeWrapper safeMutex2(thread->mutexthreadAccessor);
if(Thread::getEnableVerboseMode()) printf("In Thread::execute Line: %d\n",__LINE__);
if(thread->threadObjectValid() == true) {
if(Thread::getEnableVerboseMode()) printf("In Thread::execute Line: %d\n",__LINE__);
thread->currentState = thrsExecuteComplete;
}
if(Thread::getEnableVerboseMode()) printf("In Thread::execute Line: %d\n",__LINE__);
safeMutex2.ReleaseLock();
if(Thread::getEnableVerboseMode()) printf("In Thread::execute Line: %d\n",__LINE__);
return 0;
}
void Thread::queueAutoCleanThread() {
if(this->deleteAfterExecute == true) {
if(Thread::getEnableVerboseMode()) printf("In Thread::shutdownThreads Line: %d\n",__LINE__);
BaseThread *base_thread = dynamic_cast<BaseThread *>(this);
//ThreadGarbageCollector *garbage_collector = dynamic_cast<ThreadGarbageCollector *>(this);
if(Thread::getEnableVerboseMode()) printf("In Thread::shutdownThreads Line: %d thread = %p base_thread = %p [%s]\n",__LINE__,this,base_thread,(base_thread != NULL ? base_thread->getUniqueID().c_str() : "n/a"));
MutexSafeWrapper safeMutex(cleanupThreadMutex.get());
if(cleanupThread.get() == NULL) {
if(Thread::getEnableVerboseMode()) printf("In Thread::shutdownThreads Line: %d\n",__LINE__);
cleanupThread.reset(new ThreadGarbageCollector());
safeMutex.ReleaseLock();
cleanupThread->start();
}
else {
safeMutex.ReleaseLock();
}
for(time_t elapsed = time(NULL);
cleanupThread->getRunningStatus() == false &&
cleanupThread->getQuitStatus() == false &&
difftime(time(NULL),elapsed) < 3;) {
sleep(0);
}
if(cleanupThread->getQuitStatus() == true) {
//ThreadGarbageCollector::cleanupPendingThread(this);
if(cleanupThread->getRunningStatus() == false) {
if(Thread::getEnableVerboseMode()) printf("MANUAL DELETE In Thread::shutdownThreads Line: %d this [%p]\n",__LINE__,this);
cleanupThread->addThread(this);
cleanupThread->start();
if(Thread::getEnableVerboseMode()) printf("MANUAL DELETE In Thread::shutdownThreads Line: %d\n",__LINE__);
return;
}
else {
if(Thread::getEnableVerboseMode()) printf("In Thread::shutdownThreads Line: %d this [%p]\n",__LINE__,this);
for(time_t elapsed = time(NULL);
cleanupThread->getRunningStatus() == true &&
cleanupThread->getQuitStatus() == true &&
difftime(time(NULL),elapsed) < 3;) {
sleep(0);
}
sleep(0);
if(Thread::getEnableVerboseMode()) printf("In Thread::shutdownThreads Line: %d this [%p]\n",__LINE__,this);
cleanupThread->addThread(this);
cleanupThread->start();
}
}
else {
if(Thread::getEnableVerboseMode()) printf("In Thread::shutdownThreads Line: %d this [%p]\n",__LINE__,this);
cleanupThread->addThread(this);
}
if(Thread::getEnableVerboseMode()) printf("In Thread::shutdownThreads Line: %d this [%p]\n",__LINE__,this);
}
}
void Thread::kill() {
MutexSafeWrapper safeMutex(mutexthreadAccessor);
//SDL_KillThread(thread);
thread = NULL;
}
void Thread::suspend() {
NOIMPL;
}
void Thread::resume() {
NOIMPL;
}
// =====================================
// Mutex
// =====================================
class SDLMutexSafeWrapper {
protected:
SDL_mutex **mutex;
bool destroyMutexInDestructor;
public:
SDLMutexSafeWrapper(SDL_mutex **mutex, bool destroyMutexInDestructor=false) {
this->mutex = mutex;
this->destroyMutexInDestructor = destroyMutexInDestructor;
Lock();
}
~SDLMutexSafeWrapper() {
bool keepMutex = (this->destroyMutexInDestructor == true && mutex != NULL && *mutex != NULL);
ReleaseLock(keepMutex);
if(this->destroyMutexInDestructor == true && mutex != NULL && *mutex != NULL) {
SDL_DestroyMutex(*mutex);
*mutex = NULL;
mutex = NULL;
}
}
void Lock() {
if(mutex != NULL && *mutex != NULL) {
SDL_LockMutex(*mutex);
}
}
void ReleaseLock(bool keepMutex=false) {
if(mutex != NULL && *mutex != NULL) {
SDL_UnlockMutex(*mutex);
if(keepMutex == false) {
mutex = NULL;
}
}
}
};
const bool debugMutexLock = false;
//const int debugMutexLockMillisecondThreshold = 2000;
Mutex::Mutex(string ownerId) {
this->isStaticMutexListMutex = false;
this->mutexAccessor = SDL_CreateMutex();
SDLMutexSafeWrapper safeMutex(&mutexAccessor);
this->maxRefCount = 0;
this->refCount = 0;
this->ownerId = ownerId;
this->lastownerId = "";
this->mutex = SDL_CreateMutex();
if(this->mutex == NULL) {
char szBuf[8096]="";
snprintf(szBuf,8095,"In [%s::%s Line: %d] mutex == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
throw megaglest_runtime_error(szBuf);
}
this->deleteownerId = "";
this->chronoPerf = NULL;
if(debugMutexLock == true) {
this->chronoPerf = new Chrono();
}
if(Mutex::mutexMutexList.get()) {
MutexSafeWrapper safeMutexX(Mutex::mutexMutexList.get());
Mutex::mutexList.push_back(this);
safeMutexX.ReleaseLock();
}
else {
this->isStaticMutexListMutex = true;
}
}
Mutex::~Mutex() {
if(Mutex::mutexMutexList.get() && isStaticMutexListMutex == false) {
MutexSafeWrapper safeMutexX(Mutex::mutexMutexList.get());
std::vector<Mutex *>::iterator iterFind = std::find(Mutex::mutexList.begin(),Mutex::mutexList.end(),this);
if(iterFind == Mutex::mutexList.end()) {
char szBuf[8096]="";
snprintf(szBuf,8095,"In [%s::%s Line: %d] iterFind == Mutex::mutexList.end()",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
throw megaglest_runtime_error(szBuf);
}
Mutex::mutexList.erase(iterFind);
safeMutexX.ReleaseLock();
}
SDLMutexSafeWrapper safeMutex(&mutexAccessor,true);
if(mutex == NULL) {
char szBuf[8096]="";
snprintf(szBuf,8095,"In [%s::%s Line: %d] mutex == NULL refCount = %d owner [%s] deleteownerId [%s]",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,refCount,ownerId.c_str(),deleteownerId.c_str());
throw megaglest_runtime_error(szBuf);
//printf("%s\n",szBuf);
}
else if(refCount >= 1) {
char szBuf[8096]="";
snprintf(szBuf,8095,"In [%s::%s Line: %d] about to destroy mutex refCount = %d owner [%s] deleteownerId [%s]",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,refCount,ownerId.c_str(),deleteownerId.c_str());
throw megaglest_runtime_error(szBuf);
}
if(debugMutexLock == true) {
delete chronoPerf;
chronoPerf = NULL;
}
if(mutex != NULL) {
deleteownerId = ownerId;
SDL_DestroyMutex(mutex);
mutex=NULL;
}
// if(maxRefCount <= 1) {
// printf("***> MUTEX candidate for removal ownerId [%s] deleteownerId [%s] lastownerId [%s]\n",ownerId.c_str(),deleteownerId.c_str(),lastownerId.c_str());
// }
}
/*
inline void Mutex::p() {
// if(mutex == NULL) {
// string stack = PlatformExceptionHandler::getStackTrace();
// char szBuf[8096]="";
// snprintf(szBuf,8095,"In [%s::%s Line: %d] mutex == NULL refCount = %d owner [%s] deleteownerId [%s] stack: %s",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,refCount,ownerId.c_str(),deleteownerId.c_str(),stack.c_str());
// throw megaglest_runtime_error(szBuf);
// }
// std::auto_ptr<Chrono> chronoLockPerf;
// if(debugMutexLock == true) {
// chronoLockPerf.reset(new Chrono());
// chronoLockPerf->start();
// }
// maxRefCount = max(maxRefCount,refCount+1);
SDL_mutexP(mutex);
refCount++;
// if(debugMutexLock == true) {
// if(chronoLockPerf->getMillis() >= debugMutexLockMillisecondThreshold) {
// printf("\n**WARNING possible mutex lock detected ms [%lld] Last ownerid: [%s]\n",(long long int)chronoLockPerf->getMillis(),lastownerId.c_str());
// }
// chronoPerf->start();
// }
}
inline void Mutex::v() {
// if(mutex == NULL) {
// char szBuf[8096]="";
// snprintf(szBuf,8095,"In [%s::%s Line: %d] mutex == NULL refCount = %d owner [%s] deleteownerId [%s]",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,refCount,ownerId.c_str(),deleteownerId.c_str());
// throw megaglest_runtime_error(szBuf);
// }
refCount--;
// if(debugMutexLock == true) {
// lastownerId = ownerId;
// if(chronoPerf->getMillis() >= debugMutexLockMillisecondThreshold) {
// printf("About to get stacktrace for stuck mutex ...\n");
// string oldLastownerId = lastownerId;
// lastownerId = PlatformExceptionHandler::getStackTrace();
//
// printf("\n**WARNING possible mutex lock (on unlock) detected ms [%lld] Last ownerid: [%s]\noldLastownerId: [%s]\n",(long long int)chronoPerf->getMillis(),lastownerId.c_str(),oldLastownerId.c_str());
// }
// }
SDL_mutexV(mutex);
}
*/
// =====================================================
// class Semaphore
// =====================================================
Semaphore::Semaphore(Uint32 initialValue) {
semaphore = SDL_CreateSemaphore(initialValue);
if(semaphore == NULL) {
char szBuf[8096]="";
snprintf(szBuf,8095,"In [%s::%s Line: %d] semaphore == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
throw megaglest_runtime_error(szBuf);
}
}
Semaphore::~Semaphore() {
if(semaphore == NULL) {
char szBuf[8096]="";
snprintf(szBuf,8095,"In [%s::%s Line: %d] semaphore == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
throw megaglest_runtime_error(szBuf);
}
SDL_DestroySemaphore(semaphore);
semaphore = NULL;
}
void Semaphore::signal() {
if(semaphore == NULL) {
char szBuf[8096]="";
snprintf(szBuf,8095,"In [%s::%s Line: %d] semaphore == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
throw megaglest_runtime_error(szBuf);
}
SDL_SemPost(semaphore);
}
int Semaphore::waitTillSignalled(int waitMilliseconds) {
if(semaphore == NULL) {
char szBuf[8096]="";
snprintf(szBuf,8095,"In [%s::%s Line: %d] semaphore == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
throw megaglest_runtime_error(szBuf);
}
int semValue = 0;
if(waitMilliseconds >= 0) {
semValue = SDL_SemWaitTimeout(semaphore,waitMilliseconds);
}
else {
semValue = SDL_SemWait(semaphore);
}
return semValue;
}
bool Semaphore::tryDecrement() {
if(semaphore == NULL) {
char szBuf[8096]="";
snprintf(szBuf,8095,"In [%s::%s Line: %d] semaphore == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
throw megaglest_runtime_error(szBuf);
}
int semValue = SDL_SemTryWait(semaphore);
return (semValue == 0);
}
uint32 Semaphore::getSemValue() {
if(semaphore == NULL) {
char szBuf[8096]="";
snprintf(szBuf,8095,"In [%s::%s Line: %d] semaphore == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
throw megaglest_runtime_error(szBuf);
}
return SDL_SemValue(semaphore);
}
void Semaphore::resetSemValue(Uint32 initialValue) {
if(semaphore == NULL) {
char szBuf[8096]="";
snprintf(szBuf,8095,"In [%s::%s Line: %d] semaphore == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
throw megaglest_runtime_error(szBuf);
}
uint32 currentValue = SDL_SemValue(semaphore);
for(unsigned int i = currentValue; i < initialValue; ++i) {
SDL_SemPost(semaphore);
}
}
// =====================================================
// class ReadWriteMutex
// =====================================================
ReadWriteMutex::ReadWriteMutex(int maxReaders) : semaphore(maxReaders) {
this->maxReadersCount = maxReaders;
}
void ReadWriteMutex::LockRead() {
semaphore.waitTillSignalled();
}
void ReadWriteMutex::UnLockRead() {
semaphore.signal();
}
void ReadWriteMutex::LockWrite() {
MutexSafeWrapper safeMutex(&mutex);
uint32 totalLocks = maxReaders();
for(unsigned int i = 0; i < totalLocks; ++i) {
semaphore.waitTillSignalled();
}
}
void ReadWriteMutex::UnLockWrite() {
uint32 totalLocks = maxReaders();
for(unsigned int i = 0; i < totalLocks; ++i) {
semaphore.signal();
}
}
int ReadWriteMutex::maxReaders() {
//return semaphore.getSemValue();
return this->maxReadersCount;
}
// =====================================================
// class Trigger
// =====================================================
Trigger::Trigger(Mutex *mutex) {
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
this->mutex = mutex;
this->trigger = SDL_CreateCond();
if(this->trigger == NULL) {
char szBuf[8096]="";
snprintf(szBuf,8095,"In [%s::%s Line: %d] trigger == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
throw megaglest_runtime_error(szBuf);
}
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
}
Trigger::~Trigger() {
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
if(trigger == NULL) {
char szBuf[8096]="";
snprintf(szBuf,8095,"In [%s::%s Line: %d] trigger == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
throw megaglest_runtime_error(szBuf);
}
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
SDL_DestroyCond(trigger);
trigger = NULL;
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
this->mutex = NULL;
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
}
void Trigger::signal(bool allThreads) {
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
if(trigger == NULL) {
char szBuf[8096]="";
snprintf(szBuf,8095,"In [%s::%s Line: %d] trigger == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
throw megaglest_runtime_error(szBuf);
}
//MutexSafeWrapper safeMutex(mutex);
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
if(allThreads == false) {
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
int result = SDL_CondSignal(trigger);
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d] result = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,result);
}
else {
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
int result = SDL_CondBroadcast(trigger);
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d] result = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,result);
}
//safeMutex.ReleaseLock();
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
}
int Trigger::waitTillSignalled(Mutex *mutex, int waitMilliseconds) {
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
if(trigger == NULL) {
char szBuf[8096]="";
snprintf(szBuf,8095,"In [%s::%s Line: %d] trigger == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
throw megaglest_runtime_error(szBuf);
}
if(mutex == NULL) {
char szBuf[8096]="";
snprintf(szBuf,8095,"In [%s::%s Line: %d] mutex == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
throw megaglest_runtime_error(szBuf);
}
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
int result = 0;
if(waitMilliseconds >= 0) {
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
result = SDL_CondWaitTimeout(trigger,mutex->getMutex(),waitMilliseconds);
}
else {
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
result = SDL_CondWait(trigger, mutex->getMutex());
}
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
return result;
}
MasterSlaveThreadController::MasterSlaveThreadController() {
std::vector<SlaveThreadControllerInterface *> empty;
init(empty);
}
MasterSlaveThreadController::MasterSlaveThreadController(std::vector<SlaveThreadControllerInterface *> &slaveThreadList) {
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d] ==========================================================\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
init(slaveThreadList);
}
void MasterSlaveThreadController::init(std::vector<SlaveThreadControllerInterface *> &newSlaveThreadList) {
this->mutex = new Mutex(CODE_AT_LINE);
this->slaveTriggerSem = new Semaphore(0);
this->slaveTriggerCounter = (int)newSlaveThreadList.size() + triggerBaseCount;
setSlaves(newSlaveThreadList);
}
void MasterSlaveThreadController::clearSlaves(bool clearListOnly) {
if(this->slaveThreadList.empty() == false) {
if(clearListOnly == false) {
for(unsigned int i = 0; i < this->slaveThreadList.size(); ++i) {
SlaveThreadControllerInterface *slave = this->slaveThreadList[i];
if(slave != NULL) {
slave->setMasterController(NULL);
}
}
}
this->slaveThreadList.clear();
}
}
MasterSlaveThreadController::~MasterSlaveThreadController() {
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
clearSlaves();
delete slaveTriggerSem;
slaveTriggerSem = NULL;
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d] mutex->getRefCount() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,mutex->getRefCount());
delete mutex;
mutex = NULL;
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
}
void MasterSlaveThreadController::setSlaves(std::vector<SlaveThreadControllerInterface *> &slaveThreadList) {
this->slaveThreadList = slaveThreadList;
if(this->slaveThreadList.empty() == false) {
for(unsigned int i = 0; i < this->slaveThreadList.size(); ++i) {
SlaveThreadControllerInterface *slave = this->slaveThreadList[i];
if(slave != NULL) {
slave->setMasterController(this);
}
}
}
}
void MasterSlaveThreadController::signalSlaves(void *userdata) {
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
slaveTriggerCounter = (int)this->slaveThreadList.size() + triggerBaseCount;
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
if(this->slaveThreadList.empty() == false) {
for(unsigned int i = 0; i < this->slaveThreadList.size(); ++i) {
SlaveThreadControllerInterface *slave = this->slaveThreadList[i];
if(slave != NULL) {
slave->signalSlave(userdata);
}
}
}
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
}
void MasterSlaveThreadController::triggerMaster(int waitMilliseconds) {
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
MutexSafeWrapper safeMutex(mutex);
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d] semVal = %u\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,slaveTriggerCounter);
//printf("In [%s::%s Line: %d] semVal = %u\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,slaveTriggerCounter);
slaveTriggerCounter--;
int newCount = slaveTriggerCounter;
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d] slaveTriggerCounter = %u\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,slaveTriggerCounter);
safeMutex.ReleaseLock();
//printf("In [%s::%s Line: %d] semVal = %u\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,slaveTriggerCounter);
if(newCount <= triggerBaseCount) {
slaveTriggerSem->signal();
}
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
}
bool MasterSlaveThreadController::waitTillSlavesTrigger(int waitMilliseconds) {
bool result = true;
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d] slaveTriggerCounter = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,slaveTriggerCounter);
if(this->slaveThreadList.empty() == false) {
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d] slaveTriggerCounter = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,slaveTriggerCounter);
int slaveResult = slaveTriggerSem->waitTillSignalled(waitMilliseconds);
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d] slaveTriggerCounter = %d slaveResult = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,slaveTriggerCounter,slaveResult);
if(slaveResult != 0) {
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
result = false;
}
else if(slaveResult == 0) {
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d] slaveTriggerCounter = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,slaveTriggerCounter);
result = true;
}
}
if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
return result;
}
}}//end namespace