diff options
author | RĂ©mi Verschelde <rverschelde@gmail.com> | 2017-07-31 23:30:07 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-07-31 23:30:07 +0200 |
commit | 597ffa03b3399240e806ee524dd3f9725eefb7ab (patch) | |
tree | e66ccfddea22e7cdc0edbaa7f9fdaf1d83117dfa | |
parent | 878f34d1e1a18398e7e12c778785aee7a1de3367 (diff) | |
parent | 27637b9e7f6f7dc59768623225a687f2d595692f (diff) |
Merge pull request #9826 from RandomShaper/improve-atomics
Improve/add atomics
-rw-r--r-- | core/safe_refcount.cpp | 56 | ||||
-rw-r--r-- | core/safe_refcount.h | 2 |
2 files changed, 50 insertions, 8 deletions
diff --git a/core/safe_refcount.cpp b/core/safe_refcount.cpp index d7e5297321..971e9ad1d5 100644 --- a/core/safe_refcount.cpp +++ b/core/safe_refcount.cpp @@ -78,6 +78,15 @@ static _ALWAYS_INLINE_ T _atomic_add_impl(register T *pw, register T val) { return *pw; } +template <class T> +static _ALWAYS_INLINE_ T _atomic_exchange_if_greater_impl(register T *pw, register T val) { + + if (val > *pw) + *pw = val; + + return *pw; +} + #elif defined(__GNUC__) /* Implementation for GCC & Clang */ @@ -121,6 +130,18 @@ static _ALWAYS_INLINE_ T _atomic_add_impl(register T *pw, register T val) { return __sync_add_and_fetch(pw, val); } +template <class T> +static _ALWAYS_INLINE_ T _atomic_exchange_if_greater_impl(register T *pw, register T val) { + + while (true) { + T tmp = static_cast<T const volatile &>(*pw); + if (tmp >= val) + return tmp; // already greater, or equal + if (__sync_val_compare_and_swap(pw, tmp, val) == tmp) + return val; + } +} + #elif defined(_MSC_VER) /* Implementation for MSVC-Windows */ @@ -139,6 +160,15 @@ static _ALWAYS_INLINE_ T _atomic_add_impl(register T *pw, register T val) { return tmp + 1; \ } +#define ATOMIC_EXCHANGE_IF_GREATER_BODY(m_pw, m_val, m_win_type, m_win_cmpxchg, m_cpp_type) \ + while (true) { \ + m_cpp_type tmp = static_cast<m_cpp_type const volatile &>(*(m_pw)); \ + if (tmp >= m_val) \ + return tmp; /* already greater, or equal */ \ + if (m_win_cmpxchg((m_win_type volatile *)(m_pw), m_val, tmp) == tmp) \ + return m_val; \ + } + static _ALWAYS_INLINE_ uint32_t _atomic_conditional_increment_impl(register uint32_t *pw) { ATOMIC_CONDITIONAL_INCREMENT_BODY(pw, LONG, InterlockedCompareExchange, uint32_t) @@ -156,11 +186,7 @@ static _ALWAYS_INLINE_ uint32_t _atomic_increment_impl(register uint32_t *pw) { static _ALWAYS_INLINE_ uint32_t _atomic_sub_impl(register uint32_t *pw, register uint32_t val) { -#if _WIN32_WINNT >= 0x0601 // Windows 7+ - return InterlockedExchangeSubtract(pw, val) - val; -#else return InterlockedExchangeAdd((LONG volatile *)pw, -(int32_t)val) - val; -#endif } static _ALWAYS_INLINE_ uint32_t _atomic_add_impl(register uint32_t *pw, register uint32_t val) { @@ -168,6 +194,11 @@ static _ALWAYS_INLINE_ uint32_t _atomic_add_impl(register uint32_t *pw, register return InterlockedAdd((LONG volatile *)pw, val); } +static _ALWAYS_INLINE_ uint32_t _atomic_exchange_if_greater_impl(register uint32_t *pw, register uint32_t val) { + + ATOMIC_EXCHANGE_IF_GREATER_BODY(pw, val, LONG, InterlockedCompareExchange, uint32_t) +} + static _ALWAYS_INLINE_ uint64_t _atomic_conditional_increment_impl(register uint64_t *pw) { ATOMIC_CONDITIONAL_INCREMENT_BODY(pw, LONGLONG, InterlockedCompareExchange64, uint64_t) @@ -185,11 +216,7 @@ static _ALWAYS_INLINE_ uint64_t _atomic_increment_impl(register uint64_t *pw) { static _ALWAYS_INLINE_ uint64_t _atomic_sub_impl(register uint64_t *pw, register uint64_t val) { -#if _WIN32_WINNT >= 0x0601 && !defined(UWP_ENABLED) // Windows 7+ except UWP - return InterlockedExchangeSubtract64(pw, val) - val; -#else return InterlockedExchangeAdd64((LONGLONG volatile *)pw, -(int64_t)val) - val; -#endif } static _ALWAYS_INLINE_ uint64_t _atomic_add_impl(register uint64_t *pw, register uint64_t val) { @@ -197,6 +224,11 @@ static _ALWAYS_INLINE_ uint64_t _atomic_add_impl(register uint64_t *pw, register return InterlockedAdd64((LONGLONG volatile *)pw, val); } +static _ALWAYS_INLINE_ uint64_t _atomic_exchange_if_greater_impl(register uint64_t *pw, register uint64_t val) { + + ATOMIC_EXCHANGE_IF_GREATER_BODY(pw, val, LONGLONG, InterlockedCompareExchange64, uint64_t) +} + #else //no threads supported? @@ -226,6 +258,10 @@ uint32_t atomic_add(register uint32_t *pw, register uint32_t val) { return _atomic_add_impl(pw, val); } +uint32_t atomic_exchange_if_greater(register uint32_t *pw, register uint32_t val) { + return _atomic_exchange_if_greater_impl(pw, val); +} + uint64_t atomic_conditional_increment(register uint64_t *counter) { return _atomic_conditional_increment_impl(counter); } @@ -245,3 +281,7 @@ uint64_t atomic_sub(register uint64_t *pw, register uint64_t val) { uint64_t atomic_add(register uint64_t *pw, register uint64_t val) { return _atomic_add_impl(pw, val); } + +uint64_t atomic_exchange_if_greater(register uint64_t *pw, register uint64_t val) { + return _atomic_exchange_if_greater_impl(pw, val); +} diff --git a/core/safe_refcount.h b/core/safe_refcount.h index a2d2b5e127..ed0620c777 100644 --- a/core/safe_refcount.h +++ b/core/safe_refcount.h @@ -41,12 +41,14 @@ uint32_t atomic_decrement(register uint32_t *pw); uint32_t atomic_increment(register uint32_t *pw); uint32_t atomic_sub(register uint32_t *pw, register uint32_t val); uint32_t atomic_add(register uint32_t *pw, register uint32_t val); +uint32_t atomic_exchange_if_greater(register uint32_t *pw, register uint32_t val); uint64_t atomic_conditional_increment(register uint64_t *counter); uint64_t atomic_decrement(register uint64_t *pw); uint64_t atomic_increment(register uint64_t *pw); uint64_t atomic_sub(register uint64_t *pw, register uint64_t val); uint64_t atomic_add(register uint64_t *pw, register uint64_t val); +uint64_t atomic_exchange_if_greater(register uint64_t *pw, register uint64_t val); struct SafeRefCount { |