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