19 struct _SECURITY_ATTRIBUTES;
20 __declspec(dllimport)
void* __stdcall CreateSemaphoreW(_SECURITY_ATTRIBUTES* lpSemaphoreAttributes,
long lInitialCount,
long lMaximumCount,
const wchar_t* lpName);
21 __declspec(dllimport)
int __stdcall CloseHandle(
void* hObject);
22 __declspec(dllimport)
unsigned long __stdcall WaitForSingleObject(
void* hHandle,
unsigned long dwMilliseconds);
23 __declspec(dllimport)
int __stdcall ReleaseSemaphore(
void* hSemaphore,
long lReleaseCount,
long* lpPreviousCount);
25#elif defined(__MACH__)
28#include <zos-semaphore.h>
29#elif defined(__unix__)
32#if defined(__GLIBC_PREREQ) && defined(_GNU_SOURCE)
33#if __GLIBC_PREREQ(2,30)
34#define MOODYCAMEL_LIGHTWEIGHTSEMAPHORE_MONOTONIC
75 Semaphore(
int initialCount = 0)
77 assert(initialCount >= 0);
78 const long maxLong = 0x7fffffff;
79 m_hSema = CreateSemaphoreW(
nullptr, initialCount, maxLong,
nullptr);
90 const unsigned long infinite = 0xffffffff;
91 return WaitForSingleObject(m_hSema, infinite) == 0;
96 return WaitForSingleObject(m_hSema, 0) == 0;
99 bool timed_wait(std::uint64_t usecs)
101 return WaitForSingleObject(m_hSema, (
unsigned long)(usecs / 1000)) == 0;
104 void signal(
int count = 1)
106 while (!ReleaseSemaphore(m_hSema, count,
nullptr));
109#elif defined(__MACH__)
123 Semaphore(
int initialCount = 0)
125 assert(initialCount >= 0);
126 kern_return_t rc = semaphore_create(mach_task_self(), &m_sema, SYNC_POLICY_FIFO, initialCount);
127 assert(rc == KERN_SUCCESS);
133 semaphore_destroy(mach_task_self(), m_sema);
138 return semaphore_wait(m_sema) == KERN_SUCCESS;
143 return timed_wait(0);
146 bool timed_wait(std::uint64_t timeout_usecs)
149 ts.tv_sec =
static_cast<unsigned int>(timeout_usecs / 1000000);
150 ts.tv_nsec =
static_cast<int>((timeout_usecs % 1000000) * 1000);
153 kern_return_t rc = semaphore_timedwait(m_sema, ts);
154 return rc == KERN_SUCCESS;
159 while (semaphore_signal(m_sema) != KERN_SUCCESS);
162 void signal(
int count)
166 while (semaphore_signal(m_sema) != KERN_SUCCESS);
170#elif defined(__unix__) || defined(__MVS__)
183 Semaphore(
int initialCount = 0)
185 assert(initialCount >= 0);
186 int rc = sem_init(&m_sema, 0,
static_cast<unsigned int>(initialCount));
193 sem_destroy(&m_sema);
201 rc = sem_wait(&m_sema);
202 }
while (rc == -1 && errno == EINTR);
210 rc = sem_trywait(&m_sema);
211 }
while (rc == -1 && errno == EINTR);
215 bool timed_wait(std::uint64_t usecs)
218 const int usecs_in_1_sec = 1000000;
219 const int nsecs_in_1_sec = 1000000000;
220#ifdef MOODYCAMEL_LIGHTWEIGHTSEMAPHORE_MONOTONIC
221 clock_gettime(CLOCK_MONOTONIC, &ts);
223 clock_gettime(CLOCK_REALTIME, &ts);
225 ts.tv_sec += (time_t)(usecs / usecs_in_1_sec);
226 ts.tv_nsec += (long)(usecs % usecs_in_1_sec) * 1000;
229 if (ts.tv_nsec >= nsecs_in_1_sec) {
230 ts.tv_nsec -= nsecs_in_1_sec;
236#ifdef MOODYCAMEL_LIGHTWEIGHTSEMAPHORE_MONOTONIC
237 rc = sem_clockwait(&m_sema, CLOCK_MONOTONIC, &ts);
239 rc = sem_timedwait(&m_sema, &ts);
241 }
while (rc == -1 && errno == EINTR);
247 while (sem_post(&m_sema) == -1);
250 void signal(
int count)
254 while (sem_post(&m_sema) == -1);
259#error Unsupported platform! (No semaphore wrapper available)
271 typedef std::make_signed<std::size_t>::type
ssize_t;
274 std::atomic<ssize_t> m_count;
275 details::Semaphore m_sema;
278 bool waitWithPartialSpinning(std::int64_t
timeout_usecs = -1)
281 int spin = m_maxSpins;
284 oldCount = m_count.load(std::memory_order_relaxed);
285 if ((
oldCount > 0) && m_count.compare_exchange_strong(
oldCount,
oldCount - 1, std::memory_order_acquire, std::memory_order_relaxed))
287 std::atomic_signal_fence(std::memory_order_acquire);
289 oldCount = m_count.fetch_sub(1, std::memory_order_acquire);
306 oldCount = m_count.load(std::memory_order_acquire);
307 if (
oldCount >= 0 && m_sema.try_wait())
309 if (
oldCount < 0 && m_count.compare_exchange_strong(
oldCount,
oldCount + 1, std::memory_order_relaxed, std::memory_order_relaxed))
318 int spin = m_maxSpins;
321 oldCount = m_count.load(std::memory_order_relaxed);
325 if (m_count.compare_exchange_strong(
oldCount,
newCount, std::memory_order_acquire, std::memory_order_relaxed))
328 std::atomic_signal_fence(std::memory_order_acquire);
330 oldCount = m_count.fetch_sub(1, std::memory_order_acquire);
333 if ((timeout_usecs == 0) || (timeout_usecs < 0 && !m_sema.wait()) || (timeout_usecs > 0 && !m_sema.timed_wait((std::uint64_t)timeout_usecs)))
337 oldCount = m_count.load(std::memory_order_acquire);
338 if (oldCount >= 0 && m_sema.try_wait())
340 if (oldCount < 0 && m_count.compare_exchange_strong(oldCount, oldCount + 1, std::memory_order_relaxed, std::memory_order_relaxed))
362 if (m_count.compare_exchange_weak(
oldCount,
oldCount - 1, std::memory_order_acquire, std::memory_order_relaxed))
370 return tryWait() || waitWithPartialSpinning();
386 if (m_count.compare_exchange_weak(
oldCount,
newCount, std::memory_order_acquire, std::memory_order_relaxed))
422 ssize_t count = m_count.load(std::memory_order_relaxed);
423 return count > 0 ?
static_cast<std::size_t
>(
count) : 0;
Definition concurrentqueue.h:768
Definition lightweightsemaphore.h:269
bool wait(std::int64_t timeout_usecs)
Definition lightweightsemaphore.h:373
bool tryWait()
Definition lightweightsemaphore.h:357
LightweightSemaphore(ssize_t initialCount=0, int maxSpins=10000)
Definition lightweightsemaphore.h:351
bool wait()
Definition lightweightsemaphore.h:368
ssize_t waitMany(ssize_t max)
Definition lightweightsemaphore.h:402
void signal(ssize_t count=1)
Definition lightweightsemaphore.h:409
std::size_t availableApprox() const
Definition lightweightsemaphore.h:420
ssize_t waitMany(ssize_t max, std::int64_t timeout_usecs)
Definition lightweightsemaphore.h:393
ssize_t tryWaitMany(ssize_t max)
Definition lightweightsemaphore.h:379
std::make_signed< std::size_t >::type ssize_t
Definition lightweightsemaphore.h:271
#define MOODYCAMEL_DELETE_FUNCTION
Definition concurrentqueue.h:233
Definition blockingconcurrentqueue.h:20