CppCommon  1.0.4.1
C++ Common Library
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 
25 namespace CppCommon {
26 
28 
29 class NamedEventAutoReset::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 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 
209 private:
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 
229 NamedEventAutoReset::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 
246 const std::string& NamedEventAutoReset::name() const { return impl().name(); }
247 
248 void NamedEventAutoReset::Signal() { impl().Signal(); }
249 
250 bool NamedEventAutoReset::TryWait() { return impl().TryWait(); }
251 bool NamedEventAutoReset::TryWaitFor(const Timespan& timespan) { return impl().TryWaitFor(timespan); }
252 
253 void 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.
Definition: token_bucket.h:15
Shared memory type definition.
Aligned storage validator definition.