CppCommon 1.0.5.0
C++ Common Library
Loading...
Searching...
No Matches
named_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__) && !defined(__CYGWIN__)
17#include "system/shared_type.h"
18#include <pthread.h>
19#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
20#include <windows.h>
21#undef max
22#undef min
23#endif
24
25namespace CppCommon {
26
28
29class NamedEventAutoReset::Impl
30{
31public:
32 Impl(const std::string& name, bool signaled) : _name(name)
33#if (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__APPLE__) && !defined(__CYGWIN__)
34 , _shared(name)
35#endif
36 {
37#if defined(__APPLE__)
38 throwex SystemException("Named auto-reset event is not supported!");
39#elif (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__CYGWIN__)
40 // Only the owner should initializate a named auto-reset event
41 if (_shared.owner())
42 {
43 pthread_mutexattr_t mutex_attribute;
44 int result = pthread_mutexattr_init(&mutex_attribute);
45 if (result != 0)
46 throwex SystemException("Failed to initialize a mutex attribute for the named auto-reset event!", result);
47 result = pthread_mutexattr_setpshared(&mutex_attribute, PTHREAD_PROCESS_SHARED);
48 if (result != 0)
49 throwex SystemException("Failed to set a mutex process shared attribute for the named auto-reset event!", result);
50 result = pthread_mutex_init(&_shared->mutex, &mutex_attribute);
51 if (result != 0)
52 throwex SystemException("Failed to initialize a mutex for the named auto-reset event!", result);
53 result = pthread_mutexattr_destroy(&mutex_attribute);
54 if (result != 0)
55 throwex SystemException("Failed to destroy a mutex attribute for the named auto-reset event!", result);
56
57 pthread_condattr_t cond_attribute;
58 result = pthread_condattr_init(&cond_attribute);
59 if (result != 0)
60 throwex SystemException("Failed to initialize a conditional variable attribute for the named auto-reset event!", result);
61 result = pthread_condattr_setpshared(&cond_attribute, PTHREAD_PROCESS_SHARED);
62 if (result != 0)
63 throwex SystemException("Failed to set a conditional variable process shared attribute for the named auto-reset event!", result);
64 result = pthread_cond_init(&_shared->cond, &cond_attribute);
65 if (result != 0)
66 throwex SystemException("Failed to initialize a conditional variable for the named auto-reset event!", result);
67 result = pthread_condattr_destroy(&cond_attribute);
68 if (result != 0)
69 throwex SystemException("Failed to destroy a conditional variable attribute for the named auto-reset event!", result);
70
71 _shared->signaled = signaled ? 1 : 0;
72 }
73#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
74 _event = CreateEventA(nullptr, FALSE, signaled ? TRUE : FALSE, name.c_str());
75 if (_event == nullptr)
76 throwex SystemException("Failed to create or open a named auto-reset event!");
77#endif
78 }
79
80 ~Impl()
81 {
82#if defined(__APPLE__)
83 fatality(SystemException("Named auto-reset event is not supported!"));
84#elif (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__CYGWIN__)
85 // Only the owner should destroy a named auto-reset event
86 if (_shared.owner())
87 {
88 int result = pthread_mutex_destroy(&_shared->mutex);
89 if (result != 0)
90 fatality(SystemException("Failed to destroy a mutex for the named auto-reset event!", result));
91 result = pthread_cond_destroy(&_shared->cond);
92 if (result != 0)
93 fatality(SystemException("Failed to destroy a conditional variable for the named auto-reset event!", result));
94 }
95#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
96 if (!CloseHandle(_event))
97 fatality(SystemException("Failed to close a named auto-reset event!"));
98#endif
99 }
100
101 const std::string& name() const
102 {
103 return _name;
104 }
105
106 void Signal()
107 {
108#if defined(__APPLE__)
109 throwex SystemException("Named auto-reset event is not supported!");
110#elif (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__CYGWIN__)
111 int result = pthread_mutex_lock(&_shared->mutex);
112 if (result != 0)
113 throwex SystemException("Failed to lock a mutex for the named auto-reset event!", result);
114 ++_shared->signaled;
115 result = pthread_mutex_unlock(&_shared->mutex);
116 if (result != 0)
117 throwex SystemException("Failed to unlock a mutex for the named auto-reset event!", result);
118 result = pthread_cond_signal(&_shared->cond);
119 if (result != 0)
120 throwex SystemException("Failed to signal a named auto-reset event!", result);
121#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
122 if (!SetEvent(_event))
123 throwex SystemException("Failed to signal a named auto-reset event!");
124#endif
125 }
126
127 bool TryWait()
128 {
129#if defined(__APPLE__)
130 throwex SystemException("Named auto-reset event is not supported!");
131#elif (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__CYGWIN__)
132 int result = pthread_mutex_lock(&_shared->mutex);
133 if (result != 0)
134 throwex SystemException("Failed to lock a mutex for the named auto-reset event!", result);
135 bool signaled = (_shared->signaled-- > 0);
136 _shared->signaled = (_shared->signaled < 0) ? 0 : _shared->signaled;
137 result = pthread_mutex_unlock(&_shared->mutex);
138 if (result != 0)
139 throwex SystemException("Failed to unlock a mutex for the named auto-reset event!", result);
140 return signaled;
141#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
142 DWORD result = WaitForSingleObject(_event, 0);
143 if ((result != WAIT_OBJECT_0) && (result != WAIT_TIMEOUT))
144 throwex SystemException("Failed to try lock a named auto-reset event!");
145 return (result == WAIT_OBJECT_0);
146#endif
147 }
148
149 bool TryWaitFor(const Timespan& timespan)
150 {
151 if (timespan < 0)
152 return TryWait();
153#if defined(__APPLE__)
154 throwex SystemException("Named auto-reset event is not supported!");
155#elif (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__CYGWIN__)
156 struct timespec timeout;
157 timeout.tv_sec = timespan.seconds();
158 timeout.tv_nsec = timespan.nanoseconds() % 1000000000;
159 int result = pthread_mutex_lock(&_shared->mutex);
160 if (result != 0)
161 throwex SystemException("Failed to lock a mutex for the named auto-reset event!", result);
162 bool signaled = true;
163 while (!_shared->signaled)
164 {
165 result = pthread_cond_timedwait(&_shared->cond, &_shared->mutex, &timeout);
166 if ((result != 0) && (result != ETIMEDOUT))
167 throwex SystemException("Failed to timeout waiting a conditional variable for the named auto-reset event!", result);
168 if (result == ETIMEDOUT)
169 signaled = (_shared->signaled > 0);
170 }
171 _shared->signaled = (_shared->signaled > 0) ? (_shared->signaled - 1) : 0;
172 result = pthread_mutex_unlock(&_shared->mutex);
173 if (result != 0)
174 throwex SystemException("Failed to unlock a mutex for the named auto-reset event!", result);
175 return signaled;
176#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
177 DWORD result = WaitForSingleObject(_event, std::max((DWORD)1, (DWORD)timespan.milliseconds()));
178 if ((result != WAIT_OBJECT_0) && (result != WAIT_TIMEOUT))
179 throwex SystemException("Failed to try lock a named auto-reset event for the given timeout!");
180 return (result == WAIT_OBJECT_0);
181#endif
182 }
183
184 void Wait()
185 {
186#if defined(__APPLE__)
187 throwex SystemException("Named auto-reset event is not supported!");
188#elif (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__CYGWIN__)
189 int result = pthread_mutex_lock(&_shared->mutex);
190 if (result != 0)
191 throwex SystemException("Failed to lock a mutex for the named auto-reset event!", result);
192 while (!_shared->signaled)
193 {
194 result = pthread_cond_wait(&_shared->cond, &_shared->mutex);
195 if (result != 0)
196 throwex SystemException("Failed to waiting a conditional variable for the named auto-reset event!", result);
197 }
198 _shared->signaled = (_shared->signaled > 0) ? (_shared->signaled - 1) : 0;
199 result = pthread_mutex_unlock(&_shared->mutex);
200 if (result != 0)
201 throwex SystemException("Failed to unlock a mutex for the named auto-reset event!", result);
202#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
203 DWORD result = WaitForSingleObject(_event, INFINITE);
204 if (result != WAIT_OBJECT_0)
205 throwex SystemException("Failed to lock a named auto-reset event!");
206#endif
207 }
208
209private:
210 std::string _name;
211#if (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__APPLE__) && !defined(__CYGWIN__)
212 // Shared auto-reset event structure
213 struct EventHeader
214 {
215 pthread_mutex_t mutex;
216 pthread_cond_t cond;
217 int signaled;
218 };
219
220 // Shared auto-reset event structure wrapper
221 SharedType<EventHeader> _shared;
222#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
223 HANDLE _event;
224#endif
225};
226
228
229NamedEventAutoReset::NamedEventAutoReset(const std::string& name, bool signaled)
230{
231 // Check implementation storage parameters
232 [[maybe_unused]] ValidateAlignedStorage<sizeof(Impl), alignof(Impl), StorageSize, StorageAlign> _;
233 static_assert((StorageSize >= sizeof(Impl)), "NamedEventAutoReset::StorageSize must be increased!");
234 static_assert(((StorageAlign % alignof(Impl)) == 0), "NamedEventAutoReset::StorageAlign must be adjusted!");
235
236 // Create the implementation instance
237 new(&_storage)Impl(name, signaled);
238}
239
241{
242 // Delete the implementation instance
243 reinterpret_cast<Impl*>(&_storage)->~Impl();
244}
245
246const std::string& NamedEventAutoReset::name() const { return impl().name(); }
247
248void NamedEventAutoReset::Signal() { impl().Signal(); }
249
250bool NamedEventAutoReset::TryWait() { return impl().TryWait(); }
251bool NamedEventAutoReset::TryWaitFor(const Timespan& timespan) { return impl().TryWaitFor(timespan); }
252
253void NamedEventAutoReset::Wait() { impl().Wait(); }
254
255} // namespace CppCommon
const std::string & name() const
Get the event name.
void Wait()
Try to wait the event with block.
NamedEventAutoReset(const std::string &name, bool signaled=false)
Default class constructor.
void Signal()
Signal one of waiting thread about event occurred.
bool TryWait()
Try to wait the event without block.
bool TryWaitFor(const Timespan &timespan)
Try to wait the event for the given timespan.
#define throwex
Throw extended exception macro.
Definition exceptions.h:23
Fatal abort execution definition.
#define fatality(...)
Fatal abort execution extended macro.
Definition fatal.h:22
Named auto-reset event synchronization primitive definition.
C++ Common project definitions.
Shared memory type definition.
Aligned storage validator definition.