21 #include <semaphore.h> 35 #if defined(GOALKEEPER_DEBUG) 36 class GoalKeeper::BlockedStat
39 BlockedStat (kkint32 _blockedThreadId,
40 kkint32 _blockerThreadId,
41 kkuint32 _milliSecsBlocked,
42 kkint32 _numBlockedThreads
44 blockedThreadId (_blockedThreadId),
45 blockerThreadId (_blockerThreadId),
46 milliSecsBlocked (_milliSecsBlocked),
47 numBlockedThreads (_numBlockedThreads),
48 dateTimeBlocked (osGetLocalDateTime ())
52 kkint32 blockedThreadId;
53 kkint32 blockerThreadId;
54 kkuint32 milliSecsBlocked;
55 kkint32 numBlockedThreads;
56 DateTime dateTimeBlocked;
60 class GoalKeeper::BlockedStatList:
public KKQueue<BlockedStat>
63 BlockedStatList (
bool _owner): KKQueue<BlockedStat> (_owner) {}
82 InitializeCriticalSection (&cs);
84 pthread_mutex_init (&mutex, NULL);
87 #if defined(GOALKEEPER_DEBUG) 88 blockedStats =
new BlockedStatList (
true);
98 CriticalSectionEnd ();
100 pthread_mutex_destroy (&mutex);
103 #if defined(GOALKEEPER_DEBUG) 104 ReportBlockedStats ();
115 #if defined(GOALKEEPER_DEBUG) 116 void GoalKeeper::ReportBlockedStats ()
118 HANDLE mutexCreateHandle = CreateMutex (NULL,
120 "GoalKeeper_ReportBlockedStats" 123 WaitForSingleObject (mutexCreateHandle, INFINITE);
125 KKStr path =
"C:\\Temp\\BlockedStats";
127 KKB::osCreateDirectoryPath (path);
129 KKStr fileName = osAddSlash (path) +
"BlockedStats.txt";
131 ofstream o (fileName.Str (), ios_base::app);
135 <<
"\t" <<
"BlockedThreadId" 136 <<
"\t" <<
"BlockerThreadId" 137 <<
"\t" <<
"DateTimeBlocked" 138 <<
"\t" <<
"MilliSecsBlocked" 139 <<
"\t" <<
"NumBlockedThreads" 143 BlockedStatList::iterator idx;
144 for (idx = blockedStats->begin (), c = 0; idx != blockedStats->end (); ++idx, ++c)
146 BlockedStat* bs = *idx;
149 <<
"\t" << bs->blockedThreadId
150 <<
"\t" << bs->blockerThreadId
151 <<
"\t" << bs->dateTimeBlocked.Date () <<
" " << bs->dateTimeBlocked.Time ()
152 <<
"\t" << bs->milliSecsBlocked
153 <<
"\t" << bs->numBlockedThreads
159 ReleaseMutex (mutexCreateHandle);
160 CloseHandle(mutexCreateHandle);
186 return (blocked && (curThreadId != blockerThreadId));
194 EnterCriticalSection (&cs);
196 pthread_mutex_lock (&mutex);
206 LeaveCriticalSection (&cs);
208 pthread_mutex_unlock (&mutex);
218 bool firstPassThruLoop =
true;
219 bool weAreBlocked =
true;
224 CriticalSectionStart ();
226 if (firstPassThruLoop)
231 if (curThreadId == blockerThreadId)
236 weAreBlocked =
false;
242 #if defined(GOALKEEPER_DEBUG) 243 blockedStats->PushOnBack (
new BlockedStat (curThreadId, blockerThreadId, milliSecsBlocked, numBlockedThreads));
252 blockerThreadId = curThreadId;
253 weAreBlocked =
false;
257 CriticalSectionEnd ();
261 if (milliSecsBlocked < 10)
267 else if (milliSecsBlocked < 200)
270 milliSecsBlocked += 10;
273 else if (milliSecsBlocked < 10000)
276 milliSecsBlocked += 100;
282 milliSecsBlocked += 400;
286 firstPassThruLoop =
false;
305 CriticalSectionStart ();
312 else if (curProcessorId != blockerThreadId)
320 if (blockerDepth < 1)
323 blockerThreadId = -1;
328 CriticalSectionEnd ();
334 else if (errorCode == 1)
335 throw KKStr (
"GoalKeeper::EndBlock Name[" + name
+ "] There was no block established.");
337 else if (errorCode == 2)
338 throw KKStr (
"GoalKeeper::EndBlock Name[" + name
+ "] ThreadId[" + curProcessorId
+ "] Currently holds Block; our ThreadId[" + curProcessorId
+ "]");
351 HANDLE mutexCreateHandle = CreateMutex (NULL,
355 if (mutexCreateHandle == NULL)
356 throw KKException (
"GoalKeeper::Create failed to get handle to Mutex Object 'GoalKeeperClass'.");
358 WaitForSingleObject (mutexCreateHandle, INFINITE);
360 if (_newGoalKeeper == NULL)
363 if (existingGoalKeepers == NULL)
366 atexit (GoalKeeper::FinalCleanUp);
368 existingGoalKeepers->PushOnBack (_newGoalKeeper);
371 ReleaseMutex (mutexCreateHandle);
372 CloseHandle(mutexCreateHandle);
374 sem_t* semHandle = sem_open (
"GoalKeeperClass", O_CREAT, 0644, 1);
375 if (semHandle == SEM_FAILED)
378 <<
"GoalKeeper::Create Error[" << errno <<
"] opening '/GoalKeeper' Semaphore." << std::endl
381 perror(
"GoalKeeper::Create Error Opening Semaphore 'GoalKeeper'");
383 throw "GoalKeeper::Create Error opening 'GoalKeeper'.";
386 sem_wait (semHandle);
388 if (_newGoalKeeper == NULL)
390 _newGoalKeeper =
new GoalKeeper (_name);
391 if (existingGoalKeepers == NULL)
393 existingGoalKeepers =
new GoalKeeperList (
true);
394 atexit (GoalKeeper::FinalCleanUp);
396 existingGoalKeepers->PushOnBack (_newGoalKeeper);
399 sem_post (semHandle);
400 sem_close (semHandle);
415 bool& _didNotExistYet
419 HANDLE mutexCreateHandle = CreateMutex (NULL,
423 if (mutexCreateHandle == NULL)
424 throw KKException(
"GoalKeeper::CreateAndStartBlock failed to get handle to Mutex Object 'GoalKeeperClass'.");
426 WaitForSingleObject (mutexCreateHandle, INFINITE);
428 if (_newGoalKeeper == NULL)
430 _didNotExistYet =
true;
433 if (existingGoalKeepers == NULL)
436 atexit (GoalKeeper::FinalCleanUp);
438 existingGoalKeepers->PushOnBack (_newGoalKeeper);
442 _didNotExistYet =
false;
447 ReleaseMutex (mutexCreateHandle);
448 CloseHandle(mutexCreateHandle);
450 sem_t* semHandle = sem_open (
"GoalKeeperClass", O_CREAT, 0644, 1);
451 if (semHandle == SEM_FAILED)
454 <<
"GoalKeeper::Create Error[" << errno <<
"] opening '/GoalKeeper' Semaphore." << std::endl
457 perror(
"GoalKeeper::Create Error Opening Semaphore 'GoalKeeper'");
459 throw "GoalKeeper::Create Error opening 'GoalKeeper'.";
462 sem_wait (semHandle);
464 if (_newGoalKeeper == NULL)
466 _didNotExistYet =
true;
467 _newGoalKeeper =
new GoalKeeper (_name);
468 if (existingGoalKeepers == NULL)
470 existingGoalKeepers =
new GoalKeeperList (
true);
471 atexit (GoalKeeper::FinalCleanUp);
473 existingGoalKeepers->PushOnBack (_newGoalKeeper);
477 _didNotExistYet =
false;
480 _newGoalKeeper->StartBlock ();
482 sem_post (semHandle);
483 sem_close (semHandle);
494 HANDLE mutexCreateHandle = CreateMutex (NULL,
498 if (mutexCreateHandle == NULL)
499 throw KKException(
"GoalKeeper::Destroy failed to get handle to Mutex Object 'GoalKeeperClass'.");
501 WaitForSingleObject (mutexCreateHandle, INFINITE);
503 if (_goalKeeperInstance == NULL)
509 kkint32 existingInstanceIdx = existingGoalKeepers->PtrToIdx (_goalKeeperInstance);
510 if (existingInstanceIdx < 0)
516 existingGoalKeepers->DeleteEntry (_goalKeeperInstance);
517 delete _goalKeeperInstance;
518 _goalKeeperInstance = NULL;
522 ReleaseMutex (mutexCreateHandle);
523 CloseHandle(mutexCreateHandle);
525 sem_t* semHandle = sem_open (
"GoalKeeperClass", O_CREAT, 0644, 1);
526 if (semHandle == SEM_FAILED)
529 <<
"GoalKeeper::Create Error[" << errno <<
"] opening '/GoalKeeper' Semaphore." << std::endl
532 perror(
"GoalKeeper::Create Error Opening Semaphore 'GoalKeeper'");
534 throw "GoalKeeper::Create Error opening 'GoalKeeper'.";
537 sem_wait (semHandle);
539 if (_goalKeeperInstance == NULL)
545 kkint32 existingInstanceIdx = existingGoalKeepers->PtrToIdx (_goalKeeperInstance);
546 if (existingInstanceIdx >= 0)
552 existingGoalKeepers->DeleteEntry (_goalKeeperInstance);
553 delete _goalKeeperInstance;
554 _goalKeeperInstance = NULL;
558 sem_post (semHandle);
559 sem_close (semHandle);
568 if (existingGoalKeepers)
570 delete existingGoalKeepers;
571 existingGoalKeepers = NULL;
582 x = numBlockedThreads;
GoalKeeper * GoalKeeperPtr
kkint32 MemoryConsumedEstimated() const
kkint32 BlockerThreadId()
ThreadId of thread that currently holds the Block -1 indicates no Block.
KKStr operator+(kkint32 right) const
static void CreateAndStartBlock(const KKStr &_name, volatile GoalKeeperPtr &_newGoalKeeper, bool &_didNotExistYet)
Create a GoalKeeper object and avoid a race condition doing it.
static void Destroy(volatile GoalKeeperPtr &_goalKeeperInstance)
Destroys an existing instance of GoalKeeper.
kkint32 MemoryConsumedEstimated() const
bool Blocked()
Will return true if any thread lock on this instance of "GoalKeeper".
static void Create(const KKStr &_name, volatile GoalKeeperPtr &_newGoalKeeper)
Create a GoalKeeper object and avoid a race condition doing it.
KKStr operator+(const char *right) const
unsigned __int32 kkuint32
GoalKeeperList(bool _owner)
KKStr operator+(const char *left, const KKStr &right)
KKStr(const KKStr &str)
Copy Constructor.
void StartBlock()
Initiates a Block as long as another thread has not already locked this object.
void EndBlock()
Ends the block and allows other threads to pass through StatBlock.
static KKStr Concat(const std::vector< std::string > &values)
Concatenates the list of 'std::string' strings.
void osSleepMiliSecs(kkuint32 numMiliSecs)
static void FinalCleanUp()
Will be registered with 'atexit' so that it will be called when program is unloaded from memory...
kkint32 NumBlockedThreads()
Returns the number of threads that are waiting to establish a lock on this instance.
GoalKeeperList * GoalKeeperListPtr
bool BlockedByAnotherThread()
Returns true if a different thread has this instance of "GoalKeeper" locked.