diff options
-rw-r--r-- | src/corelib/arch/qatomic_armv5.h | 7 | ||||
-rw-r--r-- | src/corelib/arch/qatomic_armv6.h | 96 | ||||
-rw-r--r-- | src/corelib/arch/qatomic_cxx11.h | 30 | ||||
-rw-r--r-- | src/corelib/arch/qatomic_gcc.h | 11 | ||||
-rw-r--r-- | src/corelib/arch/qatomic_ia64.h | 40 | ||||
-rw-r--r-- | src/corelib/arch/qatomic_mips.h | 19 | ||||
-rw-r--r-- | src/corelib/arch/qatomic_msvc.h | 31 | ||||
-rw-r--r-- | src/corelib/arch/qatomic_x86.h | 32 | ||||
-rw-r--r-- | src/corelib/thread/qbasicatomic.h | 18 | ||||
-rw-r--r-- | src/corelib/thread/qgenericatomic.h | 24 | ||||
-rw-r--r-- | tests/auto/corelib/thread/qatomicint/tst_qatomicint.cpp | 91 | ||||
-rw-r--r-- | tests/auto/corelib/thread/qatomicinteger/tst_qatomicinteger.cpp | 382 | ||||
-rw-r--r-- | tests/auto/corelib/thread/qatomicpointer/tst_qatomicpointer.cpp | 53 |
13 files changed, 803 insertions, 31 deletions
diff --git a/src/corelib/arch/qatomic_armv5.h b/src/corelib/arch/qatomic_armv5.h index 237ff5f254..6939650c54 100644 --- a/src/corelib/arch/qatomic_armv5.h +++ b/src/corelib/arch/qatomic_armv5.h @@ -133,13 +133,16 @@ bool QBasicAtomicOps<4>::deref(T &_q_value) Q_DECL_NOTHROW } template<> template <typename T> inline -bool QBasicAtomicOps<4>::testAndSetRelaxed(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW +bool QBasicAtomicOps<4>::testAndSetRelaxed(T &_q_value, T expectedValue, T newValue, T *currentValue) Q_DECL_NOTHROW { T originalValue; do { originalValue = _q_value; - if (originalValue != expectedValue) + if (originalValue != expectedValue) { + if (currentValue) + *currentValue = originalValue; return false; + } } while (_q_cmpxchg(expectedValue, newValue, &_q_value) != 0); return true; } diff --git a/src/corelib/arch/qatomic_armv6.h b/src/corelib/arch/qatomic_armv6.h index 37df64141c..4f1c758ded 100644 --- a/src/corelib/arch/qatomic_armv6.h +++ b/src/corelib/arch/qatomic_armv6.h @@ -81,6 +81,8 @@ template <int size> struct QBasicAtomicOps: QGenericAtomicOps<QBasicAtomicOps<si static inline Q_DECL_CONSTEXPR bool isTestAndSetNative() Q_DECL_NOTHROW { return true; } static inline Q_DECL_CONSTEXPR bool isTestAndSetWaitFree() Q_DECL_NOTHROW { return false; } template <typename T> static bool testAndSetRelaxed(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW; + template <typename T> static bool testAndSetRelaxed(T &_q_value, T expectedValue, + T newValue, T *currentValue) Q_DECL_NOTHROW; static inline Q_DECL_CONSTEXPR bool isFetchAndStoreNative() Q_DECL_NOTHROW { return true; } template <typename T> static T fetchAndStoreRelaxed(T &_q_value, T newValue) Q_DECL_NOTHROW; @@ -163,6 +165,29 @@ bool QBasicAtomicOps<4>::testAndSetRelaxed(T &_q_value, T expectedValue, T newVa } template<> template <typename T> inline +bool QBasicAtomicOps<4>::testAndSetRelaxed(T &_q_value, T expectedValue, T newValue, T *currentValue) Q_DECL_NOTHROW +{ + register T tempValue; + register int result; + asm volatile("0:\n" + "ldrex %[tempValue], [%[_q_value]]\n" + "eors %[result], %[tempValue], %[expectedValue]\n" + "itt eq\n" + "strexeq %[result], %[newValue], [%[_q_value]]\n" + "teqeq %[result], #1\n" + "beq 0b\n" + : [result] "=&r" (result), + [tempValue] "=&r" (tempValue), + "+m" (_q_value) + : [expectedValue] "r" (expectedValue), + [newValue] "r" (newValue), + [_q_value] "r" (&_q_value) + : "cc"); + *currentValue = tempValue; + return result == 0; +} + +template<> template <typename T> inline T QBasicAtomicOps<4>::fetchAndStoreRelaxed(T &_q_value, T newValue) Q_DECL_NOTHROW { T originalValue; @@ -291,6 +316,29 @@ bool QBasicAtomicOps<1>::testAndSetRelaxed(T &_q_value, T expectedValue, T newVa } template<> template <typename T> inline +bool QBasicAtomicOps<1>::testAndSetRelaxed(T &_q_value, T expectedValue, T newValue, T *currentValue) Q_DECL_NOTHROW +{ + register T tempValue; + register T result; + asm volatile("0:\n" + "ldrexb %[tempValue], [%[_q_value]]\n" + "eors %[result], %[tempValue], %[expectedValue]\n" + "itt eq\n" + "strexbeq %[result], %[newValue], [%[_q_value]]\n" + "teqeq %[result], #1\n" + "beq 0b\n" + : [result] "=&r" (result), + [tempValue] "=&r" (tempValue), + "+m" (_q_value) + : [expectedValue] "r" (expectedValue), + [newValue] "r" (newValue), + [_q_value] "r" (&_q_value) + : "cc"); + *currentValue = tempValue; + return result == 0; +} + +template<> template <typename T> inline T QBasicAtomicOps<1>::fetchAndStoreRelaxed(T &_q_value, T newValue) Q_DECL_NOTHROW { T originalValue; @@ -390,6 +438,29 @@ bool QBasicAtomicOps<2>::testAndSetRelaxed(T &_q_value, T expectedValue, T newVa } template<> template <typename T> inline +bool QBasicAtomicOps<2>::testAndSetRelaxed(T &_q_value, T expectedValue, T newValue, T *currentValue) Q_DECL_NOTHROW +{ + register T tempValue; + register T result; + asm volatile("0:\n" + "ldrexh %[tempValue], [%[_q_value]]\n" + "eors %[result], %[tempValue], %[expectedValue]\n" + "itt eq\n" + "strexheq %[result], %[newValue], [%[_q_value]]\n" + "teqeq %[result], #1\n" + "beq 0b\n" + : [result] "=&r" (result), + [tempValue] "=&r" (tempValue), + "+m" (_q_value) + : [expectedValue] "r" (expectedValue), + [newValue] "r" (newValue), + [_q_value] "r" (&_q_value) + : "cc"); + *currentValue = tempValue; + return result == 0; +} + +template<> template <typename T> inline T QBasicAtomicOps<2>::fetchAndStoreRelaxed(T &_q_value, T newValue) Q_DECL_NOTHROW { T originalValue; @@ -501,6 +572,31 @@ bool QBasicAtomicOps<8>::testAndSetRelaxed(T &_q_value, T expectedValue, T newVa } template<> template <typename T> inline +bool QBasicAtomicOps<8>::testAndSetRelaxed(T &_q_value, T expectedValue, T newValue, T *currentValue) Q_DECL_NOTHROW +{ + register T tempValue; + register T result; + asm volatile("0:\n" + "ldrexd %[tempValue], %H[tempValue], [%[_q_value]]\n" + "eor %[result], %[tempValue], %[expectedValue]\n" + "eor %H[result], %H[tempValue], %H[expectedValue]\n" + "orrs %[result], %[result], %H[result]\n" + "itt eq\n" + "strexdeq %[result], %[newValue], %H[newValue], [%[_q_value]]\n" + "teqeq %[result], #1\n" + "beq 0b\n" + : [result] "=&r" (result), + [tempValue] "=&r" (tempValue), + "+m" (_q_value) + : [expectedValue] "r" (expectedValue), + [newValue] "r" (newValue), + [_q_value] "r" (&_q_value) + : "cc"); + *currentValue = tempValue; + return quint32(result) == 0; +} + +template<> template <typename T> inline T QBasicAtomicOps<8>::fetchAndStoreRelaxed(T &_q_value, T newValue) Q_DECL_NOTHROW { T originalValue; diff --git a/src/corelib/arch/qatomic_cxx11.h b/src/corelib/arch/qatomic_cxx11.h index 85575da20e..b07e470484 100644 --- a/src/corelib/arch/qatomic_cxx11.h +++ b/src/corelib/arch/qatomic_cxx11.h @@ -149,28 +149,40 @@ template <typename X> struct QAtomicOps static inline Q_DECL_CONSTEXPR bool isTestAndSetNative() Q_DECL_NOTHROW { return false; } static inline Q_DECL_CONSTEXPR bool isTestAndSetWaitFree() Q_DECL_NOTHROW { return false; } - template <typename T> static - bool testAndSetRelaxed(Type &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW + template <typename T> + static bool testAndSetRelaxed(std::atomic<T> &_q_value, T expectedValue, T newValue, T *currentValue = 0) Q_DECL_NOTHROW { - return _q_value.compare_exchange_strong(expectedValue, newValue, std::memory_order_relaxed); + bool tmp = _q_value.compare_exchange_strong(expectedValue, newValue, std::memory_order_relaxed); + if (currentValue) + *currentValue = expectedValue; + return tmp; } template <typename T> - static bool testAndSetAcquire(Type &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW + static bool testAndSetAcquire(std::atomic<T> &_q_value, T expectedValue, T newValue, T *currentValue = 0) Q_DECL_NOTHROW { - return _q_value.compare_exchange_strong(expectedValue, newValue, std::memory_order_acquire); + bool tmp = _q_value.compare_exchange_strong(expectedValue, newValue, std::memory_order_acquire); + if (currentValue) + *currentValue = expectedValue; + return tmp; } template <typename T> - static bool testAndSetRelease(Type &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW + static bool testAndSetRelease(std::atomic<T> &_q_value, T expectedValue, T newValue, T *currentValue = 0) Q_DECL_NOTHROW { - return _q_value.compare_exchange_strong(expectedValue, newValue, std::memory_order_release); + bool tmp = _q_value.compare_exchange_strong(expectedValue, newValue, std::memory_order_release); + if (currentValue) + *currentValue = expectedValue; + return tmp; } template <typename T> - static bool testAndSetOrdered(Type &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW + static bool testAndSetOrdered(std::atomic<T> &_q_value, T expectedValue, T newValue, T *currentValue = 0) Q_DECL_NOTHROW { - return _q_value.compare_exchange_strong(expectedValue, newValue, std::memory_order_acq_rel); + bool tmp = _q_value.compare_exchange_strong(expectedValue, newValue, std::memory_order_acq_rel); + if (currentValue) + *currentValue = expectedValue; + return tmp; } static inline Q_DECL_CONSTEXPR bool isFetchAndStoreNative() Q_DECL_NOTHROW { return false; } diff --git a/src/corelib/arch/qatomic_gcc.h b/src/corelib/arch/qatomic_gcc.h index 052453c082..5184293465 100644 --- a/src/corelib/arch/qatomic_gcc.h +++ b/src/corelib/arch/qatomic_gcc.h @@ -113,6 +113,17 @@ template <typename X> struct QAtomicOps: QGenericAtomicOps<QAtomicOps<X> > } template <typename T> + static bool testAndSetRelaxed(T &_q_value, T expectedValue, T newValue, T *currentValue) Q_DECL_NOTHROW + { + bool tmp = __sync_bool_compare_and_swap(&_q_value, expectedValue, newValue); + if (tmp) + *currentValue = expectedValue; + else + *currentValue = _q_value; + return tmp; + } + + template <typename T> static T fetchAndStoreRelaxed(T &_q_value, T newValue) Q_DECL_NOTHROW { return __sync_lock_test_and_set(&_q_value, newValue); diff --git a/src/corelib/arch/qatomic_ia64.h b/src/corelib/arch/qatomic_ia64.h index 0075f32a42..e5e93ec2b7 100644 --- a/src/corelib/arch/qatomic_ia64.h +++ b/src/corelib/arch/qatomic_ia64.h @@ -150,10 +150,10 @@ template <int size> struct QBasicAtomicOps: QGenericAtomicOps<QBasicAtomicOps<si static inline Q_DECL_CONSTEXPR bool isTestAndSetNative() Q_DECL_NOTHROW { return true; } static inline Q_DECL_CONSTEXPR bool isTestAndSetWaitFree() Q_DECL_NOTHROW { return true; } - template <typename T> static bool testAndSetRelaxed(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW; - template <typename T> static bool testAndSetAcquire(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW; - template <typename T> static bool testAndSetRelease(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW; - template <typename T> static bool testAndSetOrdered(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW; + template <typename T> static bool testAndSetRelaxed(T &_q_value, T expectedValue, T newValue, T *currentValue = 0) Q_DECL_NOTHROW; + template <typename T> static bool testAndSetAcquire(T &_q_value, T expectedValue, T newValue, T *currentValue = 0) Q_DECL_NOTHROW; + template <typename T> static bool testAndSetRelease(T &_q_value, T expectedValue, T newValue, T *currentValue = 0) Q_DECL_NOTHROW; + template <typename T> static bool testAndSetOrdered(T &_q_value, T expectedValue, T newValue, T *currentValue = 0) Q_DECL_NOTHROW; static inline Q_DECL_CONSTEXPR bool isFetchAndStoreNative() Q_DECL_NOTHROW { return true; } static inline Q_DECL_CONSTEXPR bool isFetchAndStoreWaitFree() Q_DECL_NOTHROW { return true; } @@ -373,7 +373,7 @@ bool QBasicAtomicOps<8>::deref(T &_q_value) Q_DECL_NOTHROW } template<> template <typename T> inline -bool QBasicAtomicOps<1>::testAndSetAcquire(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW +bool QBasicAtomicOps<1>::testAndSetAcquire(T &_q_value, T expectedValue, T newValue, T *currentValue) Q_DECL_NOTHROW { T ret; asm volatile("mov ar.ccv=%2\n" @@ -382,11 +382,13 @@ bool QBasicAtomicOps<1>::testAndSetAcquire(T &_q_value, T expectedValue, T newVa : "=r" (ret), "+m" (_q_value) : "r" (expectedValue), "r" (newValue) : "memory"); + if (currentValue) + *currentValue = ret; return ret == expectedValue; } template<> template <typename T> inline -bool QBasicAtomicOps<1>::testAndSetRelease(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW +bool QBasicAtomicOps<1>::testAndSetRelease(T &_q_value, T expectedValue, T newValue, T *currentValue) Q_DECL_NOTHROW { T ret; asm volatile("mov ar.ccv=%2\n" @@ -395,11 +397,13 @@ bool QBasicAtomicOps<1>::testAndSetRelease(T &_q_value, T expectedValue, T newVa : "=r" (ret), "+m" (_q_value) : "r" (expectedValue), "r" (newValue) : "memory"); + if (currentValue) + *currentValue = ret; return ret == expectedValue; } template<> template <typename T> inline -bool QBasicAtomicOps<2>::testAndSetAcquire(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW +bool QBasicAtomicOps<2>::testAndSetAcquire(T &_q_value, T expectedValue, T newValue, T *currentValue) Q_DECL_NOTHROW { T ret; asm volatile("mov ar.ccv=%2\n" @@ -408,11 +412,13 @@ bool QBasicAtomicOps<2>::testAndSetAcquire(T &_q_value, T expectedValue, T newVa : "=r" (ret), "+m" (_q_value) : "r" (expectedValue), "r" (newValue) : "memory"); + if (currentValue) + *currentValue = ret; return ret == expectedValue; } template<> template <typename T> inline -bool QBasicAtomicOps<2>::testAndSetRelease(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW +bool QBasicAtomicOps<2>::testAndSetRelease(T &_q_value, T expectedValue, T newValue, T *currentValue) Q_DECL_NOTHROW { T ret; asm volatile("mov ar.ccv=%2\n" @@ -421,11 +427,13 @@ bool QBasicAtomicOps<2>::testAndSetRelease(T &_q_value, T expectedValue, T newVa : "=r" (ret), "+m" (_q_value) : "r" (expectedValue), "r" (newValue) : "memory"); + if (currentValue) + *currentValue = ret; return ret == expectedValue; } template<> template <typename T> inline -bool QBasicAtomicOps<4>::testAndSetAcquire(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW +bool QBasicAtomicOps<4>::testAndSetAcquire(T &_q_value, T expectedValue, T newValue, T *currentValue) Q_DECL_NOTHROW { T ret; asm volatile("mov ar.ccv=%2\n" @@ -434,11 +442,13 @@ bool QBasicAtomicOps<4>::testAndSetAcquire(T &_q_value, T expectedValue, T newVa : "=r" (ret), "+m" (_q_value) : "r" (expectedValue), "r" (newValue) : "memory"); + if (currentValue) + *currentValue = ret; return ret == expectedValue; } template<> template <typename T> inline -bool QBasicAtomicOps<4>::testAndSetRelease(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW +bool QBasicAtomicOps<4>::testAndSetRelease(T &_q_value, T expectedValue, T newValue, T *currentValue) Q_DECL_NOTHROW { T ret; asm volatile("mov ar.ccv=%2\n" @@ -447,11 +457,13 @@ bool QBasicAtomicOps<4>::testAndSetRelease(T &_q_value, T expectedValue, T newVa : "=r" (ret), "+m" (_q_value) : "r" (expectedValue), "r" (newValue) : "memory"); + if (currentValue) + *currentValue = ret; return ret == expectedValue; } template<> template <typename T> inline -bool QBasicAtomicOps<8>::testAndSetAcquire(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW +bool QBasicAtomicOps<8>::testAndSetAcquire(T &_q_value, T expectedValue, T newValue, T *currentValue) Q_DECL_NOTHROW { T ret; asm volatile("mov ar.ccv=%2\n" @@ -460,11 +472,13 @@ bool QBasicAtomicOps<8>::testAndSetAcquire(T &_q_value, T expectedValue, T newVa : "=r" (ret), "+m" (_q_value) : "r" (expectedValue), "r" (newValue) : "memory"); + if (currentValue) + *currentValue = ret; return ret == expectedValue; } template<> template <typename T> inline -bool QBasicAtomicOps<8>::testAndSetRelease(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW +bool QBasicAtomicOps<8>::testAndSetRelease(T &_q_value, T expectedValue, T newValue, T *currentValue) Q_DECL_NOTHROW { T ret; asm volatile("mov ar.ccv=%2\n" @@ -473,6 +487,8 @@ bool QBasicAtomicOps<8>::testAndSetRelease(T &_q_value, T expectedValue, T newVa : "=r" (ret), "+m" (_q_value) : "r" (expectedValue), "r" (newValue) : "memory"); + if (currentValue) + *currentValue = ret; return ret == expectedValue; } diff --git a/src/corelib/arch/qatomic_mips.h b/src/corelib/arch/qatomic_mips.h index 9c744b885d..463612212b 100644 --- a/src/corelib/arch/qatomic_mips.h +++ b/src/corelib/arch/qatomic_mips.h @@ -84,7 +84,8 @@ template <int size> struct QBasicAtomicOps: QGenericAtomicOps<QBasicAtomicOps<si static inline Q_DECL_CONSTEXPR bool isTestAndSetNative() Q_DECL_NOTHROW { return true; } static inline Q_DECL_CONSTEXPR bool isTestAndSetWaitFree() Q_DECL_NOTHROW { return false; } - template <typename T> static bool testAndSetRelaxed(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW; + template <typename T> static bool + testAndSetRelaxed(T &_q_value, T expectedValue, T newValue, T *currentValue = 0) Q_DECL_NOTHROW; static inline Q_DECL_CONSTEXPR bool isFetchAndStoreNative() Q_DECL_NOTHROW { return true; } template <typename T> static T fetchAndStoreRelaxed(T &_q_value, T newValue) Q_DECL_NOTHROW; @@ -163,13 +164,13 @@ bool QBasicAtomicOps<4>::deref(T &_q_value) Q_DECL_NOTHROW } template<> template <typename T> inline -bool QBasicAtomicOps<4>::testAndSetRelaxed(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW +bool QBasicAtomicOps<4>::testAndSetRelaxed(T &_q_value, T expectedValue, T newValue, T *currentValue) Q_DECL_NOTHROW { T result; T tempValue; asm volatile("0:\n" - "ll %[result], %[_q_value]\n" - "xor %[result], %[result], %[expectedValue]\n" + "ll %[tempValue], %[_q_value]\n" + "xor %[result], %[tempValue], %[expectedValue]\n" "bnez %[result], 0f\n" "nop\n" "move %[tempValue], %[newValue]\n" @@ -183,6 +184,8 @@ bool QBasicAtomicOps<4>::testAndSetRelaxed(T &_q_value, T expectedValue, T newVa : [expectedValue] "r" (expectedValue), [newValue] "r" (newValue) : "cc", "memory"); + if (currentValue) + *currentValue = tempValue; return result == 0; } @@ -273,13 +276,13 @@ bool QBasicAtomicOps<8>::deref(T &_q_value) Q_DECL_NOTHROW } template<> template <typename T> inline -bool QBasicAtomicOps<8>::testAndSetRelaxed(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW +bool QBasicAtomicOps<8>::testAndSetRelaxed(T &_q_value, T expectedValue, T newValue, T *currentValue) Q_DECL_NOTHROW { T result; T tempValue; asm volatile("0:\n" - "lld %[result], %[_q_value]\n" - "xor %[result], %[result], %[expectedValue]\n" + "lld %[tempValue], %[_q_value]\n" + "xor %[result], %[tempValue], %[expectedValue]\n" "bnez %[result], 0f\n" "nop\n" "move %[tempValue], %[newValue]\n" @@ -293,6 +296,8 @@ bool QBasicAtomicOps<8>::testAndSetRelaxed(T &_q_value, T expectedValue, T newVa : [expectedValue] "r" (expectedValue), [newValue] "r" (newValue) : "cc", "memory"); + if (currentValue) + *currentValue = tempValue; return result == 0; } diff --git a/src/corelib/arch/qatomic_msvc.h b/src/corelib/arch/qatomic_msvc.h index 1cbb1442ed..c660f78888 100644 --- a/src/corelib/arch/qatomic_msvc.h +++ b/src/corelib/arch/qatomic_msvc.h @@ -310,6 +310,8 @@ template <int N> struct QAtomicOpsBySize : QGenericAtomicOps<QAtomicOpsBySize<N> static inline Q_DECL_CONSTEXPR bool isTestAndSetNative() Q_DECL_NOTHROW { return true; } static inline Q_DECL_CONSTEXPR bool isTestAndSetWaitFree() Q_DECL_NOTHROW { return true; } template <typename T> static bool testAndSetRelaxed(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW; + template <typename T> + static bool testAndSetRelaxed(T &_q_value, T expectedValue, T newValue, T *currentValue) Q_DECL_NOTHROW; static inline Q_DECL_CONSTEXPR bool isFetchAndStoreNative() Q_DECL_NOTHROW { return true; } static inline Q_DECL_CONSTEXPR bool isFetchAndStoreWaitFree() Q_DECL_NOTHROW { return true; } @@ -351,6 +353,13 @@ inline bool QAtomicOpsBySize<4>::testAndSetRelaxed(T &_q_value, T expectedValue, return QT_INTERLOCKED_FUNCTION(CompareExchange)(atomic(&_q_value), value(newValue), value(expectedValue)) == value(expectedValue); } +template<> template <typename T> +inline bool QAtomicOpsBySize<4>::testAndSetRelaxed(T &_q_value, T expectedValue, T newValue, T *currentValue) Q_DECL_NOTHROW +{ + *currentValue = T(QT_INTERLOCKED_FUNCTION(CompareExchange)(atomic(&_q_value), newValue, expectedValue)); + return *currentValue == expectedValue; +} + template<> template<typename T> inline T QAtomicOpsBySize<4>::fetchAndStoreRelaxed(T &_q_value, T newValue) Q_DECL_NOTHROW { @@ -382,6 +391,13 @@ inline bool QAtomicOpsBySize<2>::testAndSetRelaxed(T &_q_value, T expectedValue, return QT_INTERLOCKED_FUNCTION(CompareExchange16)(atomic(&_q_value), value(newValue), value(expectedValue)) == value(expectedValue); } +template<> template <typename T> +inline bool QAtomicOpsBySize<2>::testAndSetRelaxed(T &_q_value, T expectedValue, T newValue, T *currentValue) Q_DECL_NOTHROW +{ + *currentValue = T(QT_INTERLOCKED_FUNCTION(CompareExchange16)(atomic(&_q_value), newValue, expectedValue)); + return *currentValue == expectedValue; +} + template<> template<typename T> inline T QAtomicOpsBySize<2>::fetchAndStoreRelaxed(T &_q_value, T newValue) Q_DECL_NOTHROW { @@ -414,6 +430,13 @@ inline bool QAtomicOpsBySize<8>::testAndSetRelaxed(T &_q_value, T expectedValue, return QT_INTERLOCKED_FUNCTION(CompareExchange64)(atomic(&_q_value), value(newValue), value(expectedValue)) == value(expectedValue); } +template<> template <typename T> +inline bool QAtomicOpsBySize<8>::testAndSetRelaxed(T &_q_value, T expectedValue, T newValue, T *currentValue) Q_DECL_NOTHROW +{ + *currentValue = T(QT_INTERLOCKED_FUNCTION(CompareExchange64)(atomic(&_q_value), newValue, expectedValue)); + return *currentValue == expectedValue; +} + template<> template<typename T> inline T QAtomicOpsBySize<8>::fetchAndStoreRelaxed(T &_q_value, T newValue) Q_DECL_NOTHROW { @@ -436,6 +459,7 @@ struct QAtomicOps<T *> : QGenericAtomicOps<QAtomicOps<T *> > static inline Q_DECL_CONSTEXPR bool isTestAndSetNative() Q_DECL_NOTHROW { return true; } static inline Q_DECL_CONSTEXPR bool isTestAndSetWaitFree() Q_DECL_NOTHROW { return true; } static bool testAndSetRelaxed(T *&_q_value, T *expectedValue, T *newValue) Q_DECL_NOTHROW; + static bool testAndSetRelaxed(T *&_q_value, T *expectedValue, T *newValue, T **currentValue) Q_DECL_NOTHROW; static inline Q_DECL_CONSTEXPR bool isFetchAndStoreNative() Q_DECL_NOTHROW { return true; } static inline Q_DECL_CONSTEXPR bool isFetchAndStoreWaitFree() Q_DECL_NOTHROW { return true; } @@ -453,6 +477,13 @@ inline bool QAtomicOps<T *>::testAndSetRelaxed(T *&_q_value, T *expectedValue, T } template <typename T> +inline bool QAtomicOps<T *>::testAndSetRelaxed(T *&_q_value, T *expectedValue, T *newValue, T **currentValue) Q_DECL_NOTHROW +{ + *currentValue = reinterpret_cast<T *>(QT_INTERLOCKED_COMPARE_EXCHANGE_POINTER(&_q_value, newValue, expectedValue)); + return *currentValue == expectedValue; +} + +template <typename T> inline T *QAtomicOps<T *>::fetchAndStoreRelaxed(T *&_q_value, T *newValue) Q_DECL_NOTHROW { return reinterpret_cast<T *>(QT_INTERLOCKED_EXCHANGE_POINTER(&_q_value, newValue)); diff --git a/src/corelib/arch/qatomic_x86.h b/src/corelib/arch/qatomic_x86.h index 2013d8f991..e3cb296527 100644 --- a/src/corelib/arch/qatomic_x86.h +++ b/src/corelib/arch/qatomic_x86.h @@ -99,6 +99,8 @@ template <int size> struct QBasicAtomicOps: QGenericAtomicOps<QBasicAtomicOps<si static inline Q_DECL_CONSTEXPR bool isTestAndSetNative() Q_DECL_NOTHROW { return true; } static inline Q_DECL_CONSTEXPR bool isTestAndSetWaitFree() Q_DECL_NOTHROW { return true; } template <typename T> static bool testAndSetRelaxed(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW; + template <typename T> static bool + testAndSetRelaxed(T &_q_value, T expectedValue, T newValue, T *currentValue) Q_DECL_NOTHROW; static inline Q_DECL_CONSTEXPR bool isFetchAndStoreNative() Q_DECL_NOTHROW { return true; } static inline Q_DECL_CONSTEXPR bool isFetchAndStoreWaitFree() Q_DECL_NOTHROW { return true; } @@ -253,6 +255,36 @@ bool QBasicAtomicOps<1>::testAndSetRelaxed(T &_q_value, T expectedValue, T newVa } template<int size> template <typename T> inline +bool QBasicAtomicOps<size>::testAndSetRelaxed(T &_q_value, T expectedValue, + T newValue, T *currentValue) Q_DECL_NOTHROW +{ + unsigned char ret; + asm volatile("lock\n" + "cmpxchg %3,%2\n" + "sete %1\n" + : "=a" (newValue), "=qm" (ret), "+m" (_q_value) + : "r" (newValue), "0" (expectedValue) + : "memory"); + *currentValue = newValue; + return ret != 0; +} + +template<> template <typename T> inline +bool QBasicAtomicOps<1>::testAndSetRelaxed(T &_q_value, T expectedValue, + T newValue, T *currentValue) Q_DECL_NOTHROW +{ + unsigned char ret; + asm volatile("lock\n" + "cmpxchg %3,%2\n" + "sete %1\n" + : "=a" (newValue), "=qm" (ret), "+m" (_q_value) + : "q" (newValue), "0" (expectedValue) + : "memory"); + *currentValue = newValue; + return ret != 0; +} + +template<int size> template <typename T> inline T QBasicAtomicOps<size>::fetchAndStoreRelaxed(T &_q_value, T newValue) Q_DECL_NOTHROW { asm volatile("xchg %0,%1" diff --git a/src/corelib/thread/qbasicatomic.h b/src/corelib/thread/qbasicatomic.h index f75a24ae10..b2234bdb80 100644 --- a/src/corelib/thread/qbasicatomic.h +++ b/src/corelib/thread/qbasicatomic.h @@ -145,6 +145,15 @@ public: bool testAndSetOrdered(T expectedValue, T newValue) Q_DECL_NOTHROW { return Ops::testAndSetOrdered(_q_value, expectedValue, newValue); } + bool testAndSetRelaxed(T expectedValue, T newValue, T ¤tValue) Q_DECL_NOTHROW + { return Ops::testAndSetRelaxed(_q_value, expectedValue, newValue, ¤tValue); } + bool testAndSetAcquire(T expectedValue, T newValue, T ¤tValue) Q_DECL_NOTHROW + { return Ops::testAndSetAcquire(_q_value, expectedValue, newValue, ¤tValue); } + bool testAndSetRelease(T expectedValue, T newValue, T ¤tValue) Q_DECL_NOTHROW + { return Ops::testAndSetRelease(_q_value, expectedValue, newValue, ¤tValue); } + bool testAndSetOrdered(T expectedValue, T newValue, T ¤tValue) Q_DECL_NOTHROW + { return Ops::testAndSetOrdered(_q_value, expectedValue, newValue, ¤tValue); } + static Q_DECL_CONSTEXPR bool isFetchAndStoreNative() Q_DECL_NOTHROW { return Ops::isFetchAndStoreNative(); } static Q_DECL_CONSTEXPR bool isFetchAndStoreWaitFree() Q_DECL_NOTHROW { return Ops::isFetchAndStoreWaitFree(); } @@ -209,6 +218,15 @@ public: bool testAndSetOrdered(Type expectedValue, Type newValue) Q_DECL_NOTHROW { return Ops::testAndSetOrdered(_q_value, expectedValue, newValue); } + bool testAndSetRelaxed(Type expectedValue, Type newValue, Type ¤tValue) Q_DECL_NOTHROW + { return Ops::testAndSetRelaxed(_q_value, expectedValue, newValue, ¤tValue); } + bool testAndSetAcquire(Type expectedValue, Type newValue, Type ¤tValue) Q_DECL_NOTHROW + { return Ops::testAndSetAcquire(_q_value, expectedValue, newValue, ¤tValue); } + bool testAndSetRelease(Type expectedValue, Type newValue, Type ¤tValue) Q_DECL_NOTHROW + { return Ops::testAndSetRelease(_q_value, expectedValue, newValue, ¤tValue); } + bool testAndSetOrdered(Type expectedValue, Type newValue, Type ¤tValue) Q_DECL_NOTHROW + { return Ops::testAndSetOrdered(_q_value, expectedValue, newValue, ¤tValue); } + static Q_DECL_CONSTEXPR bool isFetchAndStoreNative() Q_DECL_NOTHROW { return Ops::isFetchAndStoreNative(); } static Q_DECL_CONSTEXPR bool isFetchAndStoreWaitFree() Q_DECL_NOTHROW { return Ops::isFetchAndStoreWaitFree(); } diff --git a/src/corelib/thread/qgenericatomic.h b/src/corelib/thread/qgenericatomic.h index eacde411b9..aab0cfbb45 100644 --- a/src/corelib/thread/qgenericatomic.h +++ b/src/corelib/thread/qgenericatomic.h @@ -141,6 +141,8 @@ template <typename BaseClass> struct QGenericAtomicOps static inline Q_DECL_CONSTEXPR bool isTestAndSetWaitFree() Q_DECL_NOTHROW; template <typename T, typename X> static inline bool testAndSetRelaxed(T &_q_value, X expectedValue, X newValue) Q_DECL_NOTHROW; + template <typename T, typename X> static inline + bool testAndSetRelaxed(T &_q_value, X expectedValue, X newValue, X *currentValue) Q_DECL_NOTHROW; #endif template <typename T, typename X> static inline always_inline @@ -165,6 +167,28 @@ template <typename BaseClass> struct QGenericAtomicOps return BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue); } + template <typename T, typename X> static inline always_inline + bool testAndSetAcquire(T &_q_value, X expectedValue, X newValue, X *currentValue) Q_DECL_NOTHROW + { + bool tmp = BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue, currentValue); + BaseClass::acquireMemoryFence(_q_value); + return tmp; + } + + template <typename T, typename X> static inline always_inline + bool testAndSetRelease(T &_q_value, X expectedValue, X newValue, X *currentValue) Q_DECL_NOTHROW + { + BaseClass::releaseMemoryFence(_q_value); + return BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue, currentValue); + } + + template <typename T, typename X> static inline always_inline + bool testAndSetOrdered(T &_q_value, X expectedValue, X newValue, X *currentValue) Q_DECL_NOTHROW + { + BaseClass::orderedMemoryFence(_q_value); + return BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue, currentValue); + } + static inline Q_DECL_CONSTEXPR bool isFetchAndStoreNative() Q_DECL_NOTHROW { return false; } static inline Q_DECL_CONSTEXPR bool isFetchAndStoreWaitFree() Q_DECL_NOTHROW { return false; } diff --git a/tests/auto/corelib/thread/qatomicint/tst_qatomicint.cpp b/tests/auto/corelib/thread/qatomicint/tst_qatomicint.cpp index 42b3a52531..f0d817d37d 100644 --- a/tests/auto/corelib/thread/qatomicint/tst_qatomicint.cpp +++ b/tests/auto/corelib/thread/qatomicint/tst_qatomicint.cpp @@ -84,6 +84,8 @@ private slots: void fetchAndAdd_data(); void fetchAndAdd(); + void operators(); + // stress tests void testAndSet_loop(); void fetchAndAdd_loop(); @@ -540,6 +542,43 @@ void tst_QAtomicInt::testAndSet() QAtomicInt atomic = value; QTEST(atomic.testAndSetOrdered(expected, newval) ? 1 : 0, "result"); } + +#ifdef Q_ATOMIC_INT32_IS_SUPPORTED + QFETCH(int, result); + // the new implementation has the version that loads the current value + + { + QAtomicInt atomic = value; + int currentval = 0xdeadbeef; + QCOMPARE(atomic.testAndSetRelaxed(expected, newval, currentval), result); + if (!result) + QCOMPARE(currentval, value); + } + + { + QAtomicInt atomic = value; + int currentval = 0xdeadbeef; + QCOMPARE(atomic.testAndSetAcquire(expected, newval, currentval), result); + if (!result) + QCOMPARE(currentval, value); + } + + { + QAtomicInt atomic = value; + int currentval = 0xdeadbeef; + QCOMPARE(atomic.testAndSetRelease(expected, newval, currentval), result); + if (!result) + QCOMPARE(currentval, value); + } + + { + QAtomicInt atomic = value; + int currentval = 0xdeadbeef; + QCOMPARE(atomic.testAndSetOrdered(expected, newval, currentval), result); + if (!result) + QCOMPARE(currentval, value); + } +#endif } void tst_QAtomicInt::isFetchAndStoreNative() @@ -770,6 +809,58 @@ void tst_QAtomicInt::fetchAndAdd() } } +void tst_QAtomicInt::operators() +{ + { + // Test that QBasicAtomicInt also has operator= and cast operators + // We've been using them for QAtomicInt elsewhere + QBasicAtomicInt atomic = Q_BASIC_ATOMIC_INITIALIZER(0); + atomic = 1; + QCOMPARE(int(atomic), 1); + } + + QAtomicInt atomic = 0; + int x = ++atomic; + QCOMPARE(int(atomic), x); + QCOMPARE(int(atomic), 1); + + x = atomic++; + QCOMPARE(int(atomic), x + 1); + QCOMPARE(int(atomic), 2); + + x = atomic--; + QCOMPARE(int(atomic), x - 1); + QCOMPARE(int(atomic), 1); + + x = --atomic; + QCOMPARE(int(atomic), x); + QCOMPARE(int(atomic), 0); + + x = (atomic += 1); + QCOMPARE(int(atomic), x); + QCOMPARE(int(atomic), 1); + + x = (atomic -= 1); + QCOMPARE(int(atomic), x); + QCOMPARE(int(atomic), 0); + + x = (atomic |= 0xf); + QCOMPARE(int(atomic), x); + QCOMPARE(int(atomic), 0xf); + + x = (atomic &= 0x17); + QCOMPARE(int(atomic), x); + QCOMPARE(int(atomic), 7); + + x = (atomic ^= 0x14); + QCOMPARE(int(atomic), x); + QCOMPARE(int(atomic), 0x13); + + x = (atomic ^= atomic); + QCOMPARE(int(atomic), x); + QCOMPARE(int(atomic), 0); +} + void tst_QAtomicInt::testAndSet_loop() { QTime stopWatch; diff --git a/tests/auto/corelib/thread/qatomicinteger/tst_qatomicinteger.cpp b/tests/auto/corelib/thread/qatomicinteger/tst_qatomicinteger.cpp index a7139b6a9a..6ddd2ff233 100644 --- a/tests/auto/corelib/thread/qatomicinteger/tst_qatomicinteger.cpp +++ b/tests/auto/corelib/thread/qatomicinteger/tst_qatomicinteger.cpp @@ -143,6 +143,9 @@ private Q_SLOTS: void assign_data() { addData(); } void assign(); + void operatorInteger_data() { addData(); } + void operatorInteger(); + void loadAcquireStoreRelease_data() { addData(); } void loadAcquireStoreRelease(); @@ -152,11 +155,29 @@ private Q_SLOTS: void testAndSet_data() { addData(); } void testAndSet(); + void testAndSet3_data() { addData(); } + void testAndSet3(); + void fetchAndStore_data() { addData(); } void fetchAndStore(); void fetchAndAdd_data() { addData(); } void fetchAndAdd(); + + void fetchAndSub_data() { addData(); } + void fetchAndSub(); + + void addSub_data() { addData(); } + void addSub(); + + void fetchAndOr_data() { addData(); } + void fetchAndOr(); + + void fetchAndAnd_data() { addData(); } + void fetchAndAnd(); + + void fetchAndXor_data() { addData(); } + void fetchAndXor(); }; template <bool> inline void booleanHelper() { } @@ -285,9 +306,13 @@ void tst_QAtomicIntegerXX::assign() QCOMPARE(copy.load(), atomic.load()); QAtomicInteger<T> copy2; - copy2 = atomic; + copy2 = atomic; // operator=(const QAtomicInteger &) QCOMPARE(copy2.load(), atomic.load()); + QAtomicInteger<T> copy2bis; + copy2bis = atomic.load(); // operator=(T) + QCOMPARE(copy2bis.load(), atomic.load()); + // move QAtomicInteger<T> copy3; copy3 = qMove(copy); @@ -298,6 +323,16 @@ void tst_QAtomicIntegerXX::assign() QCOMPARE(copy4.load(), atomic.load()); } +void tst_QAtomicIntegerXX::operatorInteger() +{ + QFETCH(LargeInt, value); + + QAtomicInteger<T> atomic(value); + T val2 = atomic; + QCOMPARE(val2, atomic.load()); + QCOMPARE(val2, T(value)); +} + void tst_QAtomicIntegerXX::loadAcquireStoreRelease() { QFETCH(LargeInt, value); @@ -327,6 +362,17 @@ void tst_QAtomicIntegerXX::refDeref() QCOMPARE(atomic.load(), prevValue); QCOMPARE(atomic.ref(), (value != 0)); QCOMPARE(atomic.load(), T(value)); + + QCOMPARE(++atomic, nextValue); + QCOMPARE(--atomic, T(value)); + QCOMPARE(--atomic, prevValue); + QCOMPARE(++atomic, T(value)); + + QCOMPARE(atomic++, T(value)); + QCOMPARE(atomic--, nextValue); + QCOMPARE(atomic--, T(value)); + QCOMPARE(atomic++, prevValue); + QCOMPARE(atomic.load(), T(value)); } void tst_QAtomicIntegerXX::testAndSet() @@ -360,6 +406,42 @@ void tst_QAtomicIntegerXX::testAndSet() QCOMPARE(atomic.loadAcquire(), T(value)); } +void tst_QAtomicIntegerXX::testAndSet3() +{ + QFETCH(LargeInt, value); + T newValue = ~T(value); + T oldValue; + QAtomicInteger<T> atomic(value); + + QVERIFY(atomic.testAndSetRelaxed(value, newValue, oldValue)); + QCOMPARE(atomic.load(), newValue); + QVERIFY(!atomic.testAndSetRelaxed(value, newValue, oldValue)); + QCOMPARE(oldValue, newValue); + QVERIFY(atomic.testAndSetRelaxed(newValue, value, oldValue)); + QCOMPARE(atomic.load(), T(value)); + + QVERIFY(atomic.testAndSetAcquire(value, newValue, oldValue)); + QCOMPARE(atomic.load(), newValue); + QVERIFY(!atomic.testAndSetAcquire(value, newValue, oldValue)); + QCOMPARE(oldValue, newValue); + QVERIFY(atomic.testAndSetAcquire(newValue, value, oldValue)); + QCOMPARE(atomic.load(), T(value)); + + QVERIFY(atomic.testAndSetRelease(value, newValue, oldValue)); + QCOMPARE(atomic.loadAcquire(), newValue); + QVERIFY(!atomic.testAndSetRelease(value, newValue, oldValue)); + QCOMPARE(oldValue, newValue); + QVERIFY(atomic.testAndSetRelease(newValue, value, oldValue)); + QCOMPARE(atomic.loadAcquire(), T(value)); + + QVERIFY(atomic.testAndSetOrdered(value, newValue, oldValue)); + QCOMPARE(atomic.loadAcquire(), newValue); + QVERIFY(!atomic.testAndSetOrdered(value, newValue, oldValue)); + QCOMPARE(oldValue, newValue); + QVERIFY(atomic.testAndSetOrdered(newValue, value, oldValue)); + QCOMPARE(atomic.loadAcquire(), T(value)); +} + void tst_QAtomicIntegerXX::fetchAndStore() { QFETCH(LargeInt, value); @@ -433,6 +515,304 @@ void tst_QAtomicIntegerXX::fetchAndAdd() QCOMPARE(atomic.loadAcquire(), newValue2); QCOMPARE(atomic.fetchAndAddOrdered(parcel1), newValue2); QCOMPARE(atomic.loadAcquire(), T(value)); + + // operator+= + QCOMPARE(atomic += parcel1, newValue1); + QCOMPARE(atomic += parcel2, T(value)); + QCOMPARE(atomic += parcel2, newValue2); + QCOMPARE(atomic += parcel1, T(value)); +} + +void tst_QAtomicIntegerXX::fetchAndSub() +{ + QFETCH(LargeInt, value); + QAtomicInteger<T> atomic(value); + + // note: this test has undefined behavior for signed max and min + T parcel1 = 42; + T parcel2 = T(0-parcel1); + T newValue1 = T(value) - parcel1; + T newValue2 = T(value) - parcel2; + + QCOMPARE(atomic.fetchAndSubRelaxed(parcel1), T(value)); + QCOMPARE(atomic.load(), newValue1); + QCOMPARE(atomic.fetchAndSubRelaxed(parcel2), newValue1); + QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.fetchAndSubRelaxed(parcel2), T(value)); + QCOMPARE(atomic.load(), newValue2); + QCOMPARE(atomic.fetchAndSubRelaxed(parcel1), newValue2); + QCOMPARE(atomic.load(), T(value)); + + QCOMPARE(atomic.fetchAndSubAcquire(parcel1), T(value)); + QCOMPARE(atomic.load(), newValue1); + QCOMPARE(atomic.fetchAndSubAcquire(parcel2), newValue1); + QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.fetchAndSubAcquire(parcel2), T(value)); + QCOMPARE(atomic.load(), newValue2); + QCOMPARE(atomic.fetchAndSubAcquire(parcel1), newValue2); + QCOMPARE(atomic.load(), T(value)); + + QCOMPARE(atomic.fetchAndSubRelease(parcel1), T(value)); + QCOMPARE(atomic.loadAcquire(), newValue1); + QCOMPARE(atomic.fetchAndSubRelease(parcel2), newValue1); + QCOMPARE(atomic.loadAcquire(), T(value)); + QCOMPARE(atomic.fetchAndSubRelease(parcel2), T(value)); + QCOMPARE(atomic.loadAcquire(), newValue2); + QCOMPARE(atomic.fetchAndSubRelease(parcel1), newValue2); + QCOMPARE(atomic.loadAcquire(), T(value)); + + QCOMPARE(atomic.fetchAndSubOrdered(parcel1), T(value)); + QCOMPARE(atomic.loadAcquire(), newValue1); + QCOMPARE(atomic.fetchAndSubOrdered(parcel2), newValue1); + QCOMPARE(atomic.loadAcquire(), T(value)); + QCOMPARE(atomic.fetchAndSubOrdered(parcel2), T(value)); + QCOMPARE(atomic.loadAcquire(), newValue2); + QCOMPARE(atomic.fetchAndSubOrdered(parcel1), newValue2); + QCOMPARE(atomic.loadAcquire(), T(value)); + + // operator-= + QCOMPARE(atomic -= parcel1, newValue1); + QCOMPARE(atomic -= parcel2, T(value)); + QCOMPARE(atomic -= parcel2, newValue2); + QCOMPARE(atomic -= parcel1, T(value)); +} + +void tst_QAtomicIntegerXX::addSub() +{ + QFETCH(LargeInt, value); + QAtomicInteger<T> atomic(value); + + // note: this test has undefined behavior for signed max and min + T parcel1 = 42; + T parcel2 = T(0-parcel1); + T newValue1 = T(value) + parcel1; + T newValue2 = T(value) - parcel1; + + QCOMPARE(atomic.fetchAndAddRelaxed(parcel1), T(value)); + QCOMPARE(atomic.load(), newValue1); + QCOMPARE(atomic.fetchAndSubRelaxed(parcel1), newValue1); + QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.fetchAndSubRelaxed(parcel1), T(value)); + QCOMPARE(atomic.load(), newValue2); + QCOMPARE(atomic.fetchAndAddRelaxed(parcel1), newValue2); + QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.fetchAndAddRelaxed(parcel2), T(value)); + QCOMPARE(atomic.load(), newValue2); + QCOMPARE(atomic.fetchAndSubRelaxed(parcel2), newValue2); + QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.fetchAndSubRelaxed(parcel2), T(value)); + QCOMPARE(atomic.load(), newValue1); + QCOMPARE(atomic.fetchAndAddRelaxed(parcel2), newValue1); + QCOMPARE(atomic.load(), T(value)); + + QCOMPARE(atomic.fetchAndAddAcquire(parcel1), T(value)); + QCOMPARE(atomic.load(), newValue1); + QCOMPARE(atomic.fetchAndSubAcquire(parcel1), newValue1); + QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.fetchAndSubAcquire(parcel1), T(value)); + QCOMPARE(atomic.load(), newValue2); + QCOMPARE(atomic.fetchAndAddAcquire(parcel1), newValue2); + QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.fetchAndAddAcquire(parcel2), T(value)); + QCOMPARE(atomic.load(), newValue2); + QCOMPARE(atomic.fetchAndSubAcquire(parcel2), newValue2); + QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.fetchAndSubAcquire(parcel2), T(value)); + QCOMPARE(atomic.load(), newValue1); + QCOMPARE(atomic.fetchAndAddAcquire(parcel2), newValue1); + QCOMPARE(atomic.load(), T(value)); + + QCOMPARE(atomic.fetchAndAddRelease(parcel1), T(value)); + QCOMPARE(atomic.load(), newValue1); + QCOMPARE(atomic.fetchAndSubRelease(parcel1), newValue1); + QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.fetchAndSubRelease(parcel1), T(value)); + QCOMPARE(atomic.load(), newValue2); + QCOMPARE(atomic.fetchAndAddRelease(parcel1), newValue2); + QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.fetchAndAddRelease(parcel2), T(value)); + QCOMPARE(atomic.load(), newValue2); + QCOMPARE(atomic.fetchAndSubRelease(parcel2), newValue2); + QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.fetchAndSubRelease(parcel2), T(value)); + QCOMPARE(atomic.load(), newValue1); + QCOMPARE(atomic.fetchAndAddRelease(parcel2), newValue1); + QCOMPARE(atomic.load(), T(value)); + + QCOMPARE(atomic.fetchAndAddOrdered(parcel1), T(value)); + QCOMPARE(atomic.load(), newValue1); + QCOMPARE(atomic.fetchAndSubOrdered(parcel1), newValue1); + QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.fetchAndSubOrdered(parcel1), T(value)); + QCOMPARE(atomic.load(), newValue2); + QCOMPARE(atomic.fetchAndAddOrdered(parcel1), newValue2); + QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.fetchAndAddOrdered(parcel2), T(value)); + QCOMPARE(atomic.load(), newValue2); + QCOMPARE(atomic.fetchAndSubOrdered(parcel2), newValue2); + QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.fetchAndSubOrdered(parcel2), T(value)); + QCOMPARE(atomic.load(), newValue1); + QCOMPARE(atomic.fetchAndAddOrdered(parcel2), newValue1); + QCOMPARE(atomic.load(), T(value)); + + // operator+= and operator-= + QCOMPARE(atomic += parcel1, newValue1); + QCOMPARE(atomic -= parcel1, T(value)); + QCOMPARE(atomic -= parcel1, newValue2); + QCOMPARE(atomic += parcel1, T(value)); + QCOMPARE(atomic += parcel2, newValue2); + QCOMPARE(atomic -= parcel2, T(value)); + QCOMPARE(atomic -= parcel2, newValue1); + QCOMPARE(atomic += parcel2, T(value)); +} + +void tst_QAtomicIntegerXX::fetchAndOr() +{ + QFETCH(LargeInt, value); + QAtomicInteger<T> atomic(value); + + T zero = 0; + T one = 1; + T minusOne = T(~0); + + QCOMPARE(atomic.fetchAndOrRelaxed(zero), T(value)); + QCOMPARE(atomic.fetchAndOrRelaxed(one), T(value)); + QCOMPARE(atomic.load(), T(value | 1)); + QCOMPARE(atomic.fetchAndOrRelaxed(minusOne), T(value | 1)); + QCOMPARE(atomic.load(), minusOne); + + atomic.store(value); + QCOMPARE(atomic.fetchAndOrAcquire(zero), T(value)); + QCOMPARE(atomic.fetchAndOrAcquire(one), T(value)); + QCOMPARE(atomic.load(), T(value | 1)); + QCOMPARE(atomic.fetchAndOrAcquire(minusOne), T(value | 1)); + QCOMPARE(atomic.load(), minusOne); + + atomic.store(value); + QCOMPARE(atomic.fetchAndOrRelease(zero), T(value)); + QCOMPARE(atomic.fetchAndOrRelease(one), T(value)); + QCOMPARE(atomic.load(), T(value | 1)); + QCOMPARE(atomic.fetchAndOrRelease(minusOne), T(value | 1)); + QCOMPARE(atomic.load(), minusOne); + + atomic.store(value); + QCOMPARE(atomic.fetchAndOrOrdered(zero), T(value)); + QCOMPARE(atomic.fetchAndOrOrdered(one), T(value)); + QCOMPARE(atomic.load(), T(value | 1)); + QCOMPARE(atomic.fetchAndOrOrdered(minusOne), T(value | 1)); + QCOMPARE(atomic.load(), minusOne); + + atomic.store(value); + QCOMPARE(atomic |= zero, T(value)); + QCOMPARE(atomic |= one, T(value | 1)); + QCOMPARE(atomic |= minusOne, minusOne); +} + +void tst_QAtomicIntegerXX::fetchAndAnd() +{ + QFETCH(LargeInt, value); + QAtomicInteger<T> atomic(value); + + T zero = 0; + T f = 0xf; + T minusOne = T(~0); + + QCOMPARE(atomic.fetchAndAndRelaxed(minusOne), T(value)); + QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.fetchAndAndRelaxed(f), T(value)); + QCOMPARE(atomic.load(), T(value & 0xf)); + QCOMPARE(atomic.fetchAndAndRelaxed(zero), T(value & 0xf)); + QCOMPARE(atomic.load(), zero); + + atomic.store(value); + QCOMPARE(atomic.fetchAndAndAcquire(minusOne), T(value)); + QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.fetchAndAndAcquire(f), T(value)); + QCOMPARE(atomic.load(), T(value & 0xf)); + QCOMPARE(atomic.fetchAndAndAcquire(zero), T(value & 0xf)); + QCOMPARE(atomic.load(), zero); + + atomic.store(value); + QCOMPARE(atomic.fetchAndAndRelease(minusOne), T(value)); + QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.fetchAndAndRelease(f), T(value)); + QCOMPARE(atomic.load(), T(value & 0xf)); + QCOMPARE(atomic.fetchAndAndRelease(zero), T(value & 0xf)); + QCOMPARE(atomic.load(), zero); + + atomic.store(value); + QCOMPARE(atomic.fetchAndAndOrdered(minusOne), T(value)); + QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.fetchAndAndOrdered(f), T(value)); + QCOMPARE(atomic.load(), T(value & 0xf)); + QCOMPARE(atomic.fetchAndAndOrdered(zero), T(value & 0xf)); + QCOMPARE(atomic.load(), zero); + + atomic.store(value); + QCOMPARE(atomic &= minusOne, T(value)); + QCOMPARE(atomic &= f, T(value & 0xf)); + QCOMPARE(atomic &= zero, zero); +} + +void tst_QAtomicIntegerXX::fetchAndXor() +{ + QFETCH(LargeInt, value); + QAtomicInteger<T> atomic(value); + + T zero = 0; + T pattern = T(Q_UINT64_C(0xcccccccccccccccc)); + T minusOne = T(~0); + + QCOMPARE(atomic.fetchAndXorRelaxed(zero), T(value)); + QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.fetchAndXorRelaxed(pattern), T(value)); + QCOMPARE(atomic.load(), T(value ^ pattern)); + QCOMPARE(atomic.fetchAndXorRelaxed(pattern), T(value ^ pattern)); + QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.fetchAndXorRelaxed(minusOne), T(value)); + QCOMPARE(atomic.load(), T(~value)); + QCOMPARE(atomic.fetchAndXorRelaxed(minusOne), T(~value)); + QCOMPARE(atomic.load(), T(value)); + + QCOMPARE(atomic.fetchAndXorAcquire(zero), T(value)); + QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.fetchAndXorAcquire(pattern), T(value)); + QCOMPARE(atomic.load(), T(value ^ pattern)); + QCOMPARE(atomic.fetchAndXorAcquire(pattern), T(value ^ pattern)); + QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.fetchAndXorAcquire(minusOne), T(value)); + QCOMPARE(atomic.load(), T(~value)); + QCOMPARE(atomic.fetchAndXorAcquire(minusOne), T(~value)); + QCOMPARE(atomic.load(), T(value)); + + QCOMPARE(atomic.fetchAndXorRelease(zero), T(value)); + QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.fetchAndXorRelease(pattern), T(value)); + QCOMPARE(atomic.load(), T(value ^ pattern)); + QCOMPARE(atomic.fetchAndXorRelease(pattern), T(value ^ pattern)); + QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.fetchAndXorRelease(minusOne), T(value)); + QCOMPARE(atomic.load(), T(~value)); + QCOMPARE(atomic.fetchAndXorRelease(minusOne), T(~value)); + QCOMPARE(atomic.load(), T(value)); + + QCOMPARE(atomic.fetchAndXorOrdered(zero), T(value)); + QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.fetchAndXorOrdered(pattern), T(value)); + QCOMPARE(atomic.load(), T(value ^ pattern)); + QCOMPARE(atomic.fetchAndXorOrdered(pattern), T(value ^ pattern)); + QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.fetchAndXorOrdered(minusOne), T(value)); + QCOMPARE(atomic.load(), T(~value)); + QCOMPARE(atomic.fetchAndXorOrdered(minusOne), T(~value)); + QCOMPARE(atomic.load(), T(value)); + + QCOMPARE(atomic ^= zero, T(value)); + QCOMPARE(atomic ^= pattern, T(value ^ pattern)); + QCOMPARE(atomic ^= pattern, T(value)); + QCOMPARE(atomic ^= minusOne, T(~value)); + QCOMPARE(atomic ^= minusOne, T(value)); } #include "tst_qatomicinteger.moc" diff --git a/tests/auto/corelib/thread/qatomicpointer/tst_qatomicpointer.cpp b/tests/auto/corelib/thread/qatomicpointer/tst_qatomicpointer.cpp index d4e777e35b..595808e270 100644 --- a/tests/auto/corelib/thread/qatomicpointer/tst_qatomicpointer.cpp +++ b/tests/auto/corelib/thread/qatomicpointer/tst_qatomicpointer.cpp @@ -70,6 +70,8 @@ private slots: void constAndVolatile(); void forwardDeclared(); + + void operators(); private: static void warningFreeHelper(); }; @@ -664,5 +666,56 @@ void tst_QAtomicPointer::forwardDeclared() QVERIFY(true); } +template <typename T> static void operators_helper() +{ + typedef T *Ptr; + T array[3] = {}; + Ptr zero = array; + Ptr one = array + 1; + Ptr two = array + 2; + + { + // Test that QBasicAtomicPointer also has operator= and cast operators + // We've been using them for QAtomicPointer<T> elsewhere + QBasicAtomicPointer<T> atomic = Q_BASIC_ATOMIC_INITIALIZER(0); + atomic = one; + QCOMPARE(Ptr(atomic), one); + } + + QAtomicPointer<T> atomic = zero; + Ptr x = ++atomic; + QCOMPARE(Ptr(atomic), x); + QCOMPARE(Ptr(atomic), one); + + x = atomic++; + QCOMPARE(Ptr(atomic), x + 1); + QCOMPARE(Ptr(atomic), two); + + x = atomic--; + QCOMPARE(Ptr(atomic), x - 1); + QCOMPARE(Ptr(atomic), one); + + x = --atomic; + QCOMPARE(Ptr(atomic), x); + QCOMPARE(Ptr(atomic), zero); + + x = (atomic += 1); + QCOMPARE(Ptr(atomic), x); + QCOMPARE(Ptr(atomic), one); + + x = (atomic -= 1); + QCOMPARE(Ptr(atomic), x); + QCOMPARE(Ptr(atomic), zero); +} + +struct Big { double d[10]; }; +void tst_QAtomicPointer::operators() +{ + operators_helper<char>(); + operators_helper<int>(); + operators_helper<double>(); + operators_helper<Big>(); +} + QTEST_APPLESS_MAIN(tst_QAtomicPointer) #include "tst_qatomicpointer.moc" |