qatomic_arm.h

Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
00004 ** All rights reserved.
00005 ** Contact: Nokia Corporation (qt-info@nokia.com)
00006 **
00007 ** This file is part of the QtCore module of the Qt Toolkit.
00008 **
00009 ** $QT_BEGIN_LICENSE:LGPL$
00010 ** Commercial Usage
00011 ** Licensees holding valid Qt Commercial licenses may use this file in
00012 ** accordance with the Qt Commercial License Agreement provided with the
00013 ** Software or, alternatively, in accordance with the terms contained in
00014 ** a written agreement between you and Nokia.
00015 **
00016 ** GNU Lesser General Public License Usage
00017 ** Alternatively, this file may be used under the terms of the GNU Lesser
00018 ** General Public License version 2.1 as published by the Free Software
00019 ** Foundation and appearing in the file LICENSE.LGPL included in the
00020 ** packaging of this file.  Please review the following information to
00021 ** ensure the GNU Lesser General Public License version 2.1 requirements
00022 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
00023 **
00024 ** In addition, as a special exception, Nokia gives you certain additional
00025 ** rights.  These rights are described in the Nokia Qt LGPL Exception
00026 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this module.
00027 **
00028 ** GNU General Public License Usage
00029 ** Alternatively, this file may be used under the terms of the GNU
00030 ** General Public License version 3.0 as published by the Free Software
00031 ** Foundation and appearing in the file LICENSE.GPL included in the
00032 ** packaging of this file.  Please review the following information to
00033 ** ensure the GNU General Public License version 3.0 requirements will be
00034 ** met: http://www.gnu.org/copyleft/gpl.html.
00035 **
00036 ** If you have questions regarding the use of this file, please contact
00037 ** Nokia at qt-info@nokia.com.
00038 ** $QT_END_LICENSE$
00039 **
00040 ****************************************************************************/
00041 
00042 #ifndef QATOMIC_ARM_H
00043 #define QATOMIC_ARM_H
00044 
00045 QT_BEGIN_HEADER
00046 
00047 QT_BEGIN_NAMESPACE
00048 
00049 #define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NOT_NATIVE
00050 
00051 inline bool QBasicAtomicInt::isReferenceCountingNative()
00052 { return false; }
00053 inline bool QBasicAtomicInt::isReferenceCountingWaitFree()
00054 { return false; }
00055 
00056 #define Q_ATOMIC_INT_TEST_AND_SET_IS_NOT_NATIVE
00057 
00058 inline bool QBasicAtomicInt::isTestAndSetNative()
00059 { return false; }
00060 inline bool QBasicAtomicInt::isTestAndSetWaitFree()
00061 { return false; }
00062 
00063 #define Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE
00064 #define Q_ATOMIC_INT_FETCH_AND_STORE_IS_WAIT_FREE
00065 
00066 inline bool QBasicAtomicInt::isFetchAndStoreNative()
00067 { return true; }
00068 inline bool QBasicAtomicInt::isFetchAndStoreWaitFree()
00069 { return true; }
00070 
00071 #define Q_ATOMIC_INT_FETCH_AND_ADD_IS_NOT_NATIVE
00072 
00073 inline bool QBasicAtomicInt::isFetchAndAddNative()
00074 { return false; }
00075 inline bool QBasicAtomicInt::isFetchAndAddWaitFree()
00076 { return false; }
00077 
00078 #define Q_ATOMIC_POINTER_TEST_AND_SET_IS_NOT_NATIVE
00079 
00080 template <typename T>
00081 Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isTestAndSetNative()
00082 { return false; }
00083 template <typename T>
00084 Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isTestAndSetWaitFree()
00085 { return false; }
00086 
00087 #define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE
00088 #define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_WAIT_FREE
00089 
00090 template <typename T>
00091 Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndStoreNative()
00092 { return true; }
00093 template <typename T>
00094 Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndStoreWaitFree()
00095 { return true; }
00096 
00097 #define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_NOT_NATIVE
00098 
00099 template <typename T>
00100 Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndAddNative()
00101 { return false; }
00102 template <typename T>
00103 Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndAddWaitFree()
00104 { return false; }
00105 
00106 #ifndef QT_NO_ARM_EABI
00107 
00108 // kernel places a restartable cmpxchg implementation at a fixed address
00109 extern "C" typedef int (qt_atomic_eabi_cmpxchg_int_t)(int oldval, int newval, volatile int *ptr);
00110 extern "C" typedef int (qt_atomic_eabi_cmpxchg_ptr_t)(void *oldval, void *newval, volatile void *ptr);
00111 #define qt_atomic_eabi_cmpxchg_int (*reinterpret_cast<qt_atomic_eabi_cmpxchg_int_t *>(0xffff0fc0))
00112 #define qt_atomic_eabi_cmpxchg_ptr (*reinterpret_cast<qt_atomic_eabi_cmpxchg_ptr_t *>(0xffff0fc0)) 
00113 
00114 #else
00115 
00116 extern Q_CORE_EXPORT char q_atomic_lock;
00117 Q_CORE_EXPORT void qt_atomic_yield(int *);
00118 
00119 #ifdef Q_CC_RVCT
00120 
00121 Q_CORE_EXPORT __asm char q_atomic_swp(volatile char *ptr, char newval);
00122 
00123 #else
00124 
00125 inline char q_atomic_swp(volatile char *ptr, char newval)
00126 {
00127     register char ret;
00128     asm volatile("swpb %0,%2,[%3]"
00129                  : "=&r"(ret), "=m" (*ptr)
00130                  : "r"(newval), "r"(ptr)
00131                  : "cc", "memory");
00132     return ret;
00133 }
00134 
00135 #endif // Q_CC_RVCT
00136 
00137 #endif // QT_NO_ARM_EABI
00138 
00139 // Reference counting
00140 
00141 inline bool QBasicAtomicInt::ref()
00142 {
00143 #ifndef QT_NO_ARM_EABI
00144     register int originalValue;
00145     register int newValue;
00146     do {
00147         originalValue = _q_value;
00148         newValue = originalValue + 1;
00149     } while (qt_atomic_eabi_cmpxchg_int(originalValue, newValue, &_q_value) != 0);
00150     return newValue != 0;
00151 #else
00152     int count = 0;
00153     while (q_atomic_swp(&q_atomic_lock, ~0) != 0)
00154         qt_atomic_yield(&count);
00155     int originalValue = _q_value++;
00156     q_atomic_swp(&q_atomic_lock, 0);
00157     return originalValue != -1;
00158 #endif
00159 }
00160 
00161 inline bool QBasicAtomicInt::deref()
00162 {
00163 #ifndef QT_NO_ARM_EABI
00164     register int originalValue;
00165     register int newValue;
00166     do {
00167         originalValue = _q_value;
00168         newValue = originalValue - 1;
00169     } while (qt_atomic_eabi_cmpxchg_int(originalValue, newValue, &_q_value) != 0);
00170     return newValue != 0;
00171 #else
00172     int count = 0;
00173     while (q_atomic_swp(&q_atomic_lock, ~0) != 0)
00174         qt_atomic_yield(&count);
00175     int originalValue = _q_value--;
00176     q_atomic_swp(&q_atomic_lock, 0);
00177     return originalValue != 1;
00178 #endif
00179 }
00180 
00181 // Test and set for integers
00182 
00183 inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue)
00184 {
00185 #ifndef QT_NO_ARM_EABI
00186     register int originalValue;
00187     do {
00188         originalValue = _q_value;
00189         if (originalValue != expectedValue)
00190             return false;
00191     } while (qt_atomic_eabi_cmpxchg_int(expectedValue, newValue, &_q_value) != 0);
00192     return true;
00193 #else
00194     bool returnValue = false;
00195     int count = 0;
00196     while (q_atomic_swp(&q_atomic_lock, ~0) != 0)
00197         qt_atomic_yield(&count);
00198     if (_q_value == expectedValue) {
00199     _q_value = newValue;
00200     returnValue = true;
00201     }
00202     q_atomic_swp(&q_atomic_lock, 0);
00203     return returnValue;
00204 #endif
00205 }
00206 
00207 inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue)
00208 {
00209     return testAndSetOrdered(expectedValue, newValue);
00210 }
00211 
00212 inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue)
00213 {
00214     return testAndSetOrdered(expectedValue, newValue);
00215 }
00216 
00217 inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue)
00218 {
00219     return testAndSetOrdered(expectedValue, newValue);
00220 }
00221 
00222 // Fetch and store for integers
00223 
00224 #ifndef Q_CC_RVCT
00225 
00226 inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue)
00227 {
00228     int originalValue;
00229     asm volatile("swp %0,%2,[%3]"
00230                  : "=&r"(originalValue), "=m" (_q_value)
00231                  : "r"(newValue), "r"(&_q_value)
00232                  : "cc", "memory");
00233     return originalValue;
00234 }
00235 
00236 #endif
00237 
00238 inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue)
00239 {
00240     return fetchAndStoreOrdered(newValue);
00241 }
00242 
00243 inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue)
00244 {
00245     return fetchAndStoreOrdered(newValue);
00246 }
00247 
00248 inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue)
00249 {
00250     return fetchAndStoreOrdered(newValue);
00251 }
00252 
00253 // Fetch and add for integers
00254 
00255 inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd)
00256 {
00257 #ifndef QT_NO_ARM_EABI
00258     register int originalValue;
00259     register int newValue;
00260     do {
00261         originalValue = _q_value;
00262         newValue = originalValue + valueToAdd;
00263     } while (qt_atomic_eabi_cmpxchg_int(originalValue, newValue, &_q_value) != 0);
00264     return originalValue;
00265 #else
00266     int count = 0;
00267     while (q_atomic_swp(&q_atomic_lock, ~0) != 0)
00268         qt_atomic_yield(&count);
00269     int originalValue = _q_value;
00270     _q_value += valueToAdd;
00271     q_atomic_swp(&q_atomic_lock, 0);
00272     return originalValue;
00273 #endif
00274 }
00275 
00276 inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd)
00277 {
00278     return fetchAndAddOrdered(valueToAdd);
00279 }
00280 
00281 inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd)
00282 {
00283     return fetchAndAddOrdered(valueToAdd);
00284 }
00285 
00286 inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd)
00287 {
00288     return fetchAndAddOrdered(valueToAdd);
00289 }
00290 
00291 // Test and set for pointers
00292 
00293 template <typename T>
00294 Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetOrdered(T *expectedValue, T *newValue)
00295 {
00296 #ifndef QT_NO_ARM_EABI
00297     register T *originalValue;
00298     do {
00299         originalValue = _q_value;
00300         if (originalValue != expectedValue)
00301             return false;
00302     } while (qt_atomic_eabi_cmpxchg_ptr(expectedValue, newValue, &_q_value) != 0);
00303     return true;
00304 #else
00305     bool returnValue = false;
00306     int count = 0;
00307     while (q_atomic_swp(&q_atomic_lock, ~0) != 0)
00308         qt_atomic_yield(&count);
00309     if (_q_value == expectedValue) {
00310     _q_value = newValue;
00311     returnValue = true;
00312     }
00313     q_atomic_swp(&q_atomic_lock, 0);
00314     return returnValue;
00315 #endif
00316 }
00317 
00318 template <typename T>
00319 Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetRelaxed(T *expectedValue, T *newValue)
00320 {
00321     return testAndSetOrdered(expectedValue, newValue);
00322 }
00323 
00324 template <typename T>
00325 Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetAcquire(T *expectedValue, T *newValue)
00326 {
00327     return testAndSetOrdered(expectedValue, newValue);
00328 }
00329 
00330 template <typename T>
00331 Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetRelease(T *expectedValue, T *newValue)
00332 {
00333     return testAndSetOrdered(expectedValue, newValue);
00334 }
00335 
00336 // Fetch and store for pointers
00337 
00338 #ifdef Q_CC_RVCT
00339 
00340 template <typename T>
00341 __asm T *QBasicAtomicPointer<T>::fetchAndStoreOrdered(T *newValue)
00342 {
00343     add r2, pc, #0
00344     bx r2
00345     arm
00346     swp r2,r1,[r0]
00347     mov r0, r2
00348     bx lr
00349     thumb
00350 }
00351 
00352 #else
00353 
00354 template <typename T>
00355 Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreOrdered(T *newValue)
00356 {
00357     T *originalValue;
00358     asm volatile("swp %0,%2,[%3]"
00359                  : "=&r"(originalValue), "=m" (_q_value)
00360                  : "r"(newValue), "r"(&_q_value)
00361                  : "cc", "memory");
00362     return originalValue;
00363 }
00364 
00365 #endif // Q_CC_RVCT
00366 
00367 template <typename T>
00368 Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreRelaxed(T *newValue)
00369 {
00370     return fetchAndStoreOrdered(newValue);
00371 }
00372 
00373 template <typename T>
00374 Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreAcquire(T *newValue)
00375 {
00376     return fetchAndStoreOrdered(newValue);
00377 }
00378 
00379 template <typename T>
00380 Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreRelease(T *newValue)
00381 {
00382     return fetchAndStoreOrdered(newValue);
00383 }
00384 
00385 // Fetch and add for pointers
00386 
00387 template <typename T>
00388 Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddOrdered(qptrdiff valueToAdd)
00389 {
00390 #ifndef QT_NO_ARM_EABI
00391     register T *originalValue;
00392     register T *newValue;
00393     do {
00394         originalValue = _q_value;
00395         newValue = originalValue + valueToAdd;
00396     } while (qt_atomic_eabi_cmpxchg_ptr(originalValue, newValue, &_q_value) != 0);
00397     return originalValue;
00398 #else
00399     int count = 0;
00400     while (q_atomic_swp(&q_atomic_lock, ~0) != 0)
00401         qt_atomic_yield(&count);
00402     T *originalValue = (_q_value);
00403     _q_value += valueToAdd;
00404     q_atomic_swp(&q_atomic_lock, 0);
00405     return originalValue;
00406 #endif
00407 }
00408 
00409 template <typename T>
00410 Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddRelaxed(qptrdiff valueToAdd)
00411 {
00412     return fetchAndAddOrdered(valueToAdd);
00413 }
00414 
00415 template <typename T>
00416 Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddAcquire(qptrdiff valueToAdd)
00417 {
00418     return fetchAndAddOrdered(valueToAdd);
00419 }
00420 
00421 template <typename T>
00422 Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddRelease(qptrdiff valueToAdd)
00423 {
00424     return fetchAndAddOrdered(valueToAdd);
00425 }
00426 
00427 QT_END_NAMESPACE
00428 
00429 QT_END_HEADER
00430 
00431 #endif // QATOMIC_ARM_H