CppCommon  1.0.4.1
C++ Common Library
named_event_manual_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 
25 namespace CppCommon {
26 
28 
29 class NamedEventManualReset::Impl
30 {
31 public:
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 manual-reset event is not supported!");
39 #elif (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__CYGWIN__)
40  // Only the owner should initializate a named manual-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 manual-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 manual-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 manual-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 manual-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 manual-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 manual-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 manual-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 manual-reset event!", result);
70 
71  _shared->signaled = signaled;
72  }
73 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
74  _event = CreateEventA(nullptr, TRUE, signaled ? TRUE : FALSE, name.c_str());
75  if (_event == nullptr)
76  throwex SystemException("Failed to create or open a named manual-reset event!");
77 #endif
78  }
79 
80  ~Impl()
81  {
82 #if defined(__APPLE__)
83  fatality(SystemException("Named manual-reset event is not supported!"));
84 #elif (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__CYGWIN__)
85  // Only the owner should destroy a named manual-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 manual-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 manual-reset event!", result));
94  }
95 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
96  if (!CloseHandle(_event))
97  fatality(SystemException("Failed to close a named manual-reset event!"));
98 #endif
99  }
100 
101  const std::string& name() const
102  {
103  return _name;
104  }
105 
106  void Reset()
107  {
108 #if defined(__APPLE__)
109  throwex SystemException("Named manual-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 manual-reset event!", result);
114  _shared->signaled = false;
115  result = pthread_mutex_unlock(&_shared->mutex);
116  if (result != 0)
117  throwex SystemException("Failed to unlock a mutex for the named manual-reset event!", result);
118 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
119  if (!ResetEvent(_event))
120  throwex SystemException("Failed to reset a named manual-reset event!");
121 #endif
122  }
123 
124  void Signal()
125  {
126 #if defined(__APPLE__)
127  throwex SystemException("Named manual-reset event is not supported!");
128 #elif (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__CYGWIN__)
129  int result = pthread_mutex_lock(&_shared->mutex);
130  if (result != 0)
131  throwex SystemException("Failed to lock a mutex for the named manual-reset event!", result);
132  _shared->signaled = true;
133  result = pthread_mutex_unlock(&_shared->mutex);
134  if (result != 0)
135  throwex SystemException("Failed to unlock a mutex for the named manual-reset event!", result);
136  result = pthread_cond_broadcast(&_shared->cond);
137  if (result != 0)
138  throwex SystemException("Failed to signal an named manual-reset event!", result);
139 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
140  if (!SetEvent(_event))
141  throwex SystemException("Failed to signal a named manual-reset event!");
142 #endif
143  }
144 
145  bool TryWait()
146  {
147 #if defined(__APPLE__)
148  throwex SystemException("Named manual-reset event is not supported!");
149 #elif (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__CYGWIN__)
150  int result = pthread_mutex_lock(&_shared->mutex);
151  if (result != 0)
152  throwex SystemException("Failed to lock a mutex for the named manual-reset event!", result);
153  bool signaled = _shared->signaled;
154  result = pthread_mutex_unlock(&_shared->mutex);
155  if (result != 0)
156  throwex SystemException("Failed to unlock a mutex for the named manual-reset event!", result);
157  return signaled;
158 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
159  DWORD result = WaitForSingleObject(_event, 0);
160  if ((result != WAIT_OBJECT_0) && (result != WAIT_TIMEOUT))
161  throwex SystemException("Failed to try lock a named manual-reset event!");
162  return (result == WAIT_OBJECT_0);
163 #endif
164  }
165 
166  bool TryWaitFor(const Timespan& timespan)
167  {
168  if (timespan < 0)
169  return TryWait();
170 #if defined(__APPLE__)
171  throwex SystemException("Named manual-reset event is not supported!");
172 #elif (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__CYGWIN__)
173  struct timespec timeout;
174  timeout.tv_sec = timespan.seconds();
175  timeout.tv_nsec = timespan.nanoseconds() % 1000000000;
176  int result = pthread_mutex_lock(&_shared->mutex);
177  if (result != 0)
178  throwex SystemException("Failed to lock a mutex for the named manual-reset event!", result);
179  bool signaled = true;
180  while (!_shared->signaled)
181  {
182  result = pthread_cond_timedwait(&_shared->cond, &_shared->mutex, &timeout);
183  if ((result != 0) && (result != ETIMEDOUT))
184  throwex SystemException("Failed to timeout waiting a conditional variable for the named manual-reset event!", result);
185  if (result == ETIMEDOUT)
186  signaled = _shared->signaled;
187  }
188  result = pthread_mutex_unlock(&_shared->mutex);
189  if (result != 0)
190  throwex SystemException("Failed to unlock a mutex for the named manual-reset event!", result);
191  return signaled;
192 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
193  DWORD result = WaitForSingleObject(_event, std::max((DWORD)1, (DWORD)timespan.milliseconds()));
194  if ((result != WAIT_OBJECT_0) && (result != WAIT_TIMEOUT))
195  throwex SystemException("Failed to try lock a named manual-reset event for the given timeout!");
196  return (result == WAIT_OBJECT_0);
197 #endif
198  }
199 
200  void Wait()
201  {
202 #if defined(__APPLE__)
203  throwex SystemException("Named manual-reset event is not supported!");
204 #elif (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__CYGWIN__)
205  int result = pthread_mutex_lock(&_shared->mutex);
206  if (result != 0)
207  throwex SystemException("Failed to lock a mutex for the named manual-reset event!", result);
208  while (!_shared->signaled)
209  {
210  result = pthread_cond_wait(&_shared->cond, &_shared->mutex);
211  if (result != 0)
212  throwex SystemException("Failed to waiting a conditional variable for the named manual-reset event!", result);
213  }
214  result = pthread_mutex_unlock(&_shared->mutex);
215  if (result != 0)
216  throwex SystemException("Failed to unlock a mutex for the named manual-reset event!", result);
217 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
218  DWORD result = WaitForSingleObject(_event, INFINITE);
219  if (result != WAIT_OBJECT_0)
220  throwex SystemException("Failed to lock a named manual-reset event!");
221 #endif
222  }
223 
224 private:
225  std::string _name;
226 #if (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__APPLE__) && !defined(__CYGWIN__)
227  // Shared manual-reset event structure
228  struct EventHeader
229  {
230  pthread_mutex_t mutex;
231  pthread_cond_t cond;
232  int signaled;
233  };
234 
235  // Shared manual-reset event structure wrapper
236  SharedType<EventHeader> _shared;
237 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
238  HANDLE _event;
239 #endif
240 };
241 
243 
244 NamedEventManualReset::NamedEventManualReset(const std::string& name, bool signaled)
245 {
246  // Check implementation storage parameters
247  [[maybe_unused]] ValidateAlignedStorage<sizeof(Impl), alignof(Impl), StorageSize, StorageAlign> _;
248  static_assert((StorageSize >= sizeof(Impl)), "NamedEventManualReset::StorageSize must be increased!");
249  static_assert(((StorageAlign % alignof(Impl)) == 0), "NamedEventManualReset::StorageAlign must be adjusted!");
250 
251  // Create the implementation instance
252  new(&_storage)Impl(name, signaled);
253 }
254 
256 {
257  // Delete the implementation instance
258  reinterpret_cast<Impl*>(&_storage)->~Impl();
259 }
260 
261 const std::string& NamedEventManualReset::name() const { return impl().name(); }
262 
263 void NamedEventManualReset::Reset() { impl().Reset(); }
264 void NamedEventManualReset::Signal() { impl().Signal(); }
265 
266 bool NamedEventManualReset::TryWait() { return impl().TryWait(); }
267 bool NamedEventManualReset::TryWaitFor(const Timespan& timespan) { return impl().TryWaitFor(timespan); }
268 
269 void NamedEventManualReset::Wait() { impl().Wait(); }
270 
271 } // namespace CppCommon
void Signal()
Signal one of waiting thread about event occurred.
const std::string & name() const
Get the event name.
void Wait()
Try to wait the event with block.
NamedEventManualReset(const std::string &name, bool signaled=false)
Default class constructor.
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 manual-reset event synchronization primitive definition.
C++ Common project definitions.
Definition: token_bucket.h:15
Shared memory type definition.
Aligned storage validator definition.