From 62da4db09a840e9b4ff2452932dc7357b2a3662f Mon Sep 17 00:00:00 2001 From: Leonid Yuriev Date: Sun, 11 Oct 2020 18:54:07 +0300 Subject: [PATCH] mdbx: fix/refine the use of C11 atomics. Change-Id: I5d925d4625b06296fd82f4b35ee36be682e7b2d3 --- .github/actions/spelling/expect.txt | 1 + src/core.c | 66 ++++++++++++++++++++++------- src/osal.h | 59 ++++++++++++++------------ 3 files changed, 83 insertions(+), 43 deletions(-) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 2913488c..0e8631f1 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -208,6 +208,7 @@ csrc CSRSS css cstdarg +cstdatomic cstddef cstdint cstr diff --git a/src/core.c b/src/core.c index 4d3a0263..d91a6503 100644 --- a/src/core.c +++ b/src/core.c @@ -780,12 +780,24 @@ static __always_inline void atomic_yield(void) { #if MDBX_64BIT_CAS static __always_inline bool atomic_cas64(volatile uint64_t *p, uint64_t c, uint64_t v) { -#if defined(ATOMIC_VAR_INIT) || defined(ATOMIC_LLONG_LOCK_FREE) +#if !defined(__STDC_NO_ATOMICS__) && \ + (defined(ATOMIC_VAR_INIT) || defined(ATOMIC_LLONG_LOCK_FREE) || \ + __has_extension(c_atomic)) STATIC_ASSERT(sizeof(long long) >= sizeof(uint64_t)); -#ifndef __COVERITY__ - STATIC_ASSERT(atomic_is_lock_free(p)); -#endif /* Workaround for Coverity */ - return atomic_compare_exchange_strong((_Atomic uint64_t *)p, &c, v); +#ifdef ATOMIC_LLONG_LOCK_FREE + STATIC_ASSERT(ATOMIC_LLONG_LOCK_FREE > 0); +#if ATOMIC_LLONG_LOCK_FREE < 2 + assert(atomic_is_lock_free(p)); +#endif +#else + assert(atomic_is_lock_free(p)); +#endif +#ifdef __clang__ + STATIC_ASSERT(sizeof(_Atomic uint64_t) == sizeof(uint64_t)); + return atomic_compare_exchange_strong((_Atomic volatile uint64_t *)p, &c, v); +#else + return atomic_compare_exchange_strong(p, &c, v); +#endif #elif defined(__GNUC__) || defined(__clang__) return __sync_bool_compare_and_swap(p, c, v); #elif defined(_MSC_VER) @@ -801,12 +813,24 @@ static __always_inline bool atomic_cas64(volatile uint64_t *p, uint64_t c, static __always_inline bool atomic_cas32(volatile uint32_t *p, uint32_t c, uint32_t v) { -#if defined(ATOMIC_VAR_INIT) || defined(ATOMIC_INT_LOCK_FREE) +#if !defined(__STDC_NO_ATOMICS__) && \ + (defined(ATOMIC_VAR_INIT) || defined(ATOMIC_INT_LOCK_FREE) || \ + __has_extension(c_atomic)) STATIC_ASSERT(sizeof(int) >= sizeof(uint32_t)); -#ifndef __COVERITY__ - STATIC_ASSERT(atomic_is_lock_free(p)); -#endif /* Workaround for Coverity */ - return atomic_compare_exchange_strong((_Atomic uint32_t *)p, &c, v); +#ifdef ATOMIC_INT_LOCK_FREE + STATIC_ASSERT(ATOMIC_INT_LOCK_FREE > 0); +#if ATOMIC_INT_LOCK_FREE < 2 + assert(atomic_is_lock_free(p)); +#endif +#else + assert(atomic_is_lock_free(p)); +#endif +#ifdef __clang__ + STATIC_ASSERT(sizeof(_Atomic uint32_t) == sizeof(uint32_t)); + return atomic_compare_exchange_strong((_Atomic volatile uint32_t *)p, &c, v); +#else + return atomic_compare_exchange_strong(p, &c, v); +#endif #elif defined(__GNUC__) || defined(__clang__) return __sync_bool_compare_and_swap(p, c, v); #elif defined(_MSC_VER) @@ -820,12 +844,24 @@ static __always_inline bool atomic_cas32(volatile uint32_t *p, uint32_t c, } static __always_inline uint32_t atomic_add32(volatile uint32_t *p, uint32_t v) { -#if defined(ATOMIC_VAR_INIT) || defined(ATOMIC_INT_LOCK_FREE) +#if !defined(__STDC_NO_ATOMICS__) && \ + (defined(ATOMIC_VAR_INIT) || defined(ATOMIC_INT_LOCK_FREE) || \ + __has_extension(c_atomic)) STATIC_ASSERT(sizeof(int) >= sizeof(uint32_t)); -#ifndef __COVERITY__ - STATIC_ASSERT(atomic_is_lock_free(p)); -#endif /* Workaround for Coverity */ - return atomic_fetch_add((_Atomic uint32_t *)p, v); +#ifdef ATOMIC_INT_LOCK_FREE + STATIC_ASSERT(ATOMIC_INT_LOCK_FREE > 0); +#if ATOMIC_INT_LOCK_FREE < 2 + assert(atomic_is_lock_free(p)); +#endif +#else + assert(atomic_is_lock_free(p)); +#endif +#ifdef __clang__ + STATIC_ASSERT(sizeof(_Atomic uint32_t) == sizeof(uint32_t)); + return atomic_fetch_add((_Atomic volatile uint32_t *)p, v); +#else + return atomic_fetch_add(p, v); +#endif #elif defined(__GNUC__) || defined(__clang__) return __sync_fetch_and_add(p, v); #elif defined(_MSC_VER) diff --git a/src/osal.h b/src/osal.h index b47c2426..aa839ac1 100644 --- a/src/osal.h +++ b/src/osal.h @@ -459,6 +459,35 @@ typedef union MDBX_srwlock { #ifdef __cplusplus extern void mdbx_osal_jitter(bool tiny); #else + +/*----------------------------------------------------------------------------*/ +/* Atomics */ + +#if defined(__cplusplus) && !defined(__STDC_NO_ATOMICS__) && __has_include() +#include +#elif !defined(__cplusplus) && (__STDC_VERSION__ >= 201112L) && \ + !defined(__STDC_NO_ATOMICS__) && \ + (__GNUC_PREREQ(4, 9) || __CLANG_PREREQ(3, 8) || \ + !(defined(__GNUC__) || defined(__clang__))) +#include +#elif defined(__GNUC__) || defined(__clang__) +/* LY: nothing required */ +#elif defined(_MSC_VER) +#pragma warning(disable : 4163) /* 'xyz': not available as an intrinsic */ +#pragma warning(disable : 4133) /* 'function': incompatible types - from \ + 'size_t' to 'LONGLONG' */ +#pragma warning(disable : 4244) /* 'return': conversion from 'LONGLONG' to \ + 'std::size_t', possible loss of data */ +#pragma warning(disable : 4267) /* 'function': conversion from 'size_t' to \ + 'long', possible loss of data */ +#pragma intrinsic(_InterlockedExchangeAdd, _InterlockedCompareExchange) +#pragma intrinsic(_InterlockedExchangeAdd64, _InterlockedCompareExchange64) +#elif defined(__APPLE__) +#include +#else +#error FIXME atomic-ops +#endif + /*----------------------------------------------------------------------------*/ /* Memory/Compiler barriers, cache coherence */ @@ -500,8 +529,8 @@ static __maybe_unused __inline void mdbx_compiler_barrier(void) { } static __maybe_unused __inline void mdbx_memory_barrier(void) { -#if __has_extension(c_atomic) || __has_extension(cxx_atomic) - __c11_atomic_thread_fence(__ATOMIC_SEQ_CST); +#if __has_extension(c_atomic) && !defined(__STDC_NO_ATOMICS__) + atomic_thread_fence(__ATOMIC_SEQ_CST); #elif defined(__ATOMIC_SEQ_CST) __atomic_thread_fence(__ATOMIC_SEQ_CST); #elif defined(__clang__) || defined(__GNUC__) @@ -898,32 +927,6 @@ MDBX_INTERNAL_VAR MDBX_RegGetValueA mdbx_RegGetValueA; #endif /* Windows */ -/*----------------------------------------------------------------------------*/ -/* Atomics */ - -#if !defined(__cplusplus) && (__STDC_VERSION__ >= 201112L) && \ - !defined(__STDC_NO_ATOMICS__) && \ - (__GNUC_PREREQ(4, 9) || __CLANG_PREREQ(3, 8) || \ - !(defined(__GNUC__) || defined(__clang__))) -#include -#elif defined(__GNUC__) || defined(__clang__) -/* LY: nothing required */ -#elif defined(_MSC_VER) -#pragma warning(disable : 4163) /* 'xyz': not available as an intrinsic */ -#pragma warning(disable : 4133) /* 'function': incompatible types - from \ - 'size_t' to 'LONGLONG' */ -#pragma warning(disable : 4244) /* 'return': conversion from 'LONGLONG' to \ - 'std::size_t', possible loss of data */ -#pragma warning(disable : 4267) /* 'function': conversion from 'size_t' to \ - 'long', possible loss of data */ -#pragma intrinsic(_InterlockedExchangeAdd, _InterlockedCompareExchange) -#pragma intrinsic(_InterlockedExchangeAdd64, _InterlockedCompareExchange64) -#elif defined(__APPLE__) -#include -#else -#error FIXME atomic-ops -#endif - #endif /* !__cplusplus */ /*----------------------------------------------------------------------------*/