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
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 != NULL)
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 != NULL)
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, NULL))
231 const WRes ret = ::pthread_cond_init(&_cond, NULL);
232 _isValid = 1;
233 return ret;
234 }
Enter()235 WRes Enter()
236 {
237 #if defined(Z7_LLVM_CLANG_VERSION) && (__clang_major__ == 13) \
238 && defined(__FreeBSD__)
239 #pragma GCC diagnostic ignored "-Wthread-safety-negative"
240 #pragma GCC diagnostic ignored "-Wthread-safety-analysis"
241 #endif
242 return ::pthread_mutex_lock(&_mutex);
243 }
Leave()244 WRes Leave()
245 {
246 return ::pthread_mutex_unlock(&_mutex);
247 }
WaitCond()248 WRes WaitCond()
249 {
250 return ::pthread_cond_wait(&_cond, &_mutex);
251 }
LeaveAndSignal()252 WRes LeaveAndSignal()
253 {
254 const WRes res1 = ::pthread_cond_broadcast(&_cond);
255 const WRes res2 = ::pthread_mutex_unlock(&_mutex);
256 return (res2 ? res2 : res1);
257 }
258 };
259
260
261 struct CBaseHandle_WFMO;
262 typedef NWindows::NSynchronization::CBaseHandle_WFMO *CHandle_WFMO;
263
264 // these constants are from Windows
265 #define WAIT_OBJECT_0 0
266 #define WAIT_FAILED ((DWORD)0xFFFFFFFF)
267
268 DWORD WINAPI WaitForMultiObj_Any_Infinite(DWORD count, const CHandle_WFMO *handles);
269
270
271 struct CBaseHandle_WFMO MY_UNCOPYABLE
272 {
273 CSynchro *_sync;
274
CBaseHandle_WFMOMY_UNCOPYABLE275 CBaseHandle_WFMO(): _sync(NULL) {}
276 virtual ~CBaseHandle_WFMO();
277
CHandle_WFMOMY_UNCOPYABLE278 operator CHandle_WFMO() { return this; }
279 virtual bool IsSignaledAndUpdate() = 0;
280 };
281
282
283 class CBaseEvent_WFMO : public CBaseHandle_WFMO
284 {
285 bool _manual_reset;
286 bool _state;
287
288 public:
289
290 // bool IsCreated() { return (this->_sync != NULL); }
291 // CBaseEvent_WFMO() { ; }
292 // ~CBaseEvent_WFMO() Z7_override { Close(); }
293
Close()294 WRes Close() { this->_sync = NULL; return 0; }
295
Create(CSynchro * sync,bool manualReset,bool initiallyOwn)296 WRes Create(
297 CSynchro *sync,
298 bool manualReset, bool initiallyOwn)
299 {
300 this->_sync = sync;
301 this->_manual_reset = manualReset;
302 this->_state = initiallyOwn;
303 return 0;
304 }
305
Set()306 WRes Set()
307 {
308 RINOK(this->_sync->Enter())
309 this->_state = true;
310 return this->_sync->LeaveAndSignal();
311 }
312
Reset()313 WRes Reset()
314 {
315 RINOK(this->_sync->Enter())
316 this->_state = false;
317 return this->_sync->Leave();
318 }
319
320 virtual bool IsSignaledAndUpdate() Z7_override;
321 };
322
323
324 class CManualResetEvent_WFMO Z7_final: public CBaseEvent_WFMO
325 {
326 public:
327 WRes Create(CSynchro *sync, bool initiallyOwn = false) { return CBaseEvent_WFMO::Create(sync, true, initiallyOwn); }
328 };
329
330
331 class CAutoResetEvent_WFMO Z7_final: public CBaseEvent_WFMO
332 {
333 public:
Create(CSynchro * sync)334 WRes Create(CSynchro *sync) { return CBaseEvent_WFMO::Create(sync, false, false); }
CreateIfNotCreated_Reset(CSynchro * sync)335 WRes CreateIfNotCreated_Reset(CSynchro *sync)
336 {
337 return Create(sync);
338 }
339 };
340
341
342 class CSemaphore_WFMO Z7_final: public CBaseHandle_WFMO
343 {
344 UInt32 _count;
345 UInt32 _maxCount;
346
347 public:
CSemaphore_WFMO()348 CSemaphore_WFMO() : _count(0), _maxCount(0) {}
349
Close()350 WRes Close() { this->_sync = NULL; return 0; }
351
Create(CSynchro * sync,UInt32 initCount,UInt32 maxCount)352 WRes Create(CSynchro *sync, UInt32 initCount, UInt32 maxCount)
353 {
354 if (initCount > maxCount || maxCount < 1)
355 return EINVAL;
356 this->_sync = sync;
357 this->_count = initCount;
358 this->_maxCount = maxCount;
359 return 0;
360 }
361
362 WRes Release(UInt32 releaseCount = 1)
363 {
364 if (releaseCount < 1)
365 return EINVAL;
366
367 RINOK(this->_sync->Enter())
368 UInt32 newCount = this->_count + releaseCount;
369 if (newCount > this->_maxCount)
370 {
371 RINOK(this->_sync->Leave())
372 return ERROR_TOO_MANY_POSTS; // EINVAL
373 }
374 this->_count = newCount;
375
376 return this->_sync->LeaveAndSignal();
377 }
378
379 virtual bool IsSignaledAndUpdate() Z7_override;
380 };
381
382 #endif // _WIN32
383
384 }}
385
386 #endif
387