- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files
- Directories
- Examples

- File List
- File Members

# 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