diff options
Diffstat (limited to 'src/corelib/arch/qatomic_armv5.h')
-rw-r--r-- | src/corelib/arch/qatomic_armv5.h | 378 |
1 files changed, 68 insertions, 310 deletions
diff --git a/src/corelib/arch/qatomic_armv5.h b/src/corelib/arch/qatomic_armv5.h index 2567204452..ce89934eaf 100644 --- a/src/corelib/arch/qatomic_armv5.h +++ b/src/corelib/arch/qatomic_armv5.h @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. +** Copyright (C) 2011 Thiago Macieira <thiago@kde.org> ** Contact: http://www.qt-project.org/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -42,303 +42,112 @@ #ifndef QATOMIC_ARMV5_H #define QATOMIC_ARMV5_H +#include <QtCore/qgenericatomic.h> + QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NOT_NATIVE - -inline bool QBasicAtomicInt::isReferenceCountingNative() -{ return false; } -inline bool QBasicAtomicInt::isReferenceCountingWaitFree() -{ return false; } +#if 0 +#pragma qt_sync_stop_processing +#endif +#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NOT_NATIVE #define Q_ATOMIC_INT_TEST_AND_SET_IS_NOT_NATIVE - -inline bool QBasicAtomicInt::isTestAndSetNative() -{ return false; } -inline bool QBasicAtomicInt::isTestAndSetWaitFree() -{ return false; } - #define Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE #define Q_ATOMIC_INT_FETCH_AND_STORE_IS_WAIT_FREE - -inline bool QBasicAtomicInt::isFetchAndStoreNative() -{ return true; } -inline bool QBasicAtomicInt::isFetchAndStoreWaitFree() -{ return true; } - #define Q_ATOMIC_INT_FETCH_AND_ADD_IS_NOT_NATIVE -inline bool QBasicAtomicInt::isFetchAndAddNative() -{ return false; } -inline bool QBasicAtomicInt::isFetchAndAddWaitFree() -{ return false; } - #define Q_ATOMIC_POINTER_TEST_AND_SET_IS_NOT_NATIVE - -template <typename T> -Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isTestAndSetNative() -{ return false; } -template <typename T> -Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isTestAndSetWaitFree() -{ return false; } - #define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE #define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_WAIT_FREE - -template <typename T> -Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndStoreNative() -{ return true; } -template <typename T> -Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndStoreWaitFree() -{ return true; } - #define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_NOT_NATIVE -template <typename T> -Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndAddNative() -{ return false; } -template <typename T> -Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndAddWaitFree() -{ return false; } - -#ifndef QT_NO_ARM_EABI - -// kernel places a restartable cmpxchg implementation at a fixed address -extern "C" typedef int (qt_atomic_eabi_cmpxchg_int_t)(int oldval, int newval, volatile int *ptr); -extern "C" typedef int (qt_atomic_eabi_cmpxchg_ptr_t)(const void *oldval, const void *newval, volatile void *ptr); -#define qt_atomic_eabi_cmpxchg_int (*reinterpret_cast<qt_atomic_eabi_cmpxchg_int_t *>(0xffff0fc0)) -#define qt_atomic_eabi_cmpxchg_ptr (*reinterpret_cast<qt_atomic_eabi_cmpxchg_ptr_t *>(0xffff0fc0)) +#ifdef QT_NO_ARM_EABI +# error "Sorry, ARM without EABI is no longer supported" +#endif +#ifndef Q_OS_LINUX +# error "Qt is misconfigured: this ARMv5 implementation is only possible on Linux" +#endif -#else +template<> struct QAtomicIntegerTraits<int> { enum { IsInteger = 1 }; }; +template<> struct QAtomicIntegerTraits<unsigned int> { enum { IsInteger = 1 }; }; -extern Q_CORE_EXPORT char q_atomic_lock; -Q_CORE_EXPORT void qt_atomic_yield(int *); +template <int size> struct QBasicAtomicOps: QGenericAtomicOps<QBasicAtomicOps<size> > +{ + // kernel places a restartable cmpxchg implementation at a fixed address + template <typename T> + static int _q_cmpxchg(T oldval, T newval, volatile T *ptr) + { + typedef int (* kernel_cmpxchg_t)(T oldval, T newval, volatile T *ptr); + kernel_cmpxchg_t kernel_cmpxchg = *reinterpret_cast<kernel_cmpxchg_t>(0xffff0fc0); + return kernel_cmpxchg(oldval, newval, ptr); + } + static void _q_dmb() + { + typedef void (* kernel_dmb_t)(); + kernel_dmb_t kernel_dmb = *reinterpret_cast<kernel_dmb_t>(0xffff0fa0); + kernel_dmb(); + } -#ifdef Q_CC_RVCT + static void orderedMemoryFence() { _q_dmb(); } -Q_CORE_EXPORT __asm char q_atomic_swp(volatile char *ptr, char newval); + template <typename T> static bool ref(T &_q_value); + template <typename T> static bool deref(T &_q_value); -#else + static bool isTestAndSetNative() { return false; } + static bool isTestAndSetWaitFree() { return false; } + template <typename T> static bool testAndSetRelaxed(T &_q_value, T expectedValue, T newValue); + template <typename T> static T fetchAndStoreRelaxed(T &_q_value, T newValue); + template <typename T> static + T fetchAndAddRelaxed(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd); +}; -inline char q_atomic_swp(volatile char *ptr, char newval) +template <typename T> struct QAtomicOps : QBasicAtomicOps<sizeof(T)> { - register char ret; - asm volatile("swpb %0,%2,[%3]" - : "=&r"(ret), "=m" (*ptr) - : "r"(newval), "r"(ptr) - : "cc", "memory"); - return ret; -} + typedef T Type; +}; -#endif // Q_CC_RVCT - -#endif // QT_NO_ARM_EABI - -// Reference counting - -inline bool QBasicAtomicInt::ref() +template<> template<typename T> inline +bool QBasicAtomicOps<4>::ref(T &_q_value) { -#ifndef QT_NO_ARM_EABI - register int originalValue; - register int newValue; + register T originalValue; + register T newValue; do { originalValue = _q_value; newValue = originalValue + 1; - } while (qt_atomic_eabi_cmpxchg_int(originalValue, newValue, &_q_value) != 0); + } while (_q_cmpxchg(originalValue, newValue, &_q_value) != 0); return newValue != 0; -#else - int count = 0; - while (q_atomic_swp(&q_atomic_lock, ~0) != 0) - qt_atomic_yield(&count); - int originalValue = _q_value++; - q_atomic_swp(&q_atomic_lock, 0); - return originalValue != -1; -#endif } -inline bool QBasicAtomicInt::deref() +template<> template <typename T> inline +bool QBasicAtomicOps<4>::deref(T &_q_value) { -#ifndef QT_NO_ARM_EABI - register int originalValue; - register int newValue; + register T originalValue; + register T newValue; do { originalValue = _q_value; newValue = originalValue - 1; - } while (qt_atomic_eabi_cmpxchg_int(originalValue, newValue, &_q_value) != 0); + } while (_q_cmpxchg(originalValue, newValue, &_q_value) != 0); return newValue != 0; -#else - int count = 0; - while (q_atomic_swp(&q_atomic_lock, ~0) != 0) - qt_atomic_yield(&count); - int originalValue = _q_value--; - q_atomic_swp(&q_atomic_lock, 0); - return originalValue != 1; -#endif } -// Test and set for integers - -inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) +template<> template <typename T> inline +bool QBasicAtomicOps<4>::testAndSetRelaxed(T &_q_value, T expectedValue, T newValue) { -#ifndef QT_NO_ARM_EABI - register int originalValue; + register T originalValue; do { originalValue = _q_value; if (originalValue != expectedValue) return false; - } while (qt_atomic_eabi_cmpxchg_int(expectedValue, newValue, &_q_value) != 0); + } while (_q_cmpxchg(expectedValue, newValue, &_q_value) != 0); return true; -#else - bool returnValue = false; - int count = 0; - while (q_atomic_swp(&q_atomic_lock, ~0) != 0) - qt_atomic_yield(&count); - if (_q_value == expectedValue) { - _q_value = newValue; - returnValue = true; - } - q_atomic_swp(&q_atomic_lock, 0); - return returnValue; -#endif -} - -inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) -{ - return testAndSetOrdered(expectedValue, newValue); -} - -inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) -{ - return testAndSetOrdered(expectedValue, newValue); -} - -inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) -{ - return testAndSetOrdered(expectedValue, newValue); } // Fetch and store for integers - -#ifndef Q_CC_RVCT - -inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) -{ - int originalValue; - asm volatile("swp %0,%2,[%3]" - : "=&r"(originalValue), "=m" (_q_value) - : "r"(newValue), "r"(&_q_value) - : "cc", "memory"); - return originalValue; -} - -#endif - -inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) -{ - return fetchAndStoreOrdered(newValue); -} - -inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) -{ - return fetchAndStoreOrdered(newValue); -} - -inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) -{ - return fetchAndStoreOrdered(newValue); -} - -// Fetch and add for integers - -inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) -{ -#ifndef QT_NO_ARM_EABI - register int originalValue; - register int newValue; - do { - originalValue = _q_value; - newValue = originalValue + valueToAdd; - } while (qt_atomic_eabi_cmpxchg_int(originalValue, newValue, &_q_value) != 0); - return originalValue; -#else - int count = 0; - while (q_atomic_swp(&q_atomic_lock, ~0) != 0) - qt_atomic_yield(&count); - int originalValue = _q_value; - _q_value += valueToAdd; - q_atomic_swp(&q_atomic_lock, 0); - return originalValue; -#endif -} - -inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) -{ - return fetchAndAddOrdered(valueToAdd); -} - -inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) -{ - return fetchAndAddOrdered(valueToAdd); -} - -inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) -{ - return fetchAndAddOrdered(valueToAdd); -} - -// Test and set for pointers - -template <typename T> -Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetOrdered(T *expectedValue, T *newValue) -{ -#ifndef QT_NO_ARM_EABI - register T *originalValue; - do { - originalValue = _q_value; - if (originalValue != expectedValue) - return false; - } while (qt_atomic_eabi_cmpxchg_ptr(expectedValue, newValue, &_q_value) != 0); - return true; -#else - bool returnValue = false; - int count = 0; - while (q_atomic_swp(&q_atomic_lock, ~0) != 0) - qt_atomic_yield(&count); - if (_q_value == expectedValue) { - _q_value = newValue; - returnValue = true; - } - q_atomic_swp(&q_atomic_lock, 0); - return returnValue; -#endif -} - -template <typename T> -Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetRelaxed(T *expectedValue, T *newValue) -{ - return testAndSetOrdered(expectedValue, newValue); -} - -template <typename T> -Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetAcquire(T *expectedValue, T *newValue) -{ - return testAndSetOrdered(expectedValue, newValue); -} - -template <typename T> -Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetRelease(T *expectedValue, T *newValue) -{ - return testAndSetOrdered(expectedValue, newValue); -} - -// Fetch and store for pointers - #ifdef Q_CC_RVCT - -template <typename T> -__asm T *QBasicAtomicPointer<T>::fetchAndStoreOrdered(T *newValue) +template<> template <typename T> inline +__asm T QBasicAtomicOps<4>::fetchAndStoreRelaxed(T &_q_value, T newValue) { add r2, pc, #0 bx r2 @@ -348,80 +157,29 @@ __asm T *QBasicAtomicPointer<T>::fetchAndStoreOrdered(T *newValue) bx lr thumb } - #else - -template <typename T> -Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreOrdered(T *newValue) +template<> template <typename T> inline +T QBasicAtomicOps<4>::fetchAndStoreRelaxed(T &_q_value, T newValue) { - T *originalValue; + T originalValue; asm volatile("swp %0,%2,[%3]" : "=&r"(originalValue), "=m" (_q_value) : "r"(newValue), "r"(&_q_value) : "cc", "memory"); return originalValue; } - #endif // Q_CC_RVCT -template <typename T> -Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreRelaxed(T *newValue) -{ - return fetchAndStoreOrdered(newValue); -} - -template <typename T> -Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreAcquire(T *newValue) -{ - return fetchAndStoreOrdered(newValue); -} - -template <typename T> -Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreRelease(T *newValue) -{ - return fetchAndStoreOrdered(newValue); -} - -// Fetch and add for pointers - -template <typename T> -Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddOrdered(qptrdiff valueToAdd) +template<> template <typename T> inline +T QBasicAtomicOps<4>::fetchAndAddRelaxed(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd) { -#ifndef QT_NO_ARM_EABI - register T *originalValue; - register T *newValue; + register T originalValue; + register T newValue; do { originalValue = _q_value; newValue = originalValue + valueToAdd; - } while (qt_atomic_eabi_cmpxchg_ptr(originalValue, newValue, &_q_value) != 0); + } while (_q_cmpxchg(originalValue, newValue, &_q_value) != 0); return originalValue; -#else - int count = 0; - while (q_atomic_swp(&q_atomic_lock, ~0) != 0) - qt_atomic_yield(&count); - T *originalValue = (_q_value); - _q_value += valueToAdd; - q_atomic_swp(&q_atomic_lock, 0); - return originalValue; -#endif -} - -template <typename T> -Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddRelaxed(qptrdiff valueToAdd) -{ - return fetchAndAddOrdered(valueToAdd); -} - -template <typename T> -Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddAcquire(qptrdiff valueToAdd) -{ - return fetchAndAddOrdered(valueToAdd); -} - -template <typename T> -Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddRelease(qptrdiff valueToAdd) -{ - return fetchAndAddOrdered(valueToAdd); } QT_END_NAMESPACE |