CppCommon 1.0.5.0
C++ Common Library
Loading...
Searching...
No Matches
event_auto_reset.cpp
Go to the documentation of this file.
1
10
11#include "errors/fatal.h"
13
14#include <algorithm>
15
16#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
17#include <pthread.h>
18#elif defined(_WIN32) || defined(_WIN64)
19#include <windows.h>
20#undef max
21#undef min
22#endif
23
24namespace CppCommon {
25
27
28class EventAutoReset::Impl
29{
30public:
31 Impl(bool signaled)
32 {
33#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
34 int result = pthread_mutex_init(&_mutex, nullptr);
35 if (result != 0)
36 throwex SystemException("Failed to initialize a mutex for the auto-reset event!", result);
37 result = pthread_cond_init(&_cond, nullptr);
38 if (result != 0)
39 throwex SystemException("Failed to initialize a conditional variable for the auto-reset event!", result);
40 _signaled = signaled ? 1 : 0;
41#elif defined(_WIN32) || defined(_WIN64)
42 _event = CreateEvent(nullptr, FALSE, signaled ? TRUE : FALSE, nullptr);
43 if (_event == nullptr)
44 throwex SystemException("Failed to create an auto-reset event!");
45#endif
46 }
47
48 ~Impl()
49 {
50#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
51 int result = pthread_mutex_destroy(&_mutex);
52 if (result != 0)
53 fatality(SystemException("Failed to destroy a mutex for the auto-reset event!", result));
54 result = pthread_cond_destroy(&_cond);
55 if (result != 0)
56 fatality(SystemException("Failed to destroy a conditional variable for the auto-reset event!", result));
57#elif defined(_WIN32) || defined(_WIN64)
58 if (!CloseHandle(_event))
59 fatality(SystemException("Failed to close an auto-reset event!"));
60#endif
61 }
62
63 void Signal()
64 {
65#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
66 int result = pthread_mutex_lock(&_mutex);
67 if (result != 0)
68 throwex SystemException("Failed to lock a mutex for the auto-reset event!", result);
69 ++_signaled;
70 result = pthread_mutex_unlock(&_mutex);
71 if (result != 0)
72 throwex SystemException("Failed to unlock a mutex for the auto-reset event!", result);
73 result = pthread_cond_signal(&_cond);
74 if (result != 0)
75 throwex SystemException("Failed to signal an auto-reset event!", result);
76#elif defined(_WIN32) || defined(_WIN64)
77 if (!SetEvent(_event))
78 throwex SystemException("Failed to signal an auto-reset event!");
79#endif
80 }
81
82 bool TryWait()
83 {
84#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
85 int result = pthread_mutex_lock(&_mutex);
86 if (result != 0)
87 throwex SystemException("Failed to lock a mutex for the auto-reset event!", result);
88 bool signaled = (_signaled-- > 0);
89 _signaled = (_signaled < 0) ? 0 : _signaled;
90 result = pthread_mutex_unlock(&_mutex);
91 if (result != 0)
92 throwex SystemException("Failed to unlock a mutex for the auto-reset event!", result);
93 return signaled;
94#elif defined(_WIN32) || defined(_WIN64)
95 DWORD result = WaitForSingleObject(_event, 0);
96 if ((result != WAIT_OBJECT_0) && (result != WAIT_TIMEOUT))
97 throwex SystemException("Failed to try lock an auto-reset event!");
98 return (result == WAIT_OBJECT_0);
99#endif
100 }
101
102 bool TryWaitFor(const Timespan& timespan)
103 {
104 if (timespan < 0)
105 return TryWait();
106#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
107 struct timespec timeout;
108 timeout.tv_sec = timespan.seconds();
109 timeout.tv_nsec = timespan.nanoseconds() % 1000000000;
110 int result = pthread_mutex_lock(&_mutex);
111 if (result != 0)
112 throwex SystemException("Failed to lock a mutex for the auto-reset event!", result);
113 bool signaled = true;
114 while (!_signaled)
115 {
116 result = pthread_cond_timedwait(&_cond, &_mutex, &timeout);
117 if ((result != 0) && (result != ETIMEDOUT))
118 throwex SystemException("Failed to timeout waiting a conditional variable for the auto-reset event!", result);
119 if (result == ETIMEDOUT)
120 signaled = (_signaled > 0);
121 }
122 _signaled = (_signaled > 0) ? (_signaled - 1) : 0;
123 result = pthread_mutex_unlock(&_mutex);
124 if (result != 0)
125 throwex SystemException("Failed to unlock a mutex for the auto-reset event!", result);
126 return signaled;
127#elif defined(_WIN32) || defined(_WIN64)
128 DWORD result = WaitForSingleObject(_event, std::max((DWORD)1, (DWORD)timespan.milliseconds()));
129 if ((result != WAIT_OBJECT_0) && (result != WAIT_TIMEOUT))
130 throwex SystemException("Failed to try lock an auto-reset event for the given timeout!");
131 return (result == WAIT_OBJECT_0);
132#endif
133 }
134
135 void Wait()
136 {
137#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
138 int result = pthread_mutex_lock(&_mutex);
139 if (result != 0)
140 throwex SystemException("Failed to lock a mutex for the auto-reset event!", result);
141 while (!_signaled)
142 {
143 result = pthread_cond_wait(&_cond, &_mutex);
144 if (result != 0)
145 throwex SystemException("Failed to waiting a conditional variable for the auto-reset event!", result);
146 }
147 _signaled = (_signaled > 0) ? (_signaled - 1) : 0;
148 result = pthread_mutex_unlock(&_mutex);
149 if (result != 0)
150 throwex SystemException("Failed to unlock a mutex for the auto-reset event!", result);
151#elif defined(_WIN32) || defined(_WIN64)
152 DWORD result = WaitForSingleObject(_event, INFINITE);
153 if (result != WAIT_OBJECT_0)
154 throwex SystemException("Failed to lock an auto-reset event!");
155#endif
156 }
157
158private:
159#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
160 pthread_mutex_t _mutex;
161 pthread_cond_t _cond;
162 int _signaled;
163#elif defined(_WIN32) || defined(_WIN64)
164 HANDLE _event;
165#endif
166};
167
169
171{
172 // Check implementation storage parameters
173 [[maybe_unused]] ValidateAlignedStorage<sizeof(Impl), alignof(Impl), StorageSize, StorageAlign> _;
174 static_assert((StorageSize >= sizeof(Impl)), "EventAutoReset::StorageSize must be increased!");
175 static_assert(((StorageAlign % alignof(Impl)) == 0), "EventAutoReset::StorageAlign must be adjusted!");
176
177 // Create the implementation instance
178 new(&_storage)Impl(signaled);
179}
180
182{
183 // Delete the implementation instance
184 reinterpret_cast<Impl*>(&_storage)->~Impl();
185}
186
187void EventAutoReset::Signal() { impl().Signal(); }
188
189bool EventAutoReset::TryWait() { return impl().TryWait(); }
190bool EventAutoReset::TryWaitFor(const Timespan& timespan) { return impl().TryWaitFor(timespan); }
191
192void EventAutoReset::Wait() { impl().Wait(); }
193
194} // namespace CppCommon
bool TryWait()
Try to wait the event without block.
void Wait()
Try to wait the event with block.
void Signal()
Signal one of waiting thread about event occurred.
EventAutoReset(bool signaled=false)
Default class constructor.
bool TryWaitFor(const Timespan &timespan)
Try to wait the event for the given timespan.
#define throwex
Throw extended exception macro.
Definition exceptions.h:23
Auto-reset event synchronization primitive definition.
Fatal abort execution definition.
#define fatality(...)
Fatal abort execution extended macro.
Definition fatal.h:22
C++ Common project definitions.
Aligned storage validator definition.