1 //This file is part of Glest Shared Library (www.glest.org)
2 //Copyright (C) 2005 Matthias Braun <matze@braunis.de>
3 
4 //You can redistribute this code and/or modify it under
5 //the terms of the GNU General Public License as published by the Free Software
6 //Foundation; either version 2 of the License, or (at your option) any later
7 //version.
8 
9 #include "thread.h"
10 
11 #include <iostream>
12 #include <sstream>
13 #include <stdexcept>
14 #include <assert.h>
15 #include "noimpl.h"
16 #include <algorithm>
17 #include "platform_util.h"
18 #include "platform_common.h"
19 #include "base_thread.h"
20 #include "time.h"
21 
22 using namespace std;
23 
24 namespace Shared { namespace Platform {
25 
26 bool Thread::enableVerboseMode = false;
27 Mutex Thread::mutexthreadList;
28 vector<Thread *> Thread::threadList;
29 unsigned long Thread::mainThreadId = -1;
30 
31 auto_ptr<Mutex> Mutex::mutexMutexList(new Mutex(CODE_AT_LINE));
32 vector<Mutex *> Mutex::mutexList;
33 
34 class ThreadGarbageCollector;
35 class Mutex;
36 class MutexSafeWrapper;
37 
38 static auto_ptr<ThreadGarbageCollector> cleanupThread;
39 static auto_ptr<Mutex> cleanupThreadMutex(new Mutex(CODE_AT_LINE));
40 
41 class ThreadGarbageCollector : public BaseThread
42 {
43 protected:
44 	Mutex mutexPendingCleanupList;
45 	vector<Thread *> pendingCleanupList;
46 
cleanupPendingThreads()47 	bool cleanupPendingThreads() {
48 		MutexSafeWrapper safeMutex(&mutexPendingCleanupList);
49 		if(pendingCleanupList.empty() == false) {
50 			for(unsigned int index = 0; index < pendingCleanupList.size(); ++index) {
51 				Thread *thread = pendingCleanupList[index];
52 				cleanupPendingThread(thread);
53 			}
54 			pendingCleanupList.clear();
55 			return true;
56 		}
57 		return false;
58 	}
59 
60 public:
ThreadGarbageCollector()61 	ThreadGarbageCollector() : BaseThread() {
62 		if(Thread::getEnableVerboseMode()) printf("In %s Line: %d this: %p\n",__FUNCTION__,__LINE__,this);
63 		uniqueID = "ThreadGarbageCollector";
64 		removeThreadFromList();
65 	}
~ThreadGarbageCollector()66 	virtual ~ThreadGarbageCollector() {
67 		if(Thread::getEnableVerboseMode()) {
68 			printf("In %s Line: %d this: %p\n",__FUNCTION__,__LINE__,this);
69 			string stack = PlatformExceptionHandler::getStackTrace();
70 			printf("In %s Line: %d this: %p stack: %s\n",__FUNCTION__,__LINE__,this,stack.c_str());
71 		}
72 	}
execute()73     virtual void execute() {
74     	if(Thread::getEnableVerboseMode()) printf("In %s Line: %d this: %p\n",__FUNCTION__,__LINE__,this);
75 
76         RunningStatusSafeWrapper runningStatus(this);
77         for(;getQuitStatus() == false;) {
78 			if(cleanupPendingThreads() == false) {
79 				if(getQuitStatus() == false) {
80 					sleep(200);
81 				}
82 			}
83 		}
84 
85         if(Thread::getEnableVerboseMode()) printf("In %s Line: %d this: %p\n",__FUNCTION__,__LINE__,this);
86 
87 		cleanupPendingThreads();
88 
89 		if(Thread::getEnableVerboseMode()) printf("In %s Line: %d this: %p\n",__FUNCTION__,__LINE__,this);
90 	}
addThread(Thread * thread)91     void addThread(Thread *thread) {
92     	if(Thread::getEnableVerboseMode()) printf("In %s Line: %d this: %p\n",__FUNCTION__,__LINE__,this);
93 
94 		MutexSafeWrapper safeMutex(&mutexPendingCleanupList);
95 		pendingCleanupList.push_back(thread);
96 		safeMutex.ReleaseLock();
97 
98 		if(Thread::getEnableVerboseMode()) printf("In %s Line: %d this: %p\n",__FUNCTION__,__LINE__,this);
99 	}
100 
cleanupPendingThread(Thread * thread)101 	static void cleanupPendingThread(Thread *thread) {
102 		if(thread != NULL) {
103 			BaseThread *base_thread = dynamic_cast<BaseThread *>(thread);
104 			if(base_thread != NULL &&
105 					(base_thread->getRunningStatus() == true || base_thread->getExecutingTask() == true)) {
106 				if(Thread::getEnableVerboseMode()) printf("!!!! cleanupPendingThread Line: %d thread = %p [%s]\n",__LINE__,thread,(base_thread != NULL ? base_thread->getUniqueID().c_str() : "n/a"));
107 
108 				base_thread->signalQuit();
109 				sleep(10);
110 
111 				if(Thread::getEnableVerboseMode()) printf("!!!! cleanupPendingThread Line: %d thread = %p [%s]\n",__LINE__,thread,base_thread->getUniqueID().c_str());
112 
113 				if(base_thread->getRunningStatus() == true || base_thread->getExecutingTask() == true) {
114 
115 					if(Thread::getEnableVerboseMode()) printf("\n\n\n$$$$$$$$$$$$$$$$$$$$$$$$$$$ cleanupPendingThread Line: %d thread = %p [%s]\n",__LINE__,thread,base_thread->getUniqueID().c_str());
116 
117 					char szBuf[8096]="";
118 					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());
119 					throw megaglest_runtime_error(szBuf);
120 				}
121 			}
122 
123 			if(Thread::getEnableVerboseMode()) printf("!!!! cleanupPendingThread Line: %d thread = %p [%s]\n",__LINE__,thread,(base_thread != NULL ? base_thread->getUniqueID().c_str() : "n/a"));
124 
125 			delete thread;
126 
127 			if(Thread::getEnableVerboseMode()) printf("!!!! cleanupPendingThread Line: %d thread = NULL [%s]\n",__LINE__,(base_thread != NULL ? base_thread->getUniqueID().c_str() : "n/a"));
128 		}
129 	}
130 
131 };
132 
133 // =====================================
134 //          Threads
135 // =====================================
Thread()136 Thread::Thread() : thread(NULL),
137 		mutexthreadAccessor(new Mutex(CODE_AT_LINE)),
138 		deleteAfterExecute(false), currentState(thrsNew) {
139 	addThreadToList();
140 }
141 
getCurrentThreadId()142 unsigned long Thread::getCurrentThreadId() {
143 	return SDL_ThreadID();
144 }
setMainThreadId()145 void Thread::setMainThreadId() {
146 	mainThreadId = getCurrentThreadId();
147 }
isCurrentThreadMainThread()148 bool Thread::isCurrentThreadMainThread() {
149 	return getCurrentThreadId() == mainThreadId;
150 }
151 
addThreadToList()152 void Thread::addThreadToList() {
153 	MutexSafeWrapper safeMutex(&Thread::mutexthreadList);
154 	Thread::threadList.push_back(this);
155 	safeMutex.ReleaseLock();
156 }
removeThreadFromList()157 void Thread::removeThreadFromList() {
158 	MutexSafeWrapper safeMutex(&Thread::mutexthreadList);
159 	if(Thread::threadList.empty() == false) {
160 		std::vector<Thread *>::iterator iterFind = std::find(Thread::threadList.begin(),Thread::threadList.end(),this);
161 		if(iterFind == Thread::threadList.end()) {
162 			if(this != cleanupThread.get()) {
163 				char szBuf[8096]="";
164 				snprintf(szBuf,8095,"In [%s::%s Line: %d] iterFind == Thread::threadList.end() Thread::threadList.size() = %ld",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,Thread::threadList.size());
165 				throw megaglest_runtime_error(szBuf);
166 			}
167 		}
168 		else {
169 			Thread::threadList.erase(iterFind);
170 		}
171 	}
172 	safeMutex.ReleaseLock();
173 }
174 
shutdownThreads()175 void Thread::shutdownThreads() {
176 	MutexSafeWrapper safeMutex(&Thread::mutexthreadList);
177 	for(unsigned int index = 0; index < Thread::threadList.size(); ++index) {
178 		BaseThread *thread = dynamic_cast<BaseThread *>(Thread::threadList[index]);
179 		if(thread && thread->getRunningStatus() == true) {
180 			thread->signalQuit();
181 		}
182 	}
183 	safeMutex.ReleaseLock();
184 
185 	if(Thread::getEnableVerboseMode()) printf("In Thread::shutdownThreads Line: %d\n",__LINE__);
186 	if(cleanupThread.get() != 0) {
187 		//printf("In Thread::shutdownThreads Line: %d\n",__LINE__);
188 		sleep(0);
189 		cleanupThread->signalQuit();
190 
191 		//printf("In Thread::shutdownThreads Line: %d\n",__LINE__);
192 		time_t elapsed = time(NULL);
193 		for(;cleanupThread->getRunningStatus() == true &&
194     		difftime((long int)time(NULL),elapsed) <= 5;) {
195 			sleep(100);
196 		}
197 		//printf("In Thread::shutdownThreads Line: %d\n",__LINE__);
198 		//sleep(100);
199 
200 		MutexSafeWrapper safeMutex(cleanupThreadMutex.get());
201 		cleanupThread.reset(0);
202 		//printf("In Thread::shutdownThreads Line: %d\n",__LINE__);
203 	}
204 }
205 
isThreadExecuteCompleteStatus()206 bool Thread::isThreadExecuteCompleteStatus() {
207 	MutexSafeWrapper safeMutex(mutexthreadAccessor);
208 	return (currentState == thrsExecuteComplete);
209 }
~Thread()210 Thread::~Thread() {
211 	BaseThread *base_thread = dynamic_cast<BaseThread *>(this);
212 	string uniqueId =  (base_thread ? base_thread->getUniqueID() : "new_base_thread_prev_null");
213 	if(Thread::getEnableVerboseMode()) printf("In ~Thread Line: %d [%p] thread = %p uniqueId [%s]\n",__LINE__,this,thread,uniqueId.c_str());
214 
215 	MutexSafeWrapper safeMutex(mutexthreadAccessor);
216 	if(thread != NULL) {
217 
218 		safeMutex.ReleaseLock();
219 
220 		if(isThreadExecuteCompleteStatus() == false) {
221 			printf("**WARNING** thread destructor delayed, trying to exit...\n");
222 
223 			time_t elapsed = time(NULL);
224 			for(;difftime((long int)time(NULL),elapsed) <= 5;) {
225 				sleep(0);
226 
227 				if(isThreadExecuteCompleteStatus() == true) {
228 					break;
229 				}
230 			}
231 		}
232 
233 		if(isThreadExecuteCompleteStatus() == false) {
234 			printf("**WARNING** thread destructor will KILL thread [%p]...\n",thread);
235 			//SDL_KillThread(thread);
236 		}
237 		else {
238 			if(Thread::getEnableVerboseMode()) printf("In ~Thread Line: %d [%p] thread = %p uniqueId [%s]\n",__LINE__,this,thread,uniqueId.c_str());
239 			SDL_WaitThread(thread, NULL);
240 		}
241 		thread = NULL;
242 	}
243 	else {
244 		safeMutex.ReleaseLock();
245 	}
246 
247 	if(Thread::getEnableVerboseMode()) printf("In ~Thread Line: %d [%p] thread = %p\n",__LINE__,this,thread);
248 
249 	removeThreadFromList();
250 
251 	delete mutexthreadAccessor;
252 	mutexthreadAccessor = NULL;
253 	if(Thread::getEnableVerboseMode()) printf("In ~Thread Line: %d [%p] thread = %p\n",__LINE__,this,thread);
254 }
255 
getThreadList()256 std::vector<Thread *> Thread::getThreadList() {
257 	std::vector<Thread *> result;
258 	MutexSafeWrapper safeMutex(&Thread::mutexthreadList);
259 	result = threadList;
260 	safeMutex.ReleaseLock();
261 	return result;
262 }
263 
start()264 void Thread::start() {
265 	if(Thread::getEnableVerboseMode()) printf("In Thread::execute Line: %d\n",__LINE__);
266 
267 	MutexSafeWrapper safeMutex(mutexthreadAccessor);
268 	currentState = thrsStarting;
269 
270 	BaseThread *base_thread = dynamic_cast<BaseThread *>(this);
271 	if(base_thread) base_thread->setStarted(true);
272 	string uniqueId =  (base_thread ? base_thread->getUniqueID() : "new_base_thread_prev_null");
273 
274 	if(Thread::getEnableVerboseMode()) printf("In Thread::execute Line: %d\n",__LINE__);
275 
276 	thread = SDL_CreateThread(beginExecution, uniqueId.c_str(), this);
277 
278 	if(Thread::getEnableVerboseMode()) printf("In Thread::execute Line: %d thread = %p uniqueId [%s]\n",__LINE__,thread,uniqueId.c_str());
279 
280 	if(thread == NULL) {
281 		if(Thread::getEnableVerboseMode()) printf("In Thread::execute Line: %d\n",__LINE__);
282 
283 		if(base_thread) base_thread->setStarted(false);
284 
285 		char szBuf[8096]="";
286 		snprintf(szBuf,8095,"In [%s::%s Line: %d] thread == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
287 		throw megaglest_runtime_error(szBuf);
288 	}
289 
290 	if(Thread::getEnableVerboseMode()) printf("In Thread::execute Line: %d\n",__LINE__);
291 	//printf("In Thread::start Line: %d [%p] thread = %p\n",__LINE__,this,thread);
292 }
293 
threadObjectValid()294 bool Thread::threadObjectValid() {
295 	MutexSafeWrapper safeMutex(mutexthreadAccessor);
296 	return (thread != NULL);
297 }
298 
setPriority(Thread::Priority threadPriority)299 void Thread::setPriority(Thread::Priority threadPriority) {
300 	NOIMPL;
301 }
302 
beginExecution(void * data)303 int Thread::beginExecution(void* data) {
304 	Thread* thread = static_cast<Thread*> (data);
305 	if(thread == NULL) {
306 		char szBuf[8096]="";
307 		snprintf(szBuf,8095,"In [%s::%s Line: %d] thread == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
308 		printf("%s",szBuf);
309 
310 		throw megaglest_runtime_error(szBuf);
311 	}
312 
313 	MutexSafeWrapper safeMutex(thread->mutexthreadAccessor);
314 	thread->currentState = thrsExecuteStart;
315 	safeMutex.ReleaseLock(true);
316 
317 	BaseThread *base_thread = dynamic_cast<BaseThread *>(thread);
318 	//ThreadGarbageCollector *garbage_collector = dynamic_cast<ThreadGarbageCollector *>(thread);
319 	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"));
320 
321 	if(thread->threadObjectValid() == true) {
322 		safeMutex.Lock();
323 		thread->currentState = thrsExecuting;
324 		safeMutex.ReleaseLock(true);
325 
326 		thread->execute();
327 
328 		safeMutex.Lock();
329 		thread->currentState = thrsExecuted;
330 		safeMutex.ReleaseLock(true);
331 	}
332 
333 	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"));
334 
335 	if(thread->threadObjectValid() == true) {
336 		safeMutex.Lock();
337 		thread->currentState = thrsExecuteAutoClean;
338 		safeMutex.ReleaseLock();
339 		thread->queueAutoCleanThread();
340 	}
341 
342 	if(Thread::getEnableVerboseMode()) printf("In Thread::execute Line: %d\n",__LINE__);
343 	MutexSafeWrapper safeMutex2(thread->mutexthreadAccessor);
344 
345 	if(Thread::getEnableVerboseMode()) printf("In Thread::execute Line: %d\n",__LINE__);
346 	if(thread->threadObjectValid() == true) {
347 		if(Thread::getEnableVerboseMode()) printf("In Thread::execute Line: %d\n",__LINE__);
348 		thread->currentState = thrsExecuteComplete;
349 	}
350 	if(Thread::getEnableVerboseMode()) printf("In Thread::execute Line: %d\n",__LINE__);
351 	safeMutex2.ReleaseLock();
352 	if(Thread::getEnableVerboseMode()) printf("In Thread::execute Line: %d\n",__LINE__);
353 
354 	return 0;
355 }
356 
queueAutoCleanThread()357 void Thread::queueAutoCleanThread() {
358 	if(this->deleteAfterExecute == true) {
359 		if(Thread::getEnableVerboseMode()) printf("In Thread::shutdownThreads Line: %d\n",__LINE__);
360 
361 		BaseThread *base_thread = dynamic_cast<BaseThread *>(this);
362 		//ThreadGarbageCollector *garbage_collector = dynamic_cast<ThreadGarbageCollector *>(this);
363 		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"));
364 
365 		MutexSafeWrapper safeMutex(cleanupThreadMutex.get());
366 		if(cleanupThread.get() == NULL) {
367 			if(Thread::getEnableVerboseMode()) printf("In Thread::shutdownThreads Line: %d\n",__LINE__);
368 			cleanupThread.reset(new ThreadGarbageCollector());
369 
370 			safeMutex.ReleaseLock();
371 			cleanupThread->start();
372 		}
373 		else {
374 			safeMutex.ReleaseLock();
375 		}
376 		for(time_t elapsed = time(NULL);
377 				cleanupThread->getRunningStatus() == false &&
378 					cleanupThread->getQuitStatus() == false &&
379 						difftime(time(NULL),elapsed) < 3;) {
380 			sleep(0);
381 		}
382 
383 		if(cleanupThread->getQuitStatus() == true) {
384 			//ThreadGarbageCollector::cleanupPendingThread(this);
385 			if(cleanupThread->getRunningStatus() == false) {
386 				if(Thread::getEnableVerboseMode()) printf("MANUAL DELETE In Thread::shutdownThreads Line: %d this [%p]\n",__LINE__,this);
387 
388 				cleanupThread->addThread(this);
389 				cleanupThread->start();
390 
391 				if(Thread::getEnableVerboseMode()) printf("MANUAL DELETE In Thread::shutdownThreads Line: %d\n",__LINE__);
392 				return;
393 			}
394 			else {
395 				if(Thread::getEnableVerboseMode()) printf("In Thread::shutdownThreads Line: %d this [%p]\n",__LINE__,this);
396 
397 				for(time_t elapsed = time(NULL);
398 						cleanupThread->getRunningStatus() == true &&
399 							cleanupThread->getQuitStatus() == true &&
400 								difftime(time(NULL),elapsed) < 3;) {
401 					sleep(0);
402 				}
403 				sleep(0);
404 
405 				if(Thread::getEnableVerboseMode()) printf("In Thread::shutdownThreads Line: %d this [%p]\n",__LINE__,this);
406 
407 				cleanupThread->addThread(this);
408 				cleanupThread->start();
409 			}
410 		}
411 		else {
412 			if(Thread::getEnableVerboseMode()) printf("In Thread::shutdownThreads Line: %d this [%p]\n",__LINE__,this);
413 			cleanupThread->addThread(this);
414 		}
415 		if(Thread::getEnableVerboseMode()) printf("In Thread::shutdownThreads Line: %d this [%p]\n",__LINE__,this);
416 	}
417 }
418 
kill()419 void Thread::kill() {
420 	MutexSafeWrapper safeMutex(mutexthreadAccessor);
421 	//SDL_KillThread(thread);
422 	thread = NULL;
423 }
424 
suspend()425 void Thread::suspend() {
426 	NOIMPL;
427 }
428 
resume()429 void Thread::resume() {
430 	NOIMPL;
431 }
432 
433 // =====================================
434 //          Mutex
435 // =====================================
436 
437 class SDLMutexSafeWrapper {
438 protected:
439 	SDL_mutex **mutex;
440 	bool destroyMutexInDestructor;
441 
442 public:
443 
SDLMutexSafeWrapper(SDL_mutex ** mutex,bool destroyMutexInDestructor=false)444 	SDLMutexSafeWrapper(SDL_mutex **mutex, bool destroyMutexInDestructor=false) {
445 		this->mutex = mutex;
446 		this->destroyMutexInDestructor = destroyMutexInDestructor;
447 		Lock();
448 	}
~SDLMutexSafeWrapper()449 	~SDLMutexSafeWrapper() {
450 		bool keepMutex = (this->destroyMutexInDestructor == true && mutex != NULL && *mutex != NULL);
451 		ReleaseLock(keepMutex);
452 
453 		if(this->destroyMutexInDestructor == true && mutex != NULL && *mutex != NULL) {
454 			SDL_DestroyMutex(*mutex);
455 			*mutex = NULL;
456 			mutex = NULL;
457 		}
458 	}
459 
Lock()460 	void Lock() {
461 		if(mutex != NULL && *mutex != NULL) {
462 			SDL_LockMutex(*mutex);
463 		}
464 	}
ReleaseLock(bool keepMutex=false)465 	void ReleaseLock(bool keepMutex=false) {
466 		if(mutex != NULL && *mutex != NULL) {
467 			SDL_UnlockMutex(*mutex);
468 
469 			if(keepMutex == false) {
470 				mutex = NULL;
471 			}
472 		}
473 	}
474 };
475 
476 const bool debugMutexLock 						= false;
477 //const int debugMutexLockMillisecondThreshold 	= 2000;
478 
Mutex(string ownerId)479 Mutex::Mutex(string ownerId) {
480 	this->isStaticMutexListMutex 	= false;
481 	this->mutexAccessor 			= SDL_CreateMutex();
482 
483 	SDLMutexSafeWrapper safeMutex(&mutexAccessor);
484 
485 	this->maxRefCount 				= 0;
486 	this->refCount					= 0;
487     this->ownerId 					= ownerId;
488     this->lastownerId 				= "";
489     this->mutex 					= SDL_CreateMutex();
490 	if(this->mutex == NULL) {
491 		char szBuf[8096]="";
492 		snprintf(szBuf,8095,"In [%s::%s Line: %d] mutex == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
493 		throw megaglest_runtime_error(szBuf);
494 	}
495 	this->deleteownerId 			= "";
496 
497 	this->chronoPerf 				= NULL;
498 	if(debugMutexLock == true) {
499 		this->chronoPerf = new Chrono();
500 	}
501 
502 	if(Mutex::mutexMutexList.get()) {
503 		MutexSafeWrapper safeMutexX(Mutex::mutexMutexList.get());
504 		Mutex::mutexList.push_back(this);
505 		safeMutexX.ReleaseLock();
506 	}
507 	else {
508 		this->isStaticMutexListMutex = true;
509 	}
510 }
511 
~Mutex()512 Mutex::~Mutex() {
513 	if(Mutex::mutexMutexList.get() && isStaticMutexListMutex == false) {
514 		MutexSafeWrapper safeMutexX(Mutex::mutexMutexList.get());
515 		std::vector<Mutex *>::iterator iterFind = std::find(Mutex::mutexList.begin(),Mutex::mutexList.end(),this);
516 		if(iterFind == Mutex::mutexList.end()) {
517 			char szBuf[8096]="";
518 			snprintf(szBuf,8095,"In [%s::%s Line: %d] iterFind == Mutex::mutexList.end()",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
519 			throw megaglest_runtime_error(szBuf);
520 		}
521 		Mutex::mutexList.erase(iterFind);
522 		safeMutexX.ReleaseLock();
523 	}
524 
525 	SDLMutexSafeWrapper safeMutex(&mutexAccessor,true);
526 	if(mutex == NULL) {
527 		char szBuf[8096]="";
528 		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());
529 		throw megaglest_runtime_error(szBuf);
530 		//printf("%s\n",szBuf);
531 	}
532 	else if(refCount >= 1) {
533 		char szBuf[8096]="";
534 		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());
535 		throw megaglest_runtime_error(szBuf);
536 	}
537 
538 	if(debugMutexLock == true) {
539 		delete chronoPerf;
540 		chronoPerf = NULL;
541 	}
542 
543 	if(mutex != NULL) {
544 		deleteownerId = ownerId;
545 		SDL_DestroyMutex(mutex);
546 		mutex=NULL;
547 	}
548 
549 //	if(maxRefCount <= 1) {
550 //		printf("***> MUTEX candidate for removal ownerId [%s] deleteownerId [%s] lastownerId [%s]\n",ownerId.c_str(),deleteownerId.c_str(),lastownerId.c_str());
551 //	}
552 }
553 
554 /*
555 inline void Mutex::p() {
556 //	if(mutex == NULL) {
557 //		string stack = PlatformExceptionHandler::getStackTrace();
558 //		char szBuf[8096]="";
559 //		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());
560 //		throw megaglest_runtime_error(szBuf);
561 //	}
562 //	std::auto_ptr<Chrono> chronoLockPerf;
563 //	if(debugMutexLock == true) {
564 //		chronoLockPerf.reset(new Chrono());
565 //		chronoLockPerf->start();
566 //	}
567 
568 //	maxRefCount = max(maxRefCount,refCount+1);
569 	SDL_mutexP(mutex);
570 	refCount++;
571 
572 //	if(debugMutexLock == true) {
573 //		if(chronoLockPerf->getMillis() >= debugMutexLockMillisecondThreshold) {
574 //			printf("\n**WARNING possible mutex lock detected ms [%lld] Last ownerid: [%s]\n",(long long int)chronoLockPerf->getMillis(),lastownerId.c_str());
575 //		}
576 //		chronoPerf->start();
577 //	}
578 }
579 
580 inline void Mutex::v() {
581 //	if(mutex == NULL) {
582 //		char szBuf[8096]="";
583 //		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());
584 //		throw megaglest_runtime_error(szBuf);
585 //	}
586 	refCount--;
587 
588 //	if(debugMutexLock == true) {
589 //		lastownerId = ownerId;
590 //		if(chronoPerf->getMillis() >= debugMutexLockMillisecondThreshold) {
591 //			printf("About to get stacktrace for stuck mutex ...\n");
592 //			string oldLastownerId = lastownerId;
593 //			lastownerId = PlatformExceptionHandler::getStackTrace();
594 //
595 //			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());
596 //		}
597 //	}
598 	SDL_mutexV(mutex);
599 }
600 */
601 
602 // =====================================================
603 //	class Semaphore
604 // =====================================================
605 
Semaphore(Uint32 initialValue)606 Semaphore::Semaphore(Uint32 initialValue) {
607 	semaphore = SDL_CreateSemaphore(initialValue);
608 	if(semaphore == NULL) {
609 		char szBuf[8096]="";
610 		snprintf(szBuf,8095,"In [%s::%s Line: %d] semaphore == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
611 		throw megaglest_runtime_error(szBuf);
612 	}
613 }
614 
~Semaphore()615 Semaphore::~Semaphore() {
616 	if(semaphore == NULL) {
617 		char szBuf[8096]="";
618 		snprintf(szBuf,8095,"In [%s::%s Line: %d] semaphore == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
619 		throw megaglest_runtime_error(szBuf);
620 	}
621 	SDL_DestroySemaphore(semaphore);
622 	semaphore = NULL;
623 }
624 
signal()625 void Semaphore::signal() {
626 	if(semaphore == NULL) {
627 		char szBuf[8096]="";
628 		snprintf(szBuf,8095,"In [%s::%s Line: %d] semaphore == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
629 		throw megaglest_runtime_error(szBuf);
630 	}
631 	SDL_SemPost(semaphore);
632 }
633 
waitTillSignalled(int waitMilliseconds)634 int Semaphore::waitTillSignalled(int waitMilliseconds) {
635 	if(semaphore == NULL) {
636 		char szBuf[8096]="";
637 		snprintf(szBuf,8095,"In [%s::%s Line: %d] semaphore == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
638 		throw megaglest_runtime_error(szBuf);
639 	}
640 	int semValue = 0;
641 	if(waitMilliseconds >= 0) {
642 		semValue = SDL_SemWaitTimeout(semaphore,waitMilliseconds);
643 	}
644 	else {
645 		semValue = SDL_SemWait(semaphore);
646 	}
647 	return semValue;
648 }
649 
tryDecrement()650 bool Semaphore::tryDecrement() {
651 	if(semaphore == NULL) {
652 		char szBuf[8096]="";
653 		snprintf(szBuf,8095,"In [%s::%s Line: %d] semaphore == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
654 		throw megaglest_runtime_error(szBuf);
655 	}
656 	int semValue = SDL_SemTryWait(semaphore);
657 	return (semValue == 0);
658 }
659 
getSemValue()660 uint32 Semaphore::getSemValue() {
661 	if(semaphore == NULL) {
662 		char szBuf[8096]="";
663 		snprintf(szBuf,8095,"In [%s::%s Line: %d] semaphore == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
664 		throw megaglest_runtime_error(szBuf);
665 	}
666 
667 	return SDL_SemValue(semaphore);
668 }
669 
resetSemValue(Uint32 initialValue)670 void Semaphore::resetSemValue(Uint32 initialValue) {
671 	if(semaphore == NULL) {
672 		char szBuf[8096]="";
673 		snprintf(szBuf,8095,"In [%s::%s Line: %d] semaphore == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
674 		throw megaglest_runtime_error(szBuf);
675 	}
676 
677 	uint32 currentValue = SDL_SemValue(semaphore);
678 	for(unsigned int i = currentValue; i < initialValue; ++i) {
679 		SDL_SemPost(semaphore);
680 	}
681 }
682 
683 // =====================================================
684 //	class ReadWriteMutex
685 // =====================================================
686 
ReadWriteMutex(int maxReaders)687 ReadWriteMutex::ReadWriteMutex(int maxReaders) : semaphore(maxReaders) {
688 	this->maxReadersCount = maxReaders;
689 }
690 
LockRead()691 void ReadWriteMutex::LockRead() {
692 	semaphore.waitTillSignalled();
693 }
UnLockRead()694 void ReadWriteMutex::UnLockRead() {
695 	semaphore.signal();
696 }
LockWrite()697 void ReadWriteMutex::LockWrite() {
698 	MutexSafeWrapper safeMutex(&mutex);
699 	uint32 totalLocks = maxReaders();
700 	for(unsigned int i = 0; i < totalLocks; ++i) {
701 		semaphore.waitTillSignalled();
702 	}
703 }
UnLockWrite()704 void ReadWriteMutex::UnLockWrite() {
705 	uint32 totalLocks = maxReaders();
706 	for(unsigned int i = 0; i < totalLocks; ++i) {
707 		semaphore.signal();
708 	}
709 }
maxReaders()710 int ReadWriteMutex::maxReaders() {
711 	//return semaphore.getSemValue();
712 	return this->maxReadersCount;
713 }
714 
715 // =====================================================
716 //	class Trigger
717 // =====================================================
718 
Trigger(Mutex * mutex)719 Trigger::Trigger(Mutex *mutex) {
720 	if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
721 
722 	this->mutex = mutex;
723 	this->trigger = SDL_CreateCond();
724 	if(this->trigger == NULL) {
725 		char szBuf[8096]="";
726 		snprintf(szBuf,8095,"In [%s::%s Line: %d] trigger == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
727 		throw megaglest_runtime_error(szBuf);
728 	}
729 
730 	if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
731 }
732 
~Trigger()733 Trigger::~Trigger() {
734 	if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
735 
736 	if(trigger == NULL) {
737 		char szBuf[8096]="";
738 		snprintf(szBuf,8095,"In [%s::%s Line: %d] trigger == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
739 		throw megaglest_runtime_error(szBuf);
740 	}
741 	if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
742 
743 	SDL_DestroyCond(trigger);
744 	trigger = NULL;
745 
746 	if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
747 
748 	this->mutex = NULL;
749 
750 	if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
751 }
752 
signal(bool allThreads)753 void Trigger::signal(bool allThreads) {
754 	if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
755 
756 	if(trigger == NULL) {
757 		char szBuf[8096]="";
758 		snprintf(szBuf,8095,"In [%s::%s Line: %d] trigger == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
759 		throw megaglest_runtime_error(szBuf);
760 	}
761 
762 	//MutexSafeWrapper safeMutex(mutex);
763 
764 	if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
765 
766 	if(allThreads == false) {
767 		if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
768 
769 		int result = SDL_CondSignal(trigger);
770 
771 		if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d] result = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,result);
772 	}
773 	else {
774 		if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
775 
776 		int result = SDL_CondBroadcast(trigger);
777 
778 		if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d] result = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,result);
779 	}
780 
781 	//safeMutex.ReleaseLock();
782 
783 	if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
784 }
785 
waitTillSignalled(Mutex * mutex,int waitMilliseconds)786 int Trigger::waitTillSignalled(Mutex *mutex, int waitMilliseconds) {
787 	if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
788 
789 	if(trigger == NULL) {
790 		char szBuf[8096]="";
791 		snprintf(szBuf,8095,"In [%s::%s Line: %d] trigger == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
792 		throw megaglest_runtime_error(szBuf);
793 	}
794 	if(mutex == NULL) {
795 		char szBuf[8096]="";
796 		snprintf(szBuf,8095,"In [%s::%s Line: %d] mutex == NULL",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
797 		throw megaglest_runtime_error(szBuf);
798 	}
799 
800 	if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
801 
802 	int result = 0;
803 	if(waitMilliseconds >= 0) {
804 		if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
805 
806 		result = SDL_CondWaitTimeout(trigger,mutex->getMutex(),waitMilliseconds);
807 	}
808 	else {
809 		if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
810 
811 		result = SDL_CondWait(trigger, mutex->getMutex());
812 	}
813 
814 	if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
815 
816 	return result;
817 }
818 
MasterSlaveThreadController()819 MasterSlaveThreadController::MasterSlaveThreadController() {
820 	std::vector<SlaveThreadControllerInterface *> empty;
821 	init(empty);
822 }
823 
MasterSlaveThreadController(std::vector<SlaveThreadControllerInterface * > & slaveThreadList)824 MasterSlaveThreadController::MasterSlaveThreadController(std::vector<SlaveThreadControllerInterface *> &slaveThreadList) {
825 	if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d] ==========================================================\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
826 
827 	init(slaveThreadList);
828 }
829 
init(std::vector<SlaveThreadControllerInterface * > & newSlaveThreadList)830 void MasterSlaveThreadController::init(std::vector<SlaveThreadControllerInterface *> &newSlaveThreadList) {
831 	this->mutex 				= new Mutex(CODE_AT_LINE);
832 	this->slaveTriggerSem 		= new Semaphore(0);
833 	this->slaveTriggerCounter 	= (int)newSlaveThreadList.size() + triggerBaseCount;
834 	setSlaves(newSlaveThreadList);
835 }
836 
clearSlaves(bool clearListOnly)837 void MasterSlaveThreadController::clearSlaves(bool clearListOnly) {
838 	if(this->slaveThreadList.empty() == false) {
839 		if(clearListOnly == false) {
840 			for(unsigned int i = 0; i < this->slaveThreadList.size(); ++i) {
841 				SlaveThreadControllerInterface *slave = this->slaveThreadList[i];
842 				if(slave != NULL) {
843 					slave->setMasterController(NULL);
844 				}
845 			}
846 		}
847 		this->slaveThreadList.clear();
848 	}
849 }
850 
~MasterSlaveThreadController()851 MasterSlaveThreadController::~MasterSlaveThreadController() {
852 	if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
853 
854 	clearSlaves();
855 
856 	delete slaveTriggerSem;
857 	slaveTriggerSem = NULL;
858 
859 	if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d] mutex->getRefCount() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,mutex->getRefCount());
860 
861 	delete mutex;
862 	mutex = NULL;
863 
864 	if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
865 }
866 
setSlaves(std::vector<SlaveThreadControllerInterface * > & slaveThreadList)867 void MasterSlaveThreadController::setSlaves(std::vector<SlaveThreadControllerInterface *> &slaveThreadList) {
868 	this->slaveThreadList = slaveThreadList;
869 
870 	if(this->slaveThreadList.empty() == false) {
871 		for(unsigned int i = 0; i < this->slaveThreadList.size(); ++i) {
872 			SlaveThreadControllerInterface *slave = this->slaveThreadList[i];
873 			if(slave != NULL) {
874 				slave->setMasterController(this);
875 			}
876 		}
877 	}
878 }
879 
signalSlaves(void * userdata)880 void MasterSlaveThreadController::signalSlaves(void *userdata) {
881 	if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
882 
883 	slaveTriggerCounter = (int)this->slaveThreadList.size() + triggerBaseCount;
884 
885 	if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
886 
887 	if(this->slaveThreadList.empty() == false) {
888 		for(unsigned int i = 0; i < this->slaveThreadList.size(); ++i) {
889 			SlaveThreadControllerInterface *slave = this->slaveThreadList[i];
890 			if(slave != NULL) {
891 				slave->signalSlave(userdata);
892 			}
893 		}
894 	}
895 
896 	if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
897 }
898 
triggerMaster(int waitMilliseconds)899 void MasterSlaveThreadController::triggerMaster(int waitMilliseconds) {
900 	if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
901 
902 	MutexSafeWrapper safeMutex(mutex);
903 	if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d] semVal = %u\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,slaveTriggerCounter);
904 	//printf("In [%s::%s Line: %d] semVal = %u\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,slaveTriggerCounter);
905 
906 	slaveTriggerCounter--;
907 	int newCount = slaveTriggerCounter;
908 
909 	if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d] slaveTriggerCounter = %u\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,slaveTriggerCounter);
910 
911 	safeMutex.ReleaseLock();
912 
913 	//printf("In [%s::%s Line: %d] semVal = %u\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,slaveTriggerCounter);
914 
915 	if(newCount <= triggerBaseCount) {
916 		slaveTriggerSem->signal();
917 	}
918 
919 	if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
920 }
921 
waitTillSlavesTrigger(int waitMilliseconds)922 bool MasterSlaveThreadController::waitTillSlavesTrigger(int waitMilliseconds) {
923 	bool result = true;
924 
925 	if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d] slaveTriggerCounter = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,slaveTriggerCounter);
926 
927 	if(this->slaveThreadList.empty() == false) {
928 		if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d] slaveTriggerCounter = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,slaveTriggerCounter);
929 
930 		int slaveResult = slaveTriggerSem->waitTillSignalled(waitMilliseconds);
931 
932 		if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d] slaveTriggerCounter = %d slaveResult = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,slaveTriggerCounter,slaveResult);
933 
934 		if(slaveResult != 0) {
935 			if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
936 
937 			result = false;
938 		}
939 		else if(slaveResult == 0) {
940 			if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d] slaveTriggerCounter = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,slaveTriggerCounter);
941 
942 			result = true;
943 		}
944 	}
945 
946 	if(debugMasterSlaveThreadController) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
947 
948 	return result;
949 }
950 
951 }}//end namespace
952