summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomasz Duda <tomaszduda23@gmail.com>2012-11-17 19:45:21 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2012-11-18 13:21:18 +0100
commite7e149df694041562689ec3baa2a05cefa7e5ea4 (patch)
tree7250453fb8dd2547154b5c574578ed72a708cd1e
parentc9424fa6687b5d83227c8c07df1e3806b8f487b5 (diff)
Make the qatomic classes work in ARMv5 OABI.
The function testAndSetOrdered is not atomic. The context of a thread may be interrupted inside testAndSetOrdered and then if another thread calls fetchAndStoreOrdered, _q_value may be overwritten. After that _q_value will contain random value depending on where testAndSetOrdered was interrupted. It should not be possible for the atomic classes. Since the commit 8a7b5aca7b6575013a4e4ee9b99808d25edf6fdf introduced new implementation of QMutex for linux the bug causes deadlock. Change-Id: Ib9ffcf0e26d3be36a0e158fd12a363b97177dcbf Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
-rw-r--r--src/corelib/arch/qatomic_armv5.h16
1 files changed, 16 insertions, 0 deletions
diff --git a/src/corelib/arch/qatomic_armv5.h b/src/corelib/arch/qatomic_armv5.h
index 20d6b1bb06..58af4138ca 100644
--- a/src/corelib/arch/qatomic_armv5.h
+++ b/src/corelib/arch/qatomic_armv5.h
@@ -226,10 +226,18 @@ inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue)
inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue)
{
int originalValue;
+#ifndef QT_NO_ARM_EABI
asm volatile("swp %0,%2,[%3]"
: "=&r"(originalValue), "=m" (_q_value)
: "r"(newValue), "r"(&_q_value)
: "cc", "memory");
+#else
+ while (q_atomic_swp(&q_atomic_lock, ~0) != 0)
+ qt_atomic_yield(&count);
+ originalValue=_q_value;
+ _q_value = newValue;
+ q_atomic_swp(&q_atomic_lock, 0);
+#endif
return originalValue;
}
@@ -355,10 +363,18 @@ template <typename T>
Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreOrdered(T *newValue)
{
T *originalValue;
+#ifndef QT_NO_ARM_EABI
asm volatile("swp %0,%2,[%3]"
: "=&r"(originalValue), "=m" (_q_value)
: "r"(newValue), "r"(&_q_value)
: "cc", "memory");
+#else
+ while (q_atomic_swp(&q_atomic_lock, ~0) != 0)
+ qt_atomic_yield(&count);
+ originalValue=_q_value;
+ _q_value = newValue;
+ q_atomic_swp(&q_atomic_lock, 0);
+#endif
return originalValue;
}