summaryrefslogtreecommitdiffstats
path: root/src/corelib/arch
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2012-08-06 19:57:59 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-02-16 05:12:26 +0100
commit634f82f1f1fda7983abf70b58e43c580b1f01df0 (patch)
tree0d3b67615c35f6c8938b0d40c2ab59097a4001ea /src/corelib/arch
parentfb30a3dd7c2e449235ac5896877bbc0ad41a3835 (diff)
Add a testAndSet overload to the atomics that returns the current value
This is extremely useful, since the most common action after a failed compare-and-swap is to loop around, trying again with the current value as found in memory. Code currently written as: do { Type value = atomic.load(); ... } while (!atomic.testAndSetRelaxed(value, desired)); Becomes: Type value = atomic.load(); do { ... } while (!atomic.testAndSetRelaxed(value, desired, value)); In most CPU architectures, the value that was found in memory is known to the compare-and-swap code, so this is more efficient than the previous code. In architectures where the value is not known, the new code is no worse than before. The implementation sometimes modified an existing function, sometimes it added a new one, depending on whether more registers were needed in the assembly (like ARMv6-7), the code became more complex (ARMv5), the optimizer failed (C++11), or it was just plain equivalent (MIPS). Change-Id: I7d6d200ea9746ec8978a0c1e1969dbc3580b9285 Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@digia.com> Reviewed-by: Lars Knoll <lars.knoll@digia.com> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/arch')
-rw-r--r--src/corelib/arch/qatomic_armv5.h7
-rw-r--r--src/corelib/arch/qatomic_armv6.h96
-rw-r--r--src/corelib/arch/qatomic_cxx11.h30
-rw-r--r--src/corelib/arch/qatomic_gcc.h11
-rw-r--r--src/corelib/arch/qatomic_ia64.h40
-rw-r--r--src/corelib/arch/qatomic_mips.h19
-rw-r--r--src/corelib/arch/qatomic_msvc.h31
-rw-r--r--src/corelib/arch/qatomic_x86.h32
8 files changed, 236 insertions, 30 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"