qatomic_armv6.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_ARMV6_H
00043 #define QATOMIC_ARMV6_H
00044 
00045 QT_BEGIN_HEADER
00046 
00047 QT_BEGIN_NAMESPACE
00048 #define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE
00049 
00050 inline bool QBasicAtomicInt::isReferenceCountingNative()
00051 { return true; }
00052 inline bool QBasicAtomicInt::isReferenceCountingWaitFree()
00053 { return false; }
00054 
00055 #define Q_ATOMIC_INT_TEST_AND_SET_IS_ALWAYS_NATIVE
00056 
00057 inline bool QBasicAtomicInt::isTestAndSetNative()
00058 { return true; }
00059 inline bool QBasicAtomicInt::isTestAndSetWaitFree()
00060 { return false; }
00061 
00062 #define Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE
00063 
00064 inline bool QBasicAtomicInt::isFetchAndStoreNative()
00065 { return true; }
00066 inline bool QBasicAtomicInt::isFetchAndStoreWaitFree()
00067 { return false; }
00068 
00069 #define Q_ATOMIC_INT_FETCH_AND_ADD_IS_ALWAYS_NATIVE
00070 
00071 inline bool QBasicAtomicInt::isFetchAndAddNative()
00072 { return true; }
00073 inline bool QBasicAtomicInt::isFetchAndAddWaitFree()
00074 { return false; }
00075 
00076 #define Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE
00077 
00078 template <typename T>
00079 Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isTestAndSetNative()
00080 { return true; }
00081 template <typename T>
00082 Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isTestAndSetWaitFree()
00083 { return false; }
00084 
00085 #define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE
00086 
00087 template <typename T>
00088 Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndStoreNative()
00089 { return true; }
00090 template <typename T>
00091 Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndStoreWaitFree()
00092 { return false; }
00093 
00094 #define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE
00095 
00096 template <typename T>
00097 Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndAddNative()
00098 { return true; }
00099 template <typename T>
00100 Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndAddWaitFree()
00101 { return false; }
00102 
00103 #ifndef Q_CC_RVCT
00104 
00105 inline bool QBasicAtomicInt::ref()
00106 {
00107     register int newValue;
00108     register int result;
00109     asm volatile("0:\n"
00110                  "ldrex %[newValue], [%[_q_value]]\n"
00111                  "add %[newValue], %[newValue], #1\n"
00112                  "strex %[result], %[newValue], [%[_q_value]]\n"
00113                  "teq %[result], #0\n"
00114                  "bne 0b\n"
00115                  : [newValue] "=&r" (newValue),
00116                    [result] "=&r" (result),
00117                    "+m" (_q_value)
00118                  : [_q_value] "r" (&_q_value)
00119                  : "cc", "memory");
00120     return newValue != 0;
00121 }
00122 
00123 inline bool QBasicAtomicInt::deref()
00124 {
00125     register int newValue;
00126     register int result;
00127     asm volatile("0:\n"
00128                  "ldrex %[newValue], [%[_q_value]]\n"
00129                  "sub %[newValue], %[newValue], #1\n"
00130                  "strex %[result], %[newValue], [%[_q_value]]\n"
00131                  "teq %[result], #0\n"
00132                  "bne 0b\n"
00133                  : [newValue] "=&r" (newValue),
00134                    [result] "=&r" (result),
00135                    "+m" (_q_value)
00136                  : [_q_value] "r" (&_q_value)
00137                  : "cc", "memory");
00138     return newValue != 0;
00139 }
00140 
00141 inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue)
00142 {
00143     register int result;
00144     asm volatile("0:\n"
00145                  "ldrex %[result], [%[_q_value]]\n"
00146                  "eors %[result], %[result], %[expectedValue]\n"
00147                  "strexeq %[result], %[newValue], [%[_q_value]]\n"
00148                  "teqeq %[result], #1\n"
00149                  "beq 0b\n"
00150                  : [result] "=&r" (result),
00151                    "+m" (_q_value)
00152                  : [expectedValue] "r" (expectedValue),
00153                    [newValue] "r" (newValue),
00154                    [_q_value] "r" (&_q_value)
00155                  : "cc", "memory");
00156     return result == 0;
00157 }
00158 
00159 inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue)
00160 {
00161     register int originalValue;
00162     register int result;
00163     asm volatile("0:\n"
00164                  "ldrex %[originalValue], [%[_q_value]]\n"
00165                  "strex %[result], %[newValue], [%[_q_value]]\n"
00166                  "teq %[result], #0\n"
00167                  "bne 0b\n"
00168                  : [originalValue] "=&r" (originalValue),
00169                    [result] "=&r" (result),
00170                    "+m" (_q_value)
00171                  : [newValue] "r" (newValue),
00172                    [_q_value] "r" (&_q_value)
00173                  : "cc", "memory");
00174     return originalValue;
00175 }
00176 
00177 inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd)
00178 {
00179     register int originalValue;
00180     register int newValue;
00181     register int result;
00182     asm volatile("0:\n"
00183                  "ldrex %[originalValue], [%[_q_value]]\n"
00184                  "add %[newValue], %[originalValue], %[valueToAdd]\n"
00185                  "strex %[result], %[newValue], [%[_q_value]]\n"
00186                  "teq %[result], #0\n"
00187                  "bne 0b\n"
00188                  : [originalValue] "=&r" (originalValue),
00189                    [newValue] "=&r" (newValue),
00190                    [result] "=&r" (result),
00191                    "+m" (_q_value)
00192                  : [valueToAdd] "r" (valueToAdd),
00193                    [_q_value] "r" (&_q_value)
00194                  : "cc", "memory");
00195     return originalValue;
00196 }
00197 
00198 template <typename T>
00199 Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetOrdered(T *expectedValue, T *newValue)
00200 {
00201     register T *result;
00202     asm volatile("0:\n"
00203                  "ldrex %[result], [%[_q_value]]\n"
00204                  "eors %[result], %[result], %[expectedValue]\n"
00205                  "strexeq %[result], %[newValue], [%[_q_value]]\n"
00206                  "teqeq %[result], #1\n"
00207                  "beq 0b\n"
00208                  : [result] "=&r" (result),
00209                    "+m" (_q_value)
00210                  : [expectedValue] "r" (expectedValue),
00211                    [newValue] "r" (newValue),
00212                    [_q_value] "r" (&_q_value)
00213                  : "cc", "memory");
00214     return result == 0;
00215 }
00216 
00217 template <typename T>
00218 Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreOrdered(T *newValue)
00219 {
00220     register T *originalValue;
00221     register int result;
00222     asm volatile("0:\n"
00223                  "ldrex %[originalValue], [%[_q_value]]\n"
00224                  "strex %[result], %[newValue], [%[_q_value]]\n"
00225                  "teq %[result], #0\n"
00226                  "bne 0b\n"
00227                  : [originalValue] "=&r" (originalValue),
00228                    [result] "=&r" (result),
00229                    "+m" (_q_value)
00230                  : [newValue] "r" (newValue),
00231                    [_q_value] "r" (&_q_value)
00232                  : "cc", "memory");
00233     return originalValue;
00234 }
00235 
00236 template <typename T>
00237 Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddOrdered(qptrdiff valueToAdd)
00238 {
00239     register T *originalValue;
00240     register T *newValue;
00241     register int result;
00242     asm volatile("0:\n"
00243                  "ldrex %[originalValue], [%[_q_value]]\n"
00244                  "add %[newValue], %[originalValue], %[valueToAdd]\n"
00245                  "strex %[result], %[newValue], [%[_q_value]]\n"
00246                  "teq %[result], #0\n"
00247                  "bne 0b\n"
00248                  : [originalValue] "=&r" (originalValue),
00249                    [newValue] "=&r" (newValue),
00250                    [result] "=&r" (result),
00251                    "+m" (_q_value)
00252                  : [valueToAdd] "r" (valueToAdd * sizeof(T)),
00253                    [_q_value] "r" (&_q_value)
00254                  : "cc", "memory");
00255     return originalValue;
00256 }
00257 
00258 #else
00259 // This is Q_CC_RVCT
00260 
00261 // RVCT inline assembly documentation:
00262 // http://www.keil.com/support/man/docs/armcc/armcc_chdcffdb.htm
00263 // RVCT embedded assembly documentation:
00264 // http://www.keil.com/support/man/docs/armcc/armcc_chddbeib.htm
00265 
00266 // save our pragma state and switch to ARM mode
00267 #pragma push
00268 #pragma arm
00269 
00270 inline bool QBasicAtomicInt::ref()
00271 {
00272     register int newValue;
00273     register int result;
00274     retry:
00275     __asm {
00276         ldrex   newValue, [&_q_value]
00277         add     newValue, newValue, #1
00278         strex   result, newValue, [&_q_value]
00279         teq     result, #0
00280         bne     retry
00281     }
00282     return newValue != 0;
00283 }
00284 
00285 inline bool QBasicAtomicInt::deref()
00286 {
00287     register int newValue;
00288     register int result;
00289     retry:
00290     __asm {
00291         ldrex   newValue, [&_q_value]
00292         sub     newValue, newValue, #1
00293         strex   result, newValue, [&_q_value]
00294         teq     result, #0
00295         bne     retry
00296     }
00297     return newValue != 0;
00298 }
00299 
00300 inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue)
00301 {
00302     register int result;
00303     retry:
00304     __asm {
00305         ldrex   result, [&_q_value]
00306         eors    result, result, expectedValue
00307         strexeq result, newValue, [&_q_value]
00308         teqeq   result, #1
00309         beq     retry
00310     }
00311     return result == 0;
00312 }
00313 
00314 inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue)
00315 {
00316     register int originalValue;
00317     register int result;
00318     retry:
00319     __asm {
00320         ldrex   originalValue, [&_q_value]
00321         strex   result, newValue, [&_q_value]
00322         teq     result, #0
00323         bne     retry
00324     }
00325     return originalValue;
00326 }
00327 
00328 inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd)
00329 {
00330     register int originalValue;
00331     register int newValue;
00332     register int result;
00333     retry:
00334     __asm {
00335         ldrex   originalValue, [&_q_value]
00336         add     newValue, originalValue, valueToAdd
00337         strex   result, newValue, [&_q_value]
00338         teq     result, #0
00339         bne     retry
00340     }
00341     return originalValue;
00342 }
00343 
00344 template <typename T>
00345 Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetOrdered(T *expectedValue, T *newValue)
00346 {
00347     register T *result;
00348     retry:
00349     __asm {
00350         ldrex   result, [&_q_value]
00351         eors    result, result, expectedValue
00352         strexeq result, newValue, [&_q_value]
00353         teqeq   result, #1
00354         beq     retry
00355     }
00356     return result == 0;
00357 }
00358 
00359 template <typename T>
00360 Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreOrdered(T *newValue)
00361 {
00362     register T *originalValue;
00363     register int result;
00364     retry:
00365     __asm {
00366         ldrex   originalValue, [&_q_value]
00367         strex   result, newValue, [&_q_value]
00368         teq     result, #0
00369         bne     retry
00370     }
00371     return originalValue;
00372 }
00373 
00374 template <typename T>
00375 Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddOrdered(qptrdiff valueToAdd)
00376 {
00377     register T *originalValue;
00378     register T *newValue;
00379     register int result;
00380     retry:
00381     __asm {
00382         ldrex   originalValue, [&_q_value]
00383         add     newValue, originalValue, valueToAdd * sizeof(T)
00384         strex   result, newValue, [&_q_value]
00385         teq     result, #0
00386         bne     retry
00387     }
00388     return originalValue;
00389 }
00390 
00391 // go back to the previous pragma state (probably Thumb mode)
00392 #pragma pop
00393 #endif
00394 
00395 // common code
00396 
00397 inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue)
00398 {
00399     return testAndSetOrdered(expectedValue, newValue);
00400 }
00401 
00402 inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue)
00403 {
00404     return testAndSetOrdered(expectedValue, newValue);
00405 }
00406 
00407 inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue)
00408 {
00409     return testAndSetOrdered(expectedValue, newValue);
00410 }
00411 
00412 inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue)
00413 {
00414     return fetchAndStoreOrdered(newValue);
00415 }
00416 
00417 inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue)
00418 {
00419     return fetchAndStoreOrdered(newValue);
00420 }
00421 
00422 inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue)
00423 {
00424     return fetchAndStoreOrdered(newValue);
00425 }
00426 
00427 inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd)
00428 {
00429     return fetchAndAddOrdered(valueToAdd);
00430 }
00431 
00432 inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd)
00433 {
00434     return fetchAndAddOrdered(valueToAdd);
00435 }
00436 
00437 inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd)
00438 {
00439     return fetchAndAddOrdered(valueToAdd);
00440 }
00441 
00442 template <typename T>
00443 Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetRelaxed(T *expectedValue, T *newValue)
00444 {
00445     return testAndSetOrdered(expectedValue, newValue);
00446 }
00447 
00448 template <typename T>
00449 Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetAcquire(T *expectedValue, T *newValue)
00450 {
00451     return testAndSetOrdered(expectedValue, newValue);
00452 }
00453 
00454 template <typename T>
00455 Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetRelease(T *expectedValue, T *newValue)
00456 {
00457     return testAndSetOrdered(expectedValue, newValue);
00458 }
00459 
00460 template <typename T>
00461 Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreRelaxed(T *newValue)
00462 {
00463     return fetchAndStoreOrdered(newValue);
00464 }
00465 
00466 template <typename T>
00467 Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreAcquire(T *newValue)
00468 {
00469     return fetchAndStoreOrdered(newValue);
00470 }
00471 
00472 template <typename T>
00473 Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreRelease(T *newValue)
00474 {
00475     return fetchAndStoreOrdered(newValue);
00476 }
00477 
00478 template <typename T>
00479 Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddRelaxed(qptrdiff valueToAdd)
00480 {
00481     return fetchAndAddOrdered(valueToAdd);
00482 }
00483 
00484 template <typename T>
00485 Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddAcquire(qptrdiff valueToAdd)
00486 {
00487     return fetchAndAddOrdered(valueToAdd);
00488 }
00489 
00490 template <typename T>
00491 Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddRelease(qptrdiff valueToAdd)
00492 {
00493     return fetchAndAddOrdered(valueToAdd);
00494 }
00495 
00496 QT_END_NAMESPACE
00497 
00498 QT_END_HEADER
00499 
00500 #endif // QATOMIC_ARMV6_H