CppCommon  1.0.4.1
C++ Common Library
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 
24 namespace CppCommon {
25 
27 
28 class EventAutoReset::Impl
29 {
30 public:
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 
158 private:
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 
187 void EventAutoReset::Signal() { impl().Signal(); }
188 
189 bool EventAutoReset::TryWait() { return impl().TryWait(); }
190 bool EventAutoReset::TryWaitFor(const Timespan& timespan) { return impl().TryWaitFor(timespan); }
191 
192 void 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.
Definition: token_bucket.h:15
Aligned storage validator definition.