1 // Windows/Synchronization.h
2 
3 #ifndef __WINDOWS_SYNCHRONIZATION_H
4 #define __WINDOWS_SYNCHRONIZATION_H
5 
6 #include "../../C/Threads.h"
7 
8 #include "../Common/MyTypes.h"
9 
10 #include "Defs.h"
11 
12 #ifdef _WIN32
13 #include "Handle.h"
14 #endif
15 
16 namespace NWindows {
17 namespace NSynchronization {
18 
19 class CBaseEvent  MY_UNCOPYABLE
20 {
21 protected:
22   ::CEvent _object;
23 public:
IsCreated()24   bool IsCreated() { return Event_IsCreated(&_object) != 0; }
25 
CBaseEvent()26   CBaseEvent() { Event_Construct(&_object); }
~CBaseEvent()27   ~CBaseEvent() { Close(); }
Close()28   WRes Close() { return Event_Close(&_object); }
29 
30   #ifdef _WIN32
HANDLE()31   operator HANDLE() { return _object; }
32   WRes Create(bool manualReset, bool initiallyOwn, LPCTSTR name = NULL, LPSECURITY_ATTRIBUTES sa = NULL)
33   {
34     _object = ::CreateEvent(sa, BoolToBOOL(manualReset), BoolToBOOL(initiallyOwn), name);
35     if (name == NULL && _object != 0)
36       return 0;
37     return ::GetLastError();
38   }
Open(DWORD desiredAccess,bool inheritHandle,LPCTSTR name)39   WRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name)
40   {
41     _object = ::OpenEvent(desiredAccess, BoolToBOOL(inheritHandle), name);
42     if (_object != 0)
43       return 0;
44     return ::GetLastError();
45   }
46   #endif
47 
Set()48   WRes Set() { return Event_Set(&_object); }
49   // bool Pulse() { return BOOLToBool(::PulseEvent(_handle)); }
Reset()50   WRes Reset() { return Event_Reset(&_object); }
Lock()51   WRes Lock() { return Event_Wait(&_object); }
52 };
53 
54 class CManualResetEvent: public CBaseEvent
55 {
56 public:
57   WRes Create(bool initiallyOwn = false)
58   {
59     return ManualResetEvent_Create(&_object, initiallyOwn ? 1: 0);
60   }
CreateIfNotCreated_Reset()61   WRes CreateIfNotCreated_Reset()
62   {
63     if (IsCreated())
64       return Reset();
65     return ManualResetEvent_CreateNotSignaled(&_object);
66   }
67   #ifdef _WIN32
CreateWithName(bool initiallyOwn,LPCTSTR name)68   WRes CreateWithName(bool initiallyOwn, LPCTSTR name)
69   {
70     return CBaseEvent::Create(true, initiallyOwn, name);
71   }
72   #endif
73 };
74 
75 class CAutoResetEvent: public CBaseEvent
76 {
77 public:
Create()78   WRes Create()
79   {
80     return AutoResetEvent_CreateNotSignaled(&_object);
81   }
CreateIfNotCreated_Reset()82   WRes CreateIfNotCreated_Reset()
83   {
84     if (IsCreated())
85       return Reset();
86     return AutoResetEvent_CreateNotSignaled(&_object);
87   }
88 };
89 
90 
91 /*
92 #ifdef _WIN32
93 
94 class CObject: public CHandle
95 {
96 public:
97   WRes Lock(DWORD timeoutInterval = INFINITE)
98     { return (::WaitForSingleObject(_handle, timeoutInterval) == WAIT_OBJECT_0 ? 0 : ::GetLastError()); }
99 };
100 
101 class CMutex: public CObject
102 {
103 public:
104   WRes Create(bool initiallyOwn, LPCTSTR name = NULL, LPSECURITY_ATTRIBUTES sa = NULL)
105   {
106     _handle = ::CreateMutex(sa, BoolToBOOL(initiallyOwn), name);
107     if (name == NULL && _handle != 0)
108       return 0;
109     return ::GetLastError();
110   }
111   #ifndef UNDER_CE
112   WRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name)
113   {
114     _handle = ::OpenMutex(desiredAccess, BoolToBOOL(inheritHandle), name);
115     if (_handle != 0)
116       return 0;
117     return ::GetLastError();
118   }
119   #endif
120   WRes Release()
121   {
122     return ::ReleaseMutex(_handle) ? 0 : ::GetLastError();
123   }
124 };
125 
126 class CMutexLock  MY_UNCOPYABLE
127 {
128   CMutex *_object;
129 public:
130   CMutexLock(CMutex &object): _object(&object) { _object->Lock(); }
131   ~CMutexLock() { _object->Release(); }
132 };
133 
134 #endif // _WIN32
135 */
136 
137 
138 class CSemaphore  MY_UNCOPYABLE
139 {
140   ::CSemaphore _object;
141 public:
CSemaphore()142   CSemaphore() { Semaphore_Construct(&_object); }
~CSemaphore()143   ~CSemaphore() { Close(); }
Close()144   WRes Close() { return Semaphore_Close(&_object); }
145 
146   #ifdef _WIN32
HANDLE()147   operator HANDLE() { return _object; }
148   #endif
149 
150   // bool IsCreated() const { return Semaphore_IsCreated(&_object) != 0; }
151 
Create(UInt32 initCount,UInt32 maxCount)152   WRes Create(UInt32 initCount, UInt32 maxCount)
153   {
154     return Semaphore_Create(&_object, initCount, maxCount);
155   }
OptCreateInit(UInt32 initCount,UInt32 maxCount)156   WRes OptCreateInit(UInt32 initCount, UInt32 maxCount)
157   {
158     return Semaphore_OptCreateInit(&_object, initCount, maxCount);
159   }
Release()160   WRes Release() { return Semaphore_Release1(&_object); }
Release(UInt32 releaseCount)161   WRes Release(UInt32 releaseCount) { return Semaphore_ReleaseN(&_object, releaseCount); }
Lock()162   WRes Lock() { return Semaphore_Wait(&_object); }
163 };
164 
165 class CCriticalSection  MY_UNCOPYABLE
166 {
167   ::CCriticalSection _object;
168 public:
CCriticalSection()169   CCriticalSection() { CriticalSection_Init(&_object); }
~CCriticalSection()170   ~CCriticalSection() { CriticalSection_Delete(&_object); }
Enter()171   void Enter() { CriticalSection_Enter(&_object); }
Leave()172   void Leave() { CriticalSection_Leave(&_object); }
173 };
174 
175 class CCriticalSectionLock  MY_UNCOPYABLE
176 {
177   CCriticalSection *_object;
Unlock()178   void Unlock()  { _object->Leave(); }
179 public:
CCriticalSectionLock(CCriticalSection & object)180   CCriticalSectionLock(CCriticalSection &object): _object(&object) {_object->Enter(); }
~CCriticalSectionLock()181   ~CCriticalSectionLock() { Unlock(); }
182 };
183 
184 
185 #ifdef _WIN32
186 
187 typedef HANDLE CHandle_WFMO;
188 typedef CSemaphore CSemaphore_WFMO;
189 typedef CAutoResetEvent CAutoResetEvent_WFMO;
190 typedef CManualResetEvent CManualResetEvent_WFMO;
191 
WaitForMultiObj_Any_Infinite(DWORD count,const CHandle_WFMO * handles)192 inline DWORD WINAPI WaitForMultiObj_Any_Infinite(DWORD count, const CHandle_WFMO *handles)
193 {
194   return ::WaitForMultipleObjects(count, handles, FALSE, INFINITE);
195 }
196 
197 #define SYNC_OBJ_DECL(obj)
198 #define SYNC_WFMO(x)
199 #define SYNC_PARAM(x)
200 #define SYNC_PARAM_DECL(x)
201 
202 #else //  _WIN32
203 
204 // POSIX sync objects for WaitForMultipleObjects
205 
206 #define SYNC_WFMO(x) x
207 #define SYNC_PARAM(x) x,
208 #define SYNC_PARAM_DECL(x) NWindows::NSynchronization::CSynchro *x
209 #define SYNC_OBJ_DECL(x) NWindows::NSynchronization::CSynchro x;
210 
211 class CSynchro  MY_UNCOPYABLE
212 {
213   pthread_mutex_t _mutex;
214   pthread_cond_t _cond;
215   bool _isValid;
216 
217 public:
CSynchro()218   CSynchro() { _isValid = false; }
~CSynchro()219   ~CSynchro()
220   {
221     if (_isValid)
222     {
223       ::pthread_mutex_destroy(&_mutex);
224       ::pthread_cond_destroy(&_cond);
225     }
226     _isValid = false;
227   }
Create()228   WRes Create()
229   {
230     RINOK(::pthread_mutex_init(&_mutex, 0));
231     WRes ret = ::pthread_cond_init(&_cond, 0);
232     _isValid = 1;
233     return ret;
234   }
Enter()235   WRes Enter()
236   {
237     return ::pthread_mutex_lock(&_mutex);
238   }
Leave()239   WRes Leave()
240   {
241     return ::pthread_mutex_unlock(&_mutex);
242   }
WaitCond()243   WRes WaitCond()
244   {
245     return ::pthread_cond_wait(&_cond, &_mutex);
246   }
LeaveAndSignal()247   WRes LeaveAndSignal()
248   {
249     WRes res1 = ::pthread_cond_broadcast(&_cond);
250     WRes res2 = ::pthread_mutex_unlock(&_mutex);
251     return (res2 ? res2 : res1);
252   }
253 };
254 
255 
256 struct CBaseHandle_WFMO;
257 typedef NWindows::NSynchronization::CBaseHandle_WFMO *CHandle_WFMO;
258 
259 // these constants are from Windows
260 #define WAIT_OBJECT_0 0
261 #define WAIT_FAILED ((DWORD)0xFFFFFFFF)
262 
263 DWORD WINAPI WaitForMultiObj_Any_Infinite(DWORD count, const CHandle_WFMO *handles);
264 
265 
266 struct CBaseHandle_WFMO  MY_UNCOPYABLE
267 {
268   CSynchro *_sync;
269 
CBaseHandle_WFMOMY_UNCOPYABLE270   CBaseHandle_WFMO(): _sync(NULL) {}
271 
CHandle_WFMOMY_UNCOPYABLE272   operator CHandle_WFMO() { return this; }
273   virtual bool IsSignaledAndUpdate() = 0;
274 };
275 
276 
277 class CBaseEvent_WFMO : public CBaseHandle_WFMO
278 {
279   bool _manual_reset;
280   bool _state;
281 
282 public:
283 
284   // bool IsCreated()  { return (this->_sync != NULL); }
285   // CBaseEvent_WFMO()  { ; }
~CBaseEvent_WFMO()286   ~CBaseEvent_WFMO() { Close(); }
287 
Close()288   WRes Close() { this->_sync = NULL; return 0; }
289 
Create(CSynchro * sync,bool manualReset,bool initiallyOwn)290   WRes Create(
291       CSynchro *sync,
292       bool manualReset, bool initiallyOwn)
293   {
294     this->_sync         = sync;
295     this->_manual_reset = manualReset;
296     this->_state        = initiallyOwn;
297     return 0;
298   }
299 
Set()300   WRes Set()
301   {
302     RINOK(this->_sync->Enter());
303     this->_state = true;
304     return this->_sync->LeaveAndSignal();
305   }
306 
Reset()307   WRes Reset()
308   {
309     RINOK(this->_sync->Enter());
310     this->_state = false;
311     return this->_sync->Leave();
312   }
313 
IsSignaledAndUpdate()314   virtual bool IsSignaledAndUpdate()
315   {
316     if (this->_state == false)
317       return false;
318     if (this->_manual_reset == false)
319       this->_state = false;
320     return true;
321   }
322 };
323 
324 
325 class CManualResetEvent_WFMO: public CBaseEvent_WFMO
326 {
327 public:
328   WRes Create(CSynchro *sync, bool initiallyOwn = false) { return CBaseEvent_WFMO::Create(sync, true, initiallyOwn); }
329 };
330 
331 
332 class CAutoResetEvent_WFMO: public CBaseEvent_WFMO
333 {
334 public:
Create(CSynchro * sync)335   WRes Create(CSynchro *sync) { return CBaseEvent_WFMO::Create(sync, false, false); }
CreateIfNotCreated_Reset(CSynchro * sync)336   WRes CreateIfNotCreated_Reset(CSynchro *sync)
337   {
338     return Create(sync);
339   }
340 };
341 
342 
343 class CSemaphore_WFMO : public CBaseHandle_WFMO
344 {
345   UInt32 _count;
346   UInt32 _maxCount;
347 
348 public:
CSemaphore_WFMO()349   CSemaphore_WFMO() : _count(0), _maxCount(0) {}
350 
Close()351   WRes Close() { this->_sync = NULL; return 0; }
352 
Create(CSynchro * sync,UInt32 initCount,UInt32 maxCount)353   WRes Create(CSynchro *sync, UInt32 initCount, UInt32 maxCount)
354   {
355     if (initCount > maxCount || maxCount < 1)
356       return EINVAL;
357     this->_sync     = sync;
358     this->_count    = initCount;
359     this->_maxCount = maxCount;
360     return 0;
361   }
362 
363   WRes Release(UInt32 releaseCount = 1)
364   {
365     if (releaseCount < 1)
366       return EINVAL;
367 
368     RINOK(this->_sync->Enter());
369     UInt32 newCount = this->_count + releaseCount;
370     if (newCount > this->_maxCount)
371     {
372       RINOK(this->_sync->Leave());
373       return ERROR_TOO_MANY_POSTS; // EINVAL
374     }
375     this->_count = newCount;
376 
377     return this->_sync->LeaveAndSignal();
378   }
379 
IsSignaledAndUpdate()380   virtual bool IsSignaledAndUpdate()
381   {
382     if (this->_count == 0)
383       return false;
384     this->_count--;
385     return true;
386   }
387 };
388 
389 #endif // _WIN32
390 
391 }}
392 
393 #endif
394