|
| 1 | +/* |
| 2 | + * Provides wrappers around C11 standard library atomics and MSVC intrinsics |
| 3 | + * to provide basic atomic load and store functionality. This is based on |
| 4 | + * code in CPython's pyatomic.h, pyatomic_std.h, and pyatomic_msc.h |
| 5 | + * |
| 6 | + * Adapted from: |
| 7 | + * - numpy/_core/src/common/npy_atomic.h |
| 8 | + * - cpython/Include/cpython/pyatomic.h |
| 9 | + */ |
| 10 | + |
| 11 | +#ifndef PYZSTD_ATOMICS_H |
| 12 | +#define PYZSTD_ATOMICS_H |
| 13 | + |
| 14 | +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L \ |
| 15 | + && !defined(__STDC_NO_ATOMICS__) |
| 16 | +// TODO: support C++ atomics as well if this header is ever needed in C++ |
| 17 | + #include <stdatomic.h> |
| 18 | + #include <stdint.h> |
| 19 | + #define STDC_ATOMICS |
| 20 | +#elif _MSC_VER |
| 21 | + #include <intrin.h> |
| 22 | + #define MSC_ATOMICS |
| 23 | + #if !defined(_M_X64) && !defined(_M_IX86) && !defined(_M_ARM64) |
| 24 | + #error "Unsupported MSVC build configuration, neither x86 or ARM" |
| 25 | + #endif |
| 26 | +#elif defined(__GNUC__) && (__GNUC__ > 4) |
| 27 | + #define GCC_ATOMICS |
| 28 | +#elif defined(__clang__) |
| 29 | + #if __has_builtin(__atomic_load) |
| 30 | + #define GCC_ATOMICS |
| 31 | + #endif |
| 32 | +#else |
| 33 | + #error "no supported atomic implementation for this platform/compiler" |
| 34 | +#endif |
| 35 | + |
| 36 | + |
| 37 | +static inline int8_t |
| 38 | +pyzstd_atomic_load_int8(const int8_t *obj) { |
| 39 | +#ifdef STDC_ATOMICS |
| 40 | + return (int8_t)atomic_load((const _Atomic(int8_t)*)obj); |
| 41 | +#elif defined(MSC_ATOMICS) |
| 42 | +#if defined(_M_X64) || defined(_M_IX86) |
| 43 | + return *(volatile int8_t *)obj; |
| 44 | +#else // defined(_M_ARM64) |
| 45 | + return (int8_t)__ldar8((unsigned __int8 volatile *)obj); |
| 46 | +#endif |
| 47 | +#elif defined(GCC_ATOMICS) |
| 48 | + return __atomic_load_n(obj, __ATOMIC_SEQ_CST); |
| 49 | +#endif |
| 50 | +} |
| 51 | + |
| 52 | +static inline void |
| 53 | +pyzstd_atomic_store_int8(int8_t *obj, int8_t value) { |
| 54 | +#ifdef STDC_ATOMICS |
| 55 | + atomic_store((_Atomic(int8_t)*)obj, value); |
| 56 | +#elif defined(MSC_ATOMICS) |
| 57 | + _InterlockedExchange8((volatile char *)obj, (char)value); |
| 58 | +#elif defined(GCC_ATOMICS) |
| 59 | + __atomic_store_n(obj, value, __ATOMIC_SEQ_CST); |
| 60 | +#endif |
| 61 | +} |
| 62 | + |
| 63 | +static inline int |
| 64 | +pyzstd_atomic_compare_exchange_int8(int8_t *obj, int8_t expected, int8_t desired) { |
| 65 | +#ifdef STDC_ATOMICS |
| 66 | + return atomic_compare_exchange_strong((_Atomic(int8_t)*)obj, |
| 67 | + &expected, desired); |
| 68 | +#elif defined(MSC_ATOMICS) |
| 69 | + int8_t initial = (int8_t)_InterlockedCompareExchange8( |
| 70 | + (volatile char *)obj, |
| 71 | + (char)value, |
| 72 | + (char)expected); |
| 73 | + if (initial == *expected) { |
| 74 | + return 1; |
| 75 | + } |
| 76 | + *expected = initial; |
| 77 | + return 0; |
| 78 | +#elif defined(GCC_ATOMICS) |
| 79 | + return __atomic_compare_exchange_n(obj, &expected, desired, 0, |
| 80 | + __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); |
| 81 | +#endif |
| 82 | +} |
| 83 | + |
| 84 | +#undef MSC_ATOMICS |
| 85 | +#undef STDC_ATOMICS |
| 86 | +#undef GCC_ATOMICS |
| 87 | + |
| 88 | +#endif // PYZSTD_ATOMICS_H |
0 commit comments