16 #include <type_traits>
22 #if defined(__INTEL_COMPILER)
24 #elif defined(_MSC_VER)
26 #elif defined(__GNUC__)
30 #if defined(_M_IA64) || defined(__ia64__)
32 #elif defined(_WIN64) || defined(__amd64__) || defined(_M_X64) || defined(__x86_64__)
34 #elif defined(_M_IX86) || defined(__i386__)
36 #elif defined(_M_PPC) || defined(__powerpc__)
39 #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")))
57 #if defined(AE_VCPP) || defined(AE_ICC)
58 #define AE_FORCEINLINE __forceinline
61 #define AE_FORCEINLINE inline
63 #define AE_FORCEINLINE inline
67 #if defined(AE_VCPP) || defined(AE_ICC)
68 #define AE_ALIGN(x) __declspec(align(x))
70 #define AE_ALIGN(x) __attribute__((aligned(x)))
73 #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
113 #pragma warning(push)
114 #pragma warning(disable : 4365) // Disable erroneous 'conversion from long to unsigned int, signed/unsigned mismatch'
116 #ifdef __cplusplus_cli
117 #pragma managed(push, off)
149 #if defined(AE_ARCH_X86) || defined(AE_ARCH_X64)
264 #if !defined(AE_VCPP) || (_MSC_VER >= 1700 && !defined(__cplusplus_cli))
265 #define AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC
268 #ifdef AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC
279 template <
typename T>
287 #pragma warning(push)
288 #pragma warning(disable : 4100) // Get rid of (erroneous) 'unreferenced formal parameter' warning
290 template <
typename U>
294 #ifdef __cplusplus_cli
315 #ifndef AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC
316 template <
typename U>
319 value = std::forward<U>(x);
335 #if defined(AE_ARCH_X64) || defined(AE_ARCH_X86)
337 return _InterlockedExchangeAdd((
long volatile*)&
value, (
long)increment);
338 #if defined(_M_AMD64)
339 else if (
sizeof(T) == 8)
340 return _InterlockedExchangeAdd64((
long long volatile*)&
value, (
long long)increment);
343 #error Unsupported platform
345 assert(
false &&
"T must be either a 32 or 64 bit type");
351 #if defined(AE_ARCH_X64) || defined(AE_ARCH_X86)
353 return _InterlockedExchangeAdd((
long volatile*)&
value, (
long)increment);
354 #if defined(_M_AMD64)
355 else if (
sizeof(T) == 8)
356 return _InterlockedExchangeAdd64((
long long volatile*)&
value, (
long long)increment);
359 #error Unsupported platform
361 assert(
false &&
"T must be either a 32 or 64 bit type");
365 template <
typename U>
395 #ifndef AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC
415 struct _SECURITY_ATTRIBUTES;
416 __declspec(dllimport)
void* __stdcall CreateSemaphoreW(_SECURITY_ATTRIBUTES* lpSemaphoreAttributes,
long lInitialCount,
417 long lMaximumCount,
const wchar_t* lpName);
418 __declspec(dllimport)
int __stdcall CloseHandle(
void* hObject);
419 __declspec(dllimport)
unsigned long __stdcall WaitForSingleObject(
void* hHandle,
unsigned long dwMilliseconds);
420 __declspec(dllimport)
int __stdcall ReleaseSemaphore(
void* hSemaphore,
long lReleaseCount,
long* lpPreviousCount);
422 #elif defined(__MACH__)
423 #include <mach/mach.h>
424 #elif defined(__unix__)
425 #include <semaphore.h>
459 Semaphore(
const Semaphore& other);
460 Semaphore& operator=(
const Semaphore& other);
465 assert(initialCount >= 0);
466 const long maxLong = 0x7fffffff;
467 m_hSema = CreateSemaphoreW(
nullptr, initialCount, maxLong,
nullptr);
473 CloseHandle(m_hSema);
478 const unsigned long infinite = 0xffffffff;
479 return WaitForSingleObject(m_hSema, infinite) == 0;
484 return WaitForSingleObject(m_hSema, 0) == 0;
487 bool timed_wait(std::uint64_t usecs)
AE_NO_TSAN
489 return WaitForSingleObject(m_hSema, (
unsigned long)(usecs / 1000)) == 0;
494 while (!ReleaseSemaphore(m_hSema, count,
nullptr))
498 #elif defined(__MACH__)
508 Semaphore(
const Semaphore& other);
509 Semaphore& operator=(
const Semaphore& other);
514 assert(initialCount >= 0);
515 kern_return_t rc = semaphore_create(mach_task_self(), &m_sema, SYNC_POLICY_FIFO, initialCount);
516 assert(rc == KERN_SUCCESS);
522 semaphore_destroy(mach_task_self(), m_sema);
527 return semaphore_wait(m_sema) == KERN_SUCCESS;
532 return timed_wait(0);
535 bool timed_wait(std::int64_t timeout_usecs)
AE_NO_TSAN
538 ts.tv_sec =
static_cast<unsigned int>(timeout_usecs / 1000000);
539 ts.tv_nsec = (timeout_usecs % 1000000) * 1000;
543 kern_return_t rc = semaphore_timedwait(m_sema, ts);
544 return rc == KERN_SUCCESS;
549 while (semaphore_signal(m_sema) != KERN_SUCCESS)
557 while (semaphore_signal(m_sema) != KERN_SUCCESS)
562 #elif defined(__unix__)
571 Semaphore(
const Semaphore& other);
572 Semaphore& operator=(
const Semaphore& other);
577 assert(initialCount >= 0);
578 int rc = sem_init(&m_sema, 0, initialCount);
585 sem_destroy(&m_sema);
594 rc = sem_wait(&m_sema);
595 }
while (rc == -1 && errno == EINTR);
604 rc = sem_trywait(&m_sema);
605 }
while (rc == -1 && errno == EINTR);
609 bool timed_wait(std::uint64_t usecs)
AE_NO_TSAN
612 const int usecs_in_1_sec = 1000000;
613 const int nsecs_in_1_sec = 1000000000;
614 clock_gettime(CLOCK_REALTIME, &ts);
615 ts.tv_sec += usecs / usecs_in_1_sec;
616 ts.tv_nsec += (usecs % usecs_in_1_sec) * 1000;
619 if (ts.tv_nsec >= nsecs_in_1_sec)
621 ts.tv_nsec -= nsecs_in_1_sec;
628 rc = sem_timedwait(&m_sema, &ts);
629 }
while (rc == -1 && errno == EINTR);
635 while (sem_post(&m_sema) == -1)
643 while (sem_post(&m_sema) == -1)
649 #error Unsupported platform! (No semaphore wrapper available)
658 typedef std::make_signed<std::size_t>::type
ssize_t;
683 if (timeout_usecs < 0)
685 if (
m_sema.timed_wait(timeout_usecs))
699 if (oldCount > 0 &&
m_sema.try_wait())
707 assert(initialCount >= 0);
734 assert(oldCount >= -1);
744 return count > 0 ? count : 0;
750 #if defined(AE_VCPP) && (_MSC_VER < 1700 || defined(__cplusplus_cli))
752 #ifdef __cplusplus_cli