CppCommon  1.0.4.1
C++ Common Library
semaphore.cpp
Go to the documentation of this file.
1 
9 #include "threads/semaphore.h"
10 
11 #include "errors/fatal.h"
13 
14 #include <algorithm>
15 #include <cassert>
16 
17 #if defined(__APPLE__)
18 #include <dispatch/dispatch.h>
19 #elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
20 #include <fcntl.h>
21 #include <semaphore.h>
22 #elif defined(_WIN32) || defined(_WIN64)
23 #include <windows.h>
24 #undef max
25 #undef min
26 #endif
27 
28 namespace CppCommon {
29 
31 
32 class Semaphore::Impl
33 {
34 public:
35  explicit Impl(int resources) : _resources(resources)
36  {
37  assert((resources > 0) && "Semaphore resources counter must be greater than zero!");
38 
39 #if defined(__APPLE__)
40  _semaphore = dispatch_semaphore_create(resources);
41  if (_semaphore == nullptr)
42  throwex SystemException("Failed to initialize a semaphore!");
43 #elif defined(unix) || defined(__unix) || defined(__unix__)
44  int result = sem_init(&_semaphore, 0, resources);
45  if (result != 0)
46  throwex SystemException("Failed to initialize a semaphore!");
47 #elif defined(_WIN32) || defined(_WIN64)
48  _semaphore = CreateSemaphore(nullptr, resources, resources, nullptr);
49  if (_semaphore == nullptr)
50  throwex SystemException("Failed to create a semaphore!");
51 #endif
52  }
53 
54  ~Impl()
55  {
56 #if defined(__APPLE__)
57  if (_semaphore != nullptr)
58  dispatch_release(_semaphore);
59 #elif defined(unix) || defined(__unix) || defined(__unix__)
60  int result = sem_destroy(&_semaphore);
61  if (result != 0)
62  fatality(SystemException("Failed to destroy a semaphore!"));
63 #elif defined(_WIN32) || defined(_WIN64)
64  if (!CloseHandle(_semaphore))
65  fatality(SystemException("Failed to close a semaphore!"));
66 #endif
67  }
68 
69  int resources() const noexcept
70  {
71  return _resources;
72  }
73 
74  bool TryLock()
75  {
76 #if defined(__APPLE__)
77  return (dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_NOW) == 0);
78 #elif defined(unix) || defined(__unix) || defined(__unix__)
79  int result = sem_trywait(&_semaphore);
80  if ((result != 0) && (errno != EAGAIN))
81  throwex SystemException("Failed to try lock a semaphore!");
82  return (result == 0);
83 #elif defined(_WIN32) || defined(_WIN64)
84  DWORD result = WaitForSingleObject(_semaphore, 0);
85  if ((result != WAIT_OBJECT_0) && (result != WAIT_TIMEOUT))
86  throwex SystemException("Failed to try lock a semaphore!");
87  return (result == WAIT_OBJECT_0);
88 #endif
89  }
90 
91  bool TryLockFor(const Timespan& timespan)
92  {
93  if (timespan < 0)
94  return TryLock();
95 #if defined(__APPLE__)
96  dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, timespan.nanoseconds());
97  return (dispatch_semaphore_wait(_semaphore, timeout) == 0);
98 #elif defined(unix) || defined(__unix) || defined(__unix__)
99  struct timespec timeout;
100  timeout.tv_sec = timespan.seconds();
101  timeout.tv_nsec = timespan.nanoseconds() % 1000000000;
102  int result = sem_timedwait(&_semaphore, &timeout);
103  if ((result != 0) && (errno != ETIMEDOUT))
104  throwex SystemException("Failed to try lock a semaphore for the given timeout!");
105  return (result == 0);
106 #elif defined(_WIN32) || defined(_WIN64)
107  DWORD result = WaitForSingleObject(_semaphore, std::max((DWORD)1, (DWORD)timespan.milliseconds()));
108  if ((result != WAIT_OBJECT_0) && (result != WAIT_TIMEOUT))
109  throwex SystemException("Failed to try lock a semaphore for the given timeout!");
110  return (result == WAIT_OBJECT_0);
111 #endif
112  }
113 
114  void Lock()
115  {
116 #if defined(__APPLE__)
117  dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);
118 #elif defined(unix) || defined(__unix) || defined(__unix__)
119  int result = sem_wait(&_semaphore);
120  if (result != 0)
121  throwex SystemException("Failed to lock a semaphore!");
122 #elif defined(_WIN32) || defined(_WIN64)
123  DWORD result = WaitForSingleObject(_semaphore, INFINITE);
124  if (result != WAIT_OBJECT_0)
125  throwex SystemException("Failed to lock a semaphore!");
126 #endif
127  }
128 
129  void Unlock()
130  {
131 #if defined(__APPLE__)
132  dispatch_semaphore_signal(_semaphore);
133 #elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
134  int result = sem_post(&_semaphore);
135  if (result != 0)
136  throwex SystemException("Failed to unlock a semaphore!");
137 #elif defined(_WIN32) || defined(_WIN64)
138  if (!ReleaseSemaphore(_semaphore, 1, nullptr))
139  throwex SystemException("Failed to unlock a semaphore!");
140 #endif
141  }
142 
143 private:
144  int _resources;
145 #if defined(__APPLE__)
146  dispatch_semaphore_t _semaphore;
147 #elif defined(unix) || defined(__unix) || defined(__unix__)
148  sem_t _semaphore;
149 #elif defined(_WIN32) || defined(_WIN64)
150  HANDLE _semaphore;
151 #endif
152 };
153 
155 
156 Semaphore::Semaphore(int resources)
157 {
158  // Check implementation storage parameters
159  [[maybe_unused]] ValidateAlignedStorage<sizeof(Impl), alignof(Impl), StorageSize, StorageAlign> _;
160  static_assert((StorageSize >= sizeof(Impl)), "Semaphore::StorageSize must be increased!");
161  static_assert(((StorageAlign % alignof(Impl)) == 0), "Semaphore::StorageAlign must be adjusted!");
162 
163  // Create the implementation instance
164  new(&_storage)Impl(resources);
165 }
166 
168 {
169  // Delete the implementation instance
170  reinterpret_cast<Impl*>(&_storage)->~Impl();
171 }
172 
173 int Semaphore::resources() const noexcept { return impl().resources(); }
174 
175 bool Semaphore::TryLock() { return impl().TryLock(); }
176 bool Semaphore::TryLockFor(const Timespan& timespan) { return impl().TryLockFor(timespan); }
177 
178 void Semaphore::Lock() { impl().Lock(); }
179 void Semaphore::Unlock() { impl().Unlock(); }
180 
181 } // namespace CppCommon
Semaphore(int resources)
Default class constructor.
Definition: semaphore.cpp:156
bool TryLock()
Try to acquire semaphore without block.
Definition: semaphore.cpp:175
bool TryLockFor(const Timespan &timespan)
Try to acquire semaphore for the given timespan.
Definition: semaphore.cpp:176
int resources() const noexcept
Get the semaphore resources counter.
Definition: semaphore.cpp:173
void Unlock()
Release semaphore.
Definition: semaphore.cpp:179
void Lock()
Acquire semaphore with block.
Definition: semaphore.cpp:178
#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
C++ Common project definitions.
Definition: token_bucket.h:15
Semaphore synchronization primitive definition.
Aligned storage validator definition.