CppCommon 1.0.5.0
C++ Common Library
Loading...
Searching...
No Matches
named_semaphore.cpp
Go to the documentation of this file.
1
10
11#include "errors/fatal.h"
13
14#include <algorithm>
15#include <cassert>
16
17#if defined(__APPLE__)
18#include "threads/thread.h"
19#endif
20#if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
21#include <fcntl.h>
22#include <semaphore.h>
23#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
24#include <windows.h>
25#undef Yield
26#undef max
27#undef min
28#endif
29
30namespace CppCommon {
31
33
34class NamedSemaphore::Impl
35{
36public:
37 Impl(const std::string& name, int resources) : _name(name), _resources(resources)
38 {
39 assert((resources > 0) && "Named semaphore resources counter must be greater than zero!");
40
41#if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
42 _owner = true;
43 // Try to create a named binary semaphore
44 _semaphore = sem_open(name.c_str(), (O_CREAT | O_EXCL), 0666, resources);
45 if (_semaphore == SEM_FAILED)
46 {
47 // Try to open a named binary semaphore
48 _semaphore = sem_open(name.c_str(), O_CREAT, 0666, resources);
49 if (_semaphore == SEM_FAILED)
50 throwex SystemException("Failed to initialize a named semaphore!");
51 else
52 _owner = false;
53 }
54#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
55 _semaphore = CreateSemaphoreA(nullptr, resources, resources, name.c_str());
56 if (_semaphore == nullptr)
57 throwex SystemException("Failed to create or open a named semaphore!");
58#endif
59 }
60
61 ~Impl()
62 {
63#if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
64 int result = sem_close(_semaphore);
65 if (result != 0)
66 fatality(SystemException("Failed to close a named semaphore!"));
67 // Unlink the named semaphore (owner only)
68 if (_owner)
69 {
70 result = sem_unlink(_name.c_str());
71 if (result != 0)
72 fatality(SystemException("Failed to unlink a named semaphore!"));
73 }
74#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
75 if (!CloseHandle(_semaphore))
76 fatality(SystemException("Failed to close a named semaphore!"));
77#endif
78 }
79
80 const std::string& name() const
81 {
82 return _name;
83 }
84
85 int resources() const noexcept
86 {
87 return _resources;
88 }
89
90 bool TryLock()
91 {
92#if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
93 int result = sem_trywait(_semaphore);
94 if ((result != 0) && (errno != EAGAIN))
95 throwex SystemException("Failed to try lock a named semaphore!");
96 return (result == 0);
97#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
98 DWORD result = WaitForSingleObject(_semaphore, 0);
99 if ((result != WAIT_OBJECT_0) && (result != WAIT_TIMEOUT))
100 throwex SystemException("Failed to try lock a named semaphore!");
101 return (result == WAIT_OBJECT_0);
102#endif
103 }
104
105 bool TryLockFor(const Timespan& timespan)
106 {
107 if (timespan < 0)
108 return TryLock();
109#if defined(__APPLE__)
110 // Calculate a finish timestamp
111 Timestamp finish = NanoTimestamp() + timespan;
112
113 // Try to acquire lock at least one time
114 if (TryLock())
115 return true;
116 else
117 {
118 // Try lock or yield for the given timespan
119 while (NanoTimestamp() < finish)
120 {
121 if (TryLock())
122 return true;
123 else
124 Thread::Yield();
125 }
126
127 // Failed to acquire lock
128 return false;
129 }
130#elif (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__CYGWIN__)
131 struct timespec timeout;
132 timeout.tv_sec = timespan.seconds();
133 timeout.tv_nsec = timespan.nanoseconds() % 1000000000;
134 int result = sem_timedwait(_semaphore, &timeout);
135 if ((result != 0) && (errno != ETIMEDOUT))
136 throwex SystemException("Failed to try lock a named semaphore for the given timeout!");
137 return (result == 0);
138#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
139 DWORD result = WaitForSingleObject(_semaphore, std::max((DWORD)1, (DWORD)timespan.milliseconds()));
140 if ((result != WAIT_OBJECT_0) && (result != WAIT_TIMEOUT))
141 throwex SystemException("Failed to try lock a named semaphore for the given timeout!");
142 return (result == WAIT_OBJECT_0);
143#endif
144 }
145
146 void Lock()
147 {
148#if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
149 int result = sem_wait(_semaphore);
150 if (result != 0)
151 throwex SystemException("Failed to lock a named semaphore!");
152#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
153 DWORD result = WaitForSingleObject(_semaphore, INFINITE);
154 if (result != WAIT_OBJECT_0)
155 throwex SystemException("Failed to lock a named semaphore!");
156#endif
157 }
158
159 void Unlock()
160 {
161#if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
162 int result = sem_post(_semaphore);
163 if (result != 0)
164 throwex SystemException("Failed to unlock a named semaphore!");
165#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
166 if (!ReleaseSemaphore(_semaphore, 1, nullptr))
167 throwex SystemException("Failed to unlock a named semaphore!");
168#endif
169 }
170
171private:
172 std::string _name;
173 int _resources;
174#if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
175 sem_t* _semaphore;
176 bool _owner;
177#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
178 HANDLE _semaphore;
179#endif
180};
181
183
184NamedSemaphore::NamedSemaphore(const std::string& name, int resources)
185{
186 // Check implementation storage parameters
187 [[maybe_unused]] ValidateAlignedStorage<sizeof(Impl), alignof(Impl), StorageSize, StorageAlign> _;
188 static_assert((StorageSize >= sizeof(Impl)), "NamedSemaphore::StorageSize must be increased!");
189 static_assert(((StorageAlign % alignof(Impl)) == 0), "NamedSemaphore::StorageAlign must be adjusted!");
190
191 // Create the implementation instance
192 new(&_storage)Impl(name, resources);
193}
194
196{
197 // Delete the implementation instance
198 reinterpret_cast<Impl*>(&_storage)->~Impl();
199}
200
201const std::string& NamedSemaphore::name() const { return impl().name(); }
202int NamedSemaphore::resources() const noexcept { return impl().resources(); }
203
204bool NamedSemaphore::TryLock() { return impl().TryLock(); }
205bool NamedSemaphore::TryLockFor(const Timespan& timespan) { return impl().TryLockFor(timespan); }
206
207void NamedSemaphore::Lock() { impl().Lock(); }
208void NamedSemaphore::Unlock() { impl().Unlock(); }
209
210} // namespace CppCommon
NamedSemaphore(const std::string &name, int resources)
Default class constructor.
int resources() const noexcept
Get the semaphore resources counter.
bool TryLockFor(const Timespan &timespan)
Try to acquire semaphore for the given timespan.
void Unlock()
Release semaphore.
const std::string & name() const
Get the semaphore name.
void Lock()
Acquire semaphore with block.
bool TryLock()
Try to acquire semaphore without 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
Named semaphore synchronization primitive definition.
C++ Common project definitions.
Semaphore synchronization primitive definition.
Thread definition.
Aligned storage validator definition.