CppCommon 1.0.5.0
C++ Common Library
Loading...
Searching...
No Matches
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
28namespace CppCommon {
29
31
32class Semaphore::Impl
33{
34public:
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
143private:
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
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
173int Semaphore::resources() const noexcept { return impl().resources(); }
174
175bool Semaphore::TryLock() { return impl().TryLock(); }
176bool Semaphore::TryLockFor(const Timespan& timespan) { return impl().TryLockFor(timespan); }
177
178void Semaphore::Lock() { impl().Lock(); }
179void Semaphore::Unlock() { impl().Unlock(); }
180
181} // namespace CppCommon
Semaphore(int resources)
Default class constructor.
bool TryLock()
Try to acquire semaphore without block.
bool TryLockFor(const Timespan &timespan)
Try to acquire semaphore for the given timespan.
int resources() const noexcept
Get the semaphore resources counter.
void Unlock()
Release semaphore.
void Lock()
Acquire semaphore with block.
#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.
Semaphore synchronization primitive definition.
Aligned storage validator definition.