OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
StdSync.h
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2011-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 /* synchronization helper classes */
17 
18 #ifndef INC_StdSync
19 #define INC_StdSync
20 
21 #ifdef _WIN32
23 
24 class CStdCSec
25 {
26 public:
27  CStdCSec() { InitializeCriticalSection(&sec); }
28  virtual ~CStdCSec() { DeleteCriticalSection(&sec); }
29 
30 protected:
31  CRITICAL_SECTION sec;
32 
33 public:
34  virtual void Enter() { EnterCriticalSection(&sec); }
35  virtual void Leave() { LeaveCriticalSection(&sec); }
36 };
37 
38 class CStdEvent
39 {
40 public:
41  CStdEvent(bool fManualReset) { hEvent = CreateEvent(nullptr, fManualReset, false, nullptr); }
42  ~CStdEvent() { CloseHandle(hEvent); }
43 
44 protected:
45  HANDLE hEvent;
46 
47 public:
48  void Set() { SetEvent(hEvent); }
49  void Pulse() { PulseEvent(hEvent); }
50  void Reset() { ResetEvent(hEvent); }
51  bool WaitFor(int iMillis) { return WaitForSingleObject(hEvent, iMillis) == WAIT_OBJECT_0; }
52 
53  HANDLE GetEvent() { return hEvent; }
54 };
55 
56 #else
57 // Value to specify infinite wait.
58 #define INFINITE (~0u)
59 
60 #if defined(HAVE_PTHREAD)
61 #include <pthread.h>
62 
63 class CStdCSec
64 {
65 public:
66  CStdCSec()
67  {
68  pthread_mutexattr_t attr;
69  pthread_mutexattr_init(&attr);
70  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
71  pthread_mutex_init(&mutex, &attr);
72  }
73  virtual ~CStdCSec() { pthread_mutex_destroy(&mutex); }
74 
75 protected:
76  pthread_mutex_t mutex;
77 
78 public:
79  virtual void Enter() { pthread_mutex_lock(&mutex); }
80  virtual void Leave() { pthread_mutex_unlock(&mutex); }
81 };
82 
83 class CStdEvent
84 {
85 public:
86  CStdEvent(bool fManualReset) : fManualReset(fManualReset), fSet(false)
87  {
88  pthread_cond_init(&cond, nullptr);
89  pthread_mutex_init(&mutex, nullptr);
90  }
91  ~CStdEvent()
92  {
93  pthread_cond_destroy(&cond);
94  pthread_mutex_destroy(&mutex);
95  }
96 
97 protected:
98  pthread_cond_t cond;
99  pthread_mutex_t mutex;
100  bool fManualReset, fSet;
101 
102 public:
103  void Set()
104  {
105  pthread_mutex_lock(&mutex);
106  fSet = true;
107  pthread_cond_broadcast(&cond);
108  pthread_mutex_unlock(&mutex);
109  }
110  void Pulse()
111  {
112  pthread_cond_broadcast(&cond);
113  }
114  void Reset()
115  {
116  pthread_mutex_lock(&mutex);
117  fSet = false;
118  pthread_mutex_unlock(&mutex);
119  }
120  bool WaitFor(unsigned int iMillis)
121  {
122  pthread_mutex_lock(&mutex);
123  // Already set?
124  while (!fSet)
125  {
126  // Use pthread_cond_wait or pthread_cond_timedwait depending on wait length. Check return value.
127  // Note this will temporarily unlock the mutex, so no deadlock should occur.
128  timespec ts = { static_cast<time_t>(iMillis / 1000),
129  static_cast<long>((iMillis % 1000) * 1000000) };
130  if (0 != (iMillis != INFINITE ? pthread_cond_timedwait(&cond, &mutex, &ts) : pthread_cond_wait(&cond, &mutex)))
131  {
132  pthread_mutex_unlock(&mutex);
133  return false;
134  }
135  }
136  // Reset flag, release mutex, done.
137  if (!fManualReset) fSet = false;
138  pthread_mutex_unlock(&mutex);
139  return true;
140  }
141 };
142 
143 #else
144 // Some stubs to silence the compiler
145 class CStdCSec
146 {
147 public:
148  CStdCSec() { }
149  virtual ~CStdCSec() { }
150  virtual void Enter() { }
151  virtual void Leave() { }
152 };
154 {
155 public:
156  CStdEvent(bool) { }
158  void Set() { }
159  void Pulse() { }
160  void Reset() { }
161  bool WaitFor(int) { return false; }
162 };
163 #endif // HAVE_PTHREAD
164 #endif // _WIN32
165 
166 class CStdLock
167 {
168 public:
169  CStdLock(CStdCSec *pSec) : sec(pSec)
170  { sec->Enter(); }
172  { Clear(); }
173 
174 protected:
176 
177 public:
178  void Clear()
179  { if (sec) sec->Leave(); sec = nullptr; }
180 };
181 
183 {
184 public:
185  // is called with CSec exlusive locked!
186  virtual void OnShareFree(class CStdCSecEx *pCSec) = 0;
187  virtual ~CStdCSecExCallback() {}
188 };
189 
190 class CStdCSecEx : public CStdCSec
191 {
192 public:
194  : lShareCnt(0), ShareFreeEvent(false), pCallbClass(nullptr)
195  { }
197  : lShareCnt(0), ShareFreeEvent(false), pCallbClass(pCallb)
198  { }
200  { }
201 
202 protected:
203  // share counter
204  long lShareCnt;
205  // event: exclusive access permitted
207  // callback
209 
210 public:
211 
212  // (cycles forever if shared locked by calling thread!)
213  void Enter()
214  {
215  // lock
216  CStdCSec::Enter();
217  // wait for share-free
218  while (lShareCnt)
219  {
220  // reset event
221  ShareFreeEvent.Reset();
222  // leave section for waiting
223  CStdCSec::Leave();
224  // wait
225  ShareFreeEvent.WaitFor(INFINITE);
226  // reenter section
227  CStdCSec::Enter();
228  }
229  }
230 
231  void Leave()
232  {
233  // set event
234  ShareFreeEvent.Set();
235  // unlock
236  CStdCSec::Leave();
237  }
238 
239  void EnterShared()
240  {
241  // lock
242  CStdCSec::Enter();
243  // add share
244  lShareCnt++;
245  // unlock
246  CStdCSec::Leave();
247  }
248 
249  void LeaveShared()
250  {
251  // lock
252  CStdCSec::Enter();
253  // remove share
254  if (!--lShareCnt)
255  {
256  // do callback
257  if (pCallbClass)
258  pCallbClass->OnShareFree(this);
259  // set event
260  ShareFreeEvent.Set();
261  }
262  // unlock
263  CStdCSec::Leave();
264  }
265 };
266 
268 {
269 public:
270  CStdShareLock(CStdCSecEx *pSec) : sec(pSec)
271  { sec->EnterShared(); }
273  { Clear(); }
274 
275 protected:
277 
278 public:
279  void Clear()
280  { if (sec) sec->LeaveShared(); sec = nullptr; }
281 };
282 
283 /* Debug helper class: Set current thread in Set(); assert that it's still the same thread in Check(); */
285 {
286 #if defined(_DEBUG) && defined(_WIN32)
287  DWORD idThread;
288 public:
289  StdThreadCheck() : idThread(0) {}
290 
291  inline void Set() { idThread = ::GetCurrentThreadId(); }
292  inline void Check() { assert(idThread == ::GetCurrentThreadId()); }
293 #else
294 public:
295  inline void Set() {}
296  inline void Check() { }
297 #endif
298 };
299 
300 #endif // INC_StdSync
virtual void OnShareFree(class CStdCSecEx *pCSec)=0
CStdCSecEx * sec
Definition: StdSync.h:276
CStdCSec()
Definition: StdSync.h:148
~CStdShareLock()
Definition: StdSync.h:272
void Clear()
Definition: StdSync.h:279
virtual ~CStdCSecExCallback()
Definition: StdSync.h:187
CStdLock(CStdCSec *pSec)
Definition: StdSync.h:169
~CStdCSecEx()
Definition: StdSync.h:199
~CStdLock()
Definition: StdSync.h:171
void Clear()
Definition: StdSync.h:178
void Reset()
Definition: StdSync.h:160
bool WaitFor(int)
Definition: StdSync.h:161
void Check()
Definition: StdSync.h:296
virtual ~CStdCSec()
Definition: StdSync.h:149
CStdCSec * sec
Definition: StdSync.h:175
void LeaveShared()
Definition: StdSync.h:249
void EnterShared()
Definition: StdSync.h:239
CStdShareLock(CStdCSecEx *pSec)
Definition: StdSync.h:270
virtual void Leave()
Definition: StdSync.h:151
void Set()
Definition: StdSync.h:295
virtual void Enter()
Definition: StdSync.h:150
CStdEvent(bool)
Definition: StdSync.h:156
void Set()
Definition: StdSync.h:158
~CStdEvent()
Definition: StdSync.h:157
CStdCSecEx(CStdCSecExCallback *pCallb)
Definition: StdSync.h:196
long lShareCnt
Definition: StdSync.h:204
CStdCSecEx()
Definition: StdSync.h:193
#define INFINITE
Definition: StdSync.h:58
uint32_t DWORD
CStdCSecExCallback * pCallbClass
Definition: StdSync.h:208
void Pulse()
Definition: StdSync.h:159
void Enter()
Definition: StdSync.h:213
CStdEvent ShareFreeEvent
Definition: StdSync.h:206
void Leave()
Definition: StdSync.h:231