15 #include <type_traits>
21 #if defined(__INTEL_COMPILER)
23 #elif defined(_MSC_VER)
25 #elif defined(__GNUC__)
29 #if defined(_M_IA64) || defined(__ia64__)
31 #elif defined(_WIN64) || defined(__amd64__) || defined(_M_X64) || defined(__x86_64__)
33 #elif defined(_M_IX86) || defined(__i386__)
35 #elif defined(_M_PPC) || defined(__powerpc__)
38 #define AE_ARCH_UNKNOWN
43 #define AE_UNUSED(x) ((void)x)
46 #if defined(__has_feature)
47 #if __has_feature(thread_sanitizer)
48 #define AE_NO_TSAN __attribute__((no_sanitize("thread")))
58 #if defined(AE_VCPP) || defined(AE_ICC)
59 #define AE_FORCEINLINE __forceinline
62 #define AE_FORCEINLINE inline
64 #define AE_FORCEINLINE inline
69 #if defined(AE_VCPP) || defined(AE_ICC)
70 #define AE_ALIGN(x) __declspec(align(x))
72 #define AE_ALIGN(x) __attribute__((aligned(x)))
75 #define AE_ALIGN(x) __attribute__((aligned(x)))
95 #if (defined(AE_VCPP) && (_MSC_VER < 1700 || defined(__cplusplus_cli))) || (defined(AE_ICC) && __INTEL_COMPILER < 1600)
100 #if defined(AE_ARCH_X64) || defined(AE_ARCH_X86)
101 #define AeFullSync _mm_mfence
102 #define AeLiteSync _mm_mfence
103 #elif defined(AE_ARCH_IA64)
104 #define AeFullSync __mf
105 #define AeLiteSync __mf
106 #elif defined(AE_ARCH_PPC)
107 #include <ppcintrinsics.h>
108 #define AeFullSync __sync
109 #define AeLiteSync __lwsync
114 #pragma warning(push)
115 #pragma warning(disable: 4365)
116 #ifdef __cplusplus_cli
117 #pragma managed(push, off)
121 namespace moodycamel {
131 default: assert(
false);
138 #if defined(AE_ARCH_X86) || defined(AE_ARCH_X64)
151 default: assert(
false);
181 default: assert(
false);
199 default: assert(
false);
211 default: assert(
false);
219 #if !defined(AE_VCPP) || (_MSC_VER >= 1700 && !defined(__cplusplus_cli))
220 #define AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC
223 #ifdef AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC
238 #pragma warning(push)
239 #pragma warning(disable: 4100)
242 #ifdef __cplusplus_cli
255 #ifndef AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC
263 #if defined(AE_ARCH_X64) || defined(AE_ARCH_X86)
264 if (
sizeof(T) == 4)
return _InterlockedExchangeAdd((
long volatile*)&
value, (
long)increment);
265 #if defined(_M_AMD64)
266 else if (
sizeof(T) == 8)
return _InterlockedExchangeAdd64((
long long volatile*)&
value, (
long long)increment);
269 #error Unsupported platform
271 assert(
false &&
"T must be either a 32 or 64 bit type");
277 #if defined(AE_ARCH_X64) || defined(AE_ARCH_X86)
278 if (
sizeof(T) == 4)
return _InterlockedExchangeAdd((
long volatile*)&
value, (
long)increment);
279 #if defined(_M_AMD64)
280 else if (
sizeof(T) == 8)
return _InterlockedExchangeAdd64((
long long volatile*)&
value, (
long long)increment);
283 #error Unsupported platform
285 assert(
false &&
"T must be either a 32 or 64 bit type");
317 #ifndef AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC
338 struct _SECURITY_ATTRIBUTES;
339 __declspec(dllimport)
void* __stdcall CreateSemaphoreW(_SECURITY_ATTRIBUTES* lpSemaphoreAttributes,
long lInitialCount,
long lMaximumCount,
const wchar_t* lpName);
340 __declspec(dllimport)
int __stdcall CloseHandle(
void* hObject);
341 __declspec(dllimport)
unsigned long __stdcall WaitForSingleObject(
void* hHandle,
unsigned long dwMilliseconds);
342 __declspec(dllimport)
int __stdcall ReleaseSemaphore(
void* hSemaphore,
long lReleaseCount,
long* lpPreviousCount);
344 #elif defined(__MACH__)
345 #include <mach/mach.h>
346 #elif defined(__unix__)
347 #include <semaphore.h>
379 Semaphore(
const Semaphore& other);
380 Semaphore& operator=(
const Semaphore& other);
385 assert(initialCount >= 0);
386 const long maxLong = 0x7fffffff;
387 m_hSema = CreateSemaphoreW(
nullptr, initialCount, maxLong,
nullptr);
392 CloseHandle(m_hSema);
397 const unsigned long infinite = 0xffffffff;
398 WaitForSingleObject(m_hSema, infinite);
403 const unsigned long RC_WAIT_TIMEOUT = 0x00000102;
404 return WaitForSingleObject(m_hSema, 0) != RC_WAIT_TIMEOUT;
407 bool timed_wait(std::uint64_t usecs)
AE_NO_TSAN
409 const unsigned long RC_WAIT_TIMEOUT = 0x00000102;
410 return WaitForSingleObject(m_hSema, (
unsigned long)(usecs / 1000)) != RC_WAIT_TIMEOUT;
415 ReleaseSemaphore(m_hSema, count,
nullptr);
418 #elif defined(__MACH__)
428 Semaphore(
const Semaphore& other);
429 Semaphore& operator=(
const Semaphore& other);
434 assert(initialCount >= 0);
435 semaphore_create(mach_task_self(), &m_sema, SYNC_POLICY_FIFO, initialCount);
440 semaphore_destroy(mach_task_self(), m_sema);
445 semaphore_wait(m_sema);
450 return timed_wait(0);
453 bool timed_wait(std::int64_t timeout_usecs)
AE_NO_TSAN
456 ts.tv_sec =
static_cast<unsigned int>(timeout_usecs / 1000000);
457 ts.tv_nsec = (timeout_usecs % 1000000) * 1000;
460 kern_return_t rc = semaphore_timedwait(m_sema, ts);
462 return rc != KERN_OPERATION_TIMED_OUT && rc != KERN_ABORTED;
467 semaphore_signal(m_sema);
474 semaphore_signal(m_sema);
478 #elif defined(__unix__)
487 Semaphore(
const Semaphore& other);
488 Semaphore& operator=(
const Semaphore& other);
493 assert(initialCount >= 0);
494 sem_init(&m_sema, 0, initialCount);
499 sem_destroy(&m_sema);
508 rc = sem_wait(&m_sema);
510 while (rc == -1 && errno == EINTR);
517 rc = sem_trywait(&m_sema);
518 }
while (rc == -1 && errno == EINTR);
519 return !(rc == -1 && errno == EAGAIN);
522 bool timed_wait(std::uint64_t usecs)
AE_NO_TSAN
525 const int usecs_in_1_sec = 1000000;
526 const int nsecs_in_1_sec = 1000000000;
527 clock_gettime(CLOCK_REALTIME, &ts);
528 ts.tv_sec += usecs / usecs_in_1_sec;
529 ts.tv_nsec += (usecs % usecs_in_1_sec) * 1000;
532 if (ts.tv_nsec >= nsecs_in_1_sec) {
533 ts.tv_nsec -= nsecs_in_1_sec;
539 rc = sem_timedwait(&m_sema, &ts);
540 }
while (rc == -1 && errno == EINTR);
541 return !(rc == -1 && errno == ETIMEDOUT);
558 #error Unsupported platform! (No semaphore wrapper available)
592 if (timeout_usecs < 0)
597 if (
m_sema.timed_wait(timeout_usecs))
611 if (oldCount > 0 &&
m_sema.try_wait())
619 assert(initialCount >= 0);
647 assert(oldCount >= -1);
657 return count > 0 ? count : 0;
662 #if defined(AE_VCPP) && (_MSC_VER < 1700 || defined(__cplusplus_cli))
664 #ifdef __cplusplus_cli
AE_FORCEINLINE void fence(memory_order order) AE_NO_TSAN
AE_FORCEINLINE void compiler_fence(memory_order order) AE_NO_TSAN
std::make_signed< std::size_t >::type ssize_t
bool tryWait() AE_NO_TSAN
weak_atomic< ssize_t > m_count
bool wait(std::int64_t timeout_usecs) AE_NO_TSAN
AE_NO_TSAN LightweightSemaphore(ssize_t initialCount=0)
ssize_t availableApprox() const AE_NO_TSAN
void signal(ssize_t count=1) AE_NO_TSAN
bool waitWithPartialSpinning(std::int64_t timeout_usecs=-1) AE_NO_TSAN
AE_FORCEINLINE T fetch_add_acquire(T increment) AE_NO_TSAN
AE_FORCEINLINE T fetch_add_release(T increment) AE_NO_TSAN
AE_NO_TSAN weak_atomic(U &&x)
AE_FORCEINLINE weak_atomic const & operator=(weak_atomic const &other) AE_NO_TSAN
AE_FORCEINLINE T load() const AE_NO_TSAN
AE_NO_TSAN weak_atomic(weak_atomic const &other)
AE_FORCEINLINE weak_atomic const & operator=(U &&x) AE_NO_TSAN
AE_NO_TSAN weak_atomic(weak_atomic &&other)