1// Windows/Synchronization.h
2
3#ifndef ZIP7_INC_WINDOWS_SYNCHRONIZATION_H
4#define ZIP7_INC_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
16namespace NWindows {
17namespace NSynchronization {
18
19class CBaseEvent  MY_UNCOPYABLE
20{
21protected:
22  ::CEvent _object;
23public:
24  bool IsCreated() { return Event_IsCreated(&_object) != 0; }
25
26  CBaseEvent() { Event_Construct(&_object); }
27  ~CBaseEvent() { Close(); }
28  WRes Close() { return Event_Close(&_object); }
29
30  #ifdef _WIN32
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 != NULL)
36      return 0;
37    return ::GetLastError();
38  }
39  WRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name)
40  {
41    _object = ::OpenEvent(desiredAccess, BoolToBOOL(inheritHandle), name);
42    if (_object != NULL)
43      return 0;
44    return ::GetLastError();
45  }
46  #endif
47
48  WRes Set() { return Event_Set(&_object); }
49  // bool Pulse() { return BOOLToBool(::PulseEvent(_handle)); }
50  WRes Reset() { return Event_Reset(&_object); }
51  WRes Lock() { return Event_Wait(&_object); }
52};
53
54class CManualResetEvent: public CBaseEvent
55{
56public:
57  WRes Create(bool initiallyOwn = false)
58  {
59    return ManualResetEvent_Create(&_object, initiallyOwn ? 1: 0);
60  }
61  WRes CreateIfNotCreated_Reset()
62  {
63    if (IsCreated())
64      return Reset();
65    return ManualResetEvent_CreateNotSignaled(&_object);
66  }
67  #ifdef _WIN32
68  WRes CreateWithName(bool initiallyOwn, LPCTSTR name)
69  {
70    return CBaseEvent::Create(true, initiallyOwn, name);
71  }
72  #endif
73};
74
75class CAutoResetEvent: public CBaseEvent
76{
77public:
78  WRes Create()
79  {
80    return AutoResetEvent_CreateNotSignaled(&_object);
81  }
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
94class CObject: public CHandle
95{
96public:
97  WRes Lock(DWORD timeoutInterval = INFINITE)
98    { return (::WaitForSingleObject(_handle, timeoutInterval) == WAIT_OBJECT_0 ? 0 : ::GetLastError()); }
99};
100
101class CMutex: public CObject
102{
103public:
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
126class CMutexLock  MY_UNCOPYABLE
127{
128  CMutex *_object;
129public:
130  CMutexLock(CMutex &object): _object(&object) { _object->Lock(); }
131  ~CMutexLock() { _object->Release(); }
132};
133
134#endif // _WIN32
135*/
136
137
138class CSemaphore  MY_UNCOPYABLE
139{
140  ::CSemaphore _object;
141public:
142  CSemaphore() { Semaphore_Construct(&_object); }
143  ~CSemaphore() { Close(); }
144  WRes Close() { return Semaphore_Close(&_object); }
145
146  #ifdef _WIN32
147  operator HANDLE() { return _object; }
148  #endif
149
150  // bool IsCreated() const { return Semaphore_IsCreated(&_object) != 0; }
151
152  WRes Create(UInt32 initCount, UInt32 maxCount)
153  {
154    return Semaphore_Create(&_object, initCount, maxCount);
155  }
156  WRes OptCreateInit(UInt32 initCount, UInt32 maxCount)
157  {
158    return Semaphore_OptCreateInit(&_object, initCount, maxCount);
159  }
160  WRes Release() { return Semaphore_Release1(&_object); }
161  WRes Release(UInt32 releaseCount) { return Semaphore_ReleaseN(&_object, releaseCount); }
162  WRes Lock() { return Semaphore_Wait(&_object); }
163};
164
165class CCriticalSection  MY_UNCOPYABLE
166{
167  ::CCriticalSection _object;
168public:
169  CCriticalSection() { CriticalSection_Init(&_object); }
170  ~CCriticalSection() { CriticalSection_Delete(&_object); }
171  void Enter() { CriticalSection_Enter(&_object); }
172  void Leave() { CriticalSection_Leave(&_object); }
173};
174
175class CCriticalSectionLock  MY_UNCOPYABLE
176{
177  CCriticalSection *_object;
178  void Unlock()  { _object->Leave(); }
179public:
180  CCriticalSectionLock(CCriticalSection &object): _object(&object) {_object->Enter(); }
181  ~CCriticalSectionLock() { Unlock(); }
182};
183
184
185#ifdef _WIN32
186
187typedef HANDLE CHandle_WFMO;
188typedef CSemaphore CSemaphore_WFMO;
189typedef CAutoResetEvent CAutoResetEvent_WFMO;
190typedef CManualResetEvent CManualResetEvent_WFMO;
191
192inline 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
211class CSynchro  MY_UNCOPYABLE
212{
213  pthread_mutex_t _mutex;
214  pthread_cond_t _cond;
215  bool _isValid;
216
217public:
218  CSynchro() { _isValid = false; }
219  ~CSynchro()
220  {
221    if (_isValid)
222    {
223      ::pthread_mutex_destroy(&_mutex);
224      ::pthread_cond_destroy(&_cond);
225    }
226    _isValid = false;
227  }
228  WRes Create()
229  {
230    RINOK(::pthread_mutex_init(&_mutex, NULL))
231    const WRes ret = ::pthread_cond_init(&_cond, NULL);
232    _isValid = 1;
233    return ret;
234  }
235  WRes Enter()
236  {
237    return ::pthread_mutex_lock(&_mutex);
238  }
239  WRes Leave()
240  {
241    return ::pthread_mutex_unlock(&_mutex);
242  }
243  WRes WaitCond()
244  {
245    return ::pthread_cond_wait(&_cond, &_mutex);
246  }
247  WRes LeaveAndSignal()
248  {
249    const WRes res1 = ::pthread_cond_broadcast(&_cond);
250    const WRes res2 = ::pthread_mutex_unlock(&_mutex);
251    return (res2 ? res2 : res1);
252  }
253};
254
255
256struct CBaseHandle_WFMO;
257typedef 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
263DWORD WINAPI WaitForMultiObj_Any_Infinite(DWORD count, const CHandle_WFMO *handles);
264
265
266struct CBaseHandle_WFMO  MY_UNCOPYABLE
267{
268  CSynchro *_sync;
269
270  CBaseHandle_WFMO(): _sync(NULL) {}
271  virtual ~CBaseHandle_WFMO();
272
273  operator CHandle_WFMO() { return this; }
274  virtual bool IsSignaledAndUpdate() = 0;
275};
276
277
278class CBaseEvent_WFMO : public CBaseHandle_WFMO
279{
280  bool _manual_reset;
281  bool _state;
282
283public:
284
285  // bool IsCreated()  { return (this->_sync != NULL); }
286  // CBaseEvent_WFMO()  { ; }
287  // ~CBaseEvent_WFMO() Z7_override { Close(); }
288
289  WRes Close() { this->_sync = NULL; return 0; }
290
291  WRes Create(
292      CSynchro *sync,
293      bool manualReset, bool initiallyOwn)
294  {
295    this->_sync         = sync;
296    this->_manual_reset = manualReset;
297    this->_state        = initiallyOwn;
298    return 0;
299  }
300
301  WRes Set()
302  {
303    RINOK(this->_sync->Enter())
304    this->_state = true;
305    return this->_sync->LeaveAndSignal();
306  }
307
308  WRes Reset()
309  {
310    RINOK(this->_sync->Enter())
311    this->_state = false;
312    return this->_sync->Leave();
313  }
314
315  virtual bool IsSignaledAndUpdate() Z7_override;
316};
317
318
319class CManualResetEvent_WFMO Z7_final: public CBaseEvent_WFMO
320{
321public:
322  WRes Create(CSynchro *sync, bool initiallyOwn = false) { return CBaseEvent_WFMO::Create(sync, true, initiallyOwn); }
323};
324
325
326class CAutoResetEvent_WFMO Z7_final: public CBaseEvent_WFMO
327{
328public:
329  WRes Create(CSynchro *sync) { return CBaseEvent_WFMO::Create(sync, false, false); }
330  WRes CreateIfNotCreated_Reset(CSynchro *sync)
331  {
332    return Create(sync);
333  }
334};
335
336
337class CSemaphore_WFMO Z7_final: public CBaseHandle_WFMO
338{
339  UInt32 _count;
340  UInt32 _maxCount;
341
342public:
343  CSemaphore_WFMO() : _count(0), _maxCount(0) {}
344
345  WRes Close() { this->_sync = NULL; return 0; }
346
347  WRes Create(CSynchro *sync, UInt32 initCount, UInt32 maxCount)
348  {
349    if (initCount > maxCount || maxCount < 1)
350      return EINVAL;
351    this->_sync     = sync;
352    this->_count    = initCount;
353    this->_maxCount = maxCount;
354    return 0;
355  }
356
357  WRes Release(UInt32 releaseCount = 1)
358  {
359    if (releaseCount < 1)
360      return EINVAL;
361
362    RINOK(this->_sync->Enter())
363    UInt32 newCount = this->_count + releaseCount;
364    if (newCount > this->_maxCount)
365    {
366      RINOK(this->_sync->Leave())
367      return ERROR_TOO_MANY_POSTS; // EINVAL
368    }
369    this->_count = newCount;
370
371    return this->_sync->LeaveAndSignal();
372  }
373
374  virtual bool IsSignaledAndUpdate() Z7_override;
375};
376
377#endif // _WIN32
378
379}}
380
381#endif
382