KSquare Utilities
GoalKeeperSimple.cpp
Go to the documentation of this file.
1 /* GoalKeeperSimple.cpp -- Implements blocking routines to support thread synchronization.
2  * Copyright (C) 1994-2011 Kurt Kramer
3  * For conditions of distribution and use, see copyright notice in KKB.h
4  */
5 #include "FirstIncludes.h"
6 #include <errno.h>
7 #include <istream>
8 #include <iostream>
9 #include <fstream>
10 //#include <stdio.h>
11 #include <vector>
12 #include "KKBaseTypes.h"
13 
14 #if defined(WIN32)
15 #include <windows.h>
16 #else
17 #include <fcntl.h>
18 #include <semaphore.h>
19 #endif
20 #include "MemoryDebug.h"
21 using namespace std;
22 
23 
24 #include "GoalKeeperSimple.h"
25 #include "KKException.h"
26 #include "OSservices.h"
27 using namespace KKB;
28 
29 
30 
31 
32 
33 
34 volatile GoalKeeperSimpleListPtr GoalKeeperSimple::existingGoalKeepers = NULL;
35 
36 
37 
38 GoalKeeperSimple::GoalKeeperSimple (const KKStr& _name):
39  blocked (false),
40  blockerThreadId (-1),
41  levels (0),
42  name (_name)
43 {
44 #if defined(WIN32)
45  InitializeCriticalSection (&cs);
46 #else
47  pthread_mutex_init (&mutex, NULL);
48 #endif
49 }
50 
51 
52 
53 GoalKeeperSimple::~GoalKeeperSimple ()
54 {
55 #if defined(WIN32)
56  if (blocked)
57  CriticalSectionEnd ();
58 #else
59  pthread_mutex_destroy (&mutex);
60 #endif
61 
62 }
63 
64 
65 
66 
67 
68 
70 {
71  return (sizeof (GoalKeeperSimple) + name.MemoryConsumedEstimated ());
72 }
73 
74 
75 
77 {
78  return blocked;
79 } /* Blocked */
80 
81 
82 
84 {
85  if (!blocked)
86  return false;
87 
88  kkint32 curThreadId = KKB::osGetThreadId ();
89  return (blocked && (curThreadId != blockerThreadId));
90 }
91 
92 
93 
94 void GoalKeeperSimple::CriticalSectionStart ()
95 {
96 #if defined(WIN32)
97  EnterCriticalSection (&cs);
98 #else
99  pthread_mutex_lock (&mutex);
100 #endif
101 }
102 
103 
104 
105 
106 void GoalKeeperSimple::CriticalSectionEnd ()
107 {
108 #if defined(WIN32)
109  LeaveCriticalSection (&cs);
110 #else
111  pthread_mutex_unlock (&mutex);
112 #endif
113 }
114 
115 
116 
118 {
119  kkint32 curThreadId = KKB::osGetThreadId ();
120 
121  if (blocked && (curThreadId == blockerThreadId))
122  {
123  ++levels;
124  }
125  else
126  {
127  CriticalSectionStart ();
128  levels = 1;
129  blockerThreadId = curThreadId;
130  blocked = true;
131  }
132 
133  return;
134 } /* StartBlock */
135 
136 
137 
138 
140 {
141  kkint32 curThreadId = KKB::osGetThreadId ();
142  if (!blocked)
143  throw KKB::KKException ("GoalKeeperSimple::EndBlock Name[" + name + "] Is not currently blocked.");
144 
145  if (curThreadId != blockerThreadId)
146  throw KKB::KKException ("GoalKeeperSimple::EndBlock Name[" + name + "] ThreadId[" + blockerThreadId + "] Currently holds Block; our ThreadId[" + curThreadId + "]");
147 
148  --levels;
149  if (levels < 1)
150  {
151  blocked = false;
152  blockerThreadId = -1;
153  CriticalSectionEnd ();
154  }
155 } /* EndBlock */
156 
157 
158 
159 
160 void GoalKeeperSimple::Create (const KKStr& _name,
161  volatile GoalKeeperSimplePtr& _newGoalKeeper
162  )
163 {
164 #if defined(WIN32)
165  HANDLE mutexCreateHandle = CreateMutex (NULL, /**< default security attributes */
166  false, /**< initially not owned */
167  "GoalKeeperClass"
168  );
169  if (!mutexCreateHandle)
170  {
171  KKStr errMsg = "GoalKeeperSimple::Create ***ERROR*** CreateMutex failed; returned back NULL; _name:" + _name;
172  cerr << endl << errMsg << endl << endl;
173  throw KKException (errMsg);
174  }
175 
176  WaitForSingleObject (mutexCreateHandle, INFINITE);
177 
178  if (_newGoalKeeper == NULL)
179  {
180  _newGoalKeeper = new GoalKeeperSimple (_name);
181  if (existingGoalKeepers == NULL)
182  {
183  existingGoalKeepers = new GoalKeeperSimpleList (true);
184  atexit (GoalKeeperSimple::FinalCleanUp);
185  }
186  existingGoalKeepers->PushOnBack (_newGoalKeeper);
187  }
188 
189  ReleaseMutex (mutexCreateHandle);
190  CloseHandle(mutexCreateHandle);
191 #else
192  sem_t* semHandle = sem_open ("GoalKeeperClass", O_CREAT, 0644, 1);
193  if (semHandle == SEM_FAILED)
194  {
195  cout << std::endl
196  << "GoalKeeperSimple::Create Error[" << errno << "] opening '/GoalKeeperSimple' Semaphore." << std::endl
197  << std::endl;
198 
199  perror("GoalKeeperSimple::Create Error Opening Semaphore 'GoalKeeperSimple'");
200 
201  throw "GoalKeeperSimple::Create Error opening 'GoalKeeperSimple'.";
202  }
203 
204  sem_wait (semHandle);
205 
206  if (_newGoalKeeper == NULL)
207  {
208  _newGoalKeeper = new GoalKeeperSimple (_name);
209  if (existingGoalKeepers == NULL)
210  {
211  existingGoalKeepers = new GoalKeeperSimpleList (true);
212  atexit (GoalKeeperSimple::FinalCleanUp);
213  }
214  existingGoalKeepers->PushOnBack (_newGoalKeeper);
215  }
216 
217  sem_post (semHandle);
218  sem_close (semHandle);
219 #endif
220 } /* Create */
221 
222 
223 
224 
225 /**
226  *@brief Create a new instance of a GoalKeeperSimple object if it has not already been done and locks it if we create it.
227  *@param[in] _name Name to be assigned to GoalKeeperSimple object.
228  *@param[in,out] _newGoalKeeper A pointer to the GoalKeeperSimple that already exists or to new one that got created.
229  *@param[out] _didNotExistYet Indicates if the call to 'CreateAndStartBlock' had to create a new instance.
230  */
232  volatile GoalKeeperSimplePtr& _newGoalKeeper,
233  bool& _didNotExistYet
234  )
235 {
236 #if defined(WIN32)
237  HANDLE mutexCreateHandle = CreateMutex (NULL, /**< default security attributes. */
238  false, /**< initially not owned. */
239  "GoalKeeperClass"
240  );
241  if (!mutexCreateHandle)
242  {
243  KKStr errMsg = "GoalKeeperSimple::CreateAndStartBlock ***ERROR*** CreateMutex failed; returned back NULL; _name:" + _name;
244  cerr << endl << errMsg << endl << endl;
245  throw KKException(errMsg);
246  }
247 
248  WaitForSingleObject (mutexCreateHandle, INFINITE);
249 
250  if (_newGoalKeeper == NULL)
251  {
252  _didNotExistYet = true;
253  _newGoalKeeper = new GoalKeeperSimple (_name);
254 
255  if (existingGoalKeepers == NULL)
256  {
257  existingGoalKeepers = new GoalKeeperSimpleList (true);
258  atexit (GoalKeeperSimple::FinalCleanUp);
259  }
260  existingGoalKeepers->PushOnBack (_newGoalKeeper);
261  }
262  else
263  {
264  _didNotExistYet = false;
265  }
266 
267  _newGoalKeeper->StartBlock ();
268 
269  ReleaseMutex (mutexCreateHandle);
270  CloseHandle(mutexCreateHandle);
271 #else
272  sem_t* semHandle = sem_open ("GoalKeeperClass", O_CREAT, 0644, 1);
273  if (semHandle == SEM_FAILED)
274  {
275  cout << std::endl
276  << "GoalKeeperSimple::Create Error[" << errno << "] opening '/GoalKeeperSimple' Semaphore." << std::endl
277  << std::endl;
278 
279  perror("GoalKeeperSimple::Create Error Opening Semaphore 'GoalKeeperSimple'");
280 
281  throw "GoalKeeperSimple::Create Error opening 'GoalKeeperSimple'.";
282  }
283 
284  sem_wait (semHandle);
285 
286  if (_newGoalKeeper == NULL)
287  {
288  _didNotExistYet = true;
289  _newGoalKeeper = new GoalKeeperSimple (_name);
290  if (existingGoalKeepers == NULL)
291  {
292  existingGoalKeepers = new GoalKeeperSimpleList (true);
293  atexit (GoalKeeperSimple::FinalCleanUp);
294  }
295  existingGoalKeepers->PushOnBack (_newGoalKeeper);
296  }
297  else
298  {
299  _didNotExistYet = false;
300  }
301 
302  _newGoalKeeper->StartBlock ();
303 
304  sem_post (semHandle);
305  sem_close (semHandle);
306 #endif
307 } /* CreateAndStartBlock */
308 
309 
310 
311 
312 
313 void GoalKeeperSimple::Destroy (volatile GoalKeeperSimplePtr& _goalKeeperInstance)
314 {
315 #if defined(WIN32)
316  HANDLE mutexCreateHandle = CreateMutex (NULL, /**< default security attributes */
317  false, /**< initially not owned */
318  "GoalKeeperClass"
319  );
320  if (!mutexCreateHandle)
321  {
322  KKStr errMsg = "GoalKeeperSimple::Destroy ***ERROR*** CreateMutex failed; returned back NULL";
323  cerr << endl << errMsg << endl << endl;
324  throw KKException(errMsg);
325  }
326 
327  WaitForSingleObject (mutexCreateHandle, INFINITE);
328 
329  if (_goalKeeperInstance == NULL)
330  {
331  // Some other thread managed to destroy this instance.
332  }
333  else
334  {
335  kkint32 existingInstanceIdx = existingGoalKeepers->PtrToIdx (_goalKeeperInstance);
336  if (existingInstanceIdx < 0)
337  {
338  // If not in list then a different thread beat us to destroying this instance or it was never created to start with.
339  }
340  else
341  {
342  existingGoalKeepers->DeleteEntry (_goalKeeperInstance);
343  delete _goalKeeperInstance;
344  _goalKeeperInstance = NULL;
345  }
346  }
347 
348  ReleaseMutex (mutexCreateHandle);
349  CloseHandle(mutexCreateHandle);
350 #else
351  sem_t* semHandle = sem_open ("GoalKeeperClass", O_CREAT, 0644, 1);
352  if (semHandle == SEM_FAILED)
353  {
354  cout << std::endl
355  << "GoalKeeperSimple::Create Error[" << errno << "] opening '/GoalKeeperSimple' Semaphore." << std::endl
356  << std::endl;
357 
358  perror("GoalKeeperSimple::Create Error Opening Semaphore 'GoalKeeperSimple'");
359 
360  throw "GoalKeeperSimple::Create Error opening 'GoalKeeperSimple'.";
361  }
362 
363  sem_wait (semHandle);
364 
365  if (_goalKeeperInstance == NULL)
366  {
367  // Some other thread managed to destroy this instance.
368  }
369  else
370  {
371  kkint32 existingInstanceIdx = existingGoalKeepers->PtrToIdx (_goalKeeperInstance);
372  if (existingInstanceIdx >= 0)
373  {
374  // If not in list then a different thread beat us to destroying this instance or it was never created to start with.
375  }
376  else
377  {
378  existingGoalKeepers->DeleteEntry (_goalKeeperInstance);
379  delete _goalKeeperInstance;
380  _goalKeeperInstance = NULL;
381  }
382  }
383 
384  sem_post (semHandle);
385  sem_close (semHandle);
386 #endif
387 
388 } /* Destroy */
389 
390 
391 
393 {
394  if (existingGoalKeepers)
395  {
396  delete existingGoalKeepers;
397  existingGoalKeepers = NULL;
398  }
399 }
400 
401 
402 
403 
405 {
406  kkint32 x = 0;
407  x = blockerThreadId;
408  return x;
409 }
bool BlockedByAnotherThread()
Returns true if a different thread has this instance of "GoalKeeperSimple" locked.
GoalKeeperSimpleList * GoalKeeperSimpleListPtr
kkint32 MemoryConsumedEstimated() const
Definition: KKStr.cpp:766
__int32 kkint32
Definition: KKBaseTypes.h:88
KKStr operator+(kkint32 right) const
Definition: KKStr.cpp:4036
static void Destroy(volatile GoalKeeperSimplePtr &_goalKeeperInstance)
Destroys an existing instance of GoalKeeperSimple.
kkint32 osGetThreadId()
kkint32 BlockerThreadId()
ThreadId of thread that currently holds the Block -1 indicates no Block.
A simple/ light-weight implementation of critical section blocking.
KKStr operator+(const char *right) const
Definition: KKStr.cpp:3986
void EndBlock()
Ends the block and allows other threads to pass through StatBlock.
KKTHread * KKTHreadPtr
KKStr operator+(const char *left, const KKStr &right)
Definition: KKStr.cpp:3976
KKStr(const KKStr &str)
Copy Constructor.
Definition: KKStr.cpp:561
static KKStr Concat(const std::vector< std::string > &values)
Concatenates the list of &#39;std::string&#39; strings.
Definition: KKStr.cpp:1082
static void CreateAndStartBlock(const KKStr &_name, volatile GoalKeeperSimplePtr &_newGoalKeeper, bool &_didNotExistYet)
Create a GoalKeeperSimple object and avoid a race condition doing it.
static void Create(const KKStr &_name, volatile GoalKeeperSimplePtr &_newGoalKeeper)
Create a GoalKeeperSimple object and avoid a race condition doing it.
void StartBlock()
Initiates a Block as long as another thread has not already locked this object.
static void FinalCleanUp()
Will be registered with &#39;atexit&#39; so that it will be called when program is unloaded from memory...
bool Blocked()
Will return true if any thread lock on this instance of "GoalKeeperSimple".
GoalKeeperSimple * GoalKeeperSimplePtr
KKException(const KKStr &_exceptionStr)
Definition: KKException.cpp:45
kkint32 MemoryConsumedEstimated() const