From 634f82f1f1fda7983abf70b58e43c580b1f01df0 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 6 Aug 2012 19:57:59 +0200 Subject: 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 Reviewed-by: Lars Knoll Reviewed-by: Thiago Macieira --- src/corelib/thread/qbasicatomic.h | 18 ++++++++++++++++++ src/corelib/thread/qgenericatomic.h | 24 ++++++++++++++++++++++++ 2 files changed, 42 insertions(+) (limited to 'src/corelib/thread') 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 struct QGenericAtomicOps static inline Q_DECL_CONSTEXPR bool isTestAndSetWaitFree() Q_DECL_NOTHROW; template static inline bool testAndSetRelaxed(T &_q_value, X expectedValue, X newValue) Q_DECL_NOTHROW; + template static inline + bool testAndSetRelaxed(T &_q_value, X expectedValue, X newValue, X *currentValue) Q_DECL_NOTHROW; #endif template static inline always_inline @@ -165,6 +167,28 @@ template struct QGenericAtomicOps return BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue); } + template 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 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 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; } -- cgit v1.2.3