| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2016 The Qt Company Ltd. | 
| 4 | ** Copyright (C) 2016 Intel Corporation. | 
| 5 | ** Contact: https://www.qt.io/licensing/ | 
| 6 | ** | 
| 7 | ** This file is part of the test suite of the Qt Toolkit. | 
| 8 | ** | 
| 9 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ | 
| 10 | ** Commercial License Usage | 
| 11 | ** Licensees holding valid commercial Qt licenses may use this file in | 
| 12 | ** accordance with the commercial license agreement provided with the | 
| 13 | ** Software or, alternatively, in accordance with the terms contained in | 
| 14 | ** a written agreement between you and The Qt Company. For licensing terms | 
| 15 | ** and conditions see https://www.qt.io/terms-conditions. For further | 
| 16 | ** information use the contact form at https://www.qt.io/contact-us. | 
| 17 | ** | 
| 18 | ** GNU General Public License Usage | 
| 19 | ** Alternatively, this file may be used under the terms of the GNU | 
| 20 | ** General Public License version 3 as published by the Free Software | 
| 21 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT | 
| 22 | ** included in the packaging of this file. Please review the following | 
| 23 | ** information to ensure the GNU General Public License requirements will | 
| 24 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. | 
| 25 | ** | 
| 26 | ** $QT_END_LICENSE$ | 
| 27 | ** | 
| 28 | ****************************************************************************/ | 
| 29 |  | 
| 30 | #include <QtTest/QtTest> | 
| 31 |  | 
| 32 | #include <QAtomicInt> | 
| 33 | #include <QCoreApplication> | 
| 34 | #include <QElapsedTimer> | 
| 35 |  | 
| 36 | #include <limits.h> | 
| 37 |  | 
| 38 | class tst_QAtomicInt : public QObject | 
| 39 | { | 
| 40 |     Q_OBJECT | 
| 41 |  | 
| 42 | private slots: | 
| 43 |     void warningFree(); | 
| 44 |     void alignment(); | 
| 45 |  | 
| 46 |     // QAtomicInt members | 
| 47 |     void constructor_data(); | 
| 48 |     void constructor(); | 
| 49 |     void copy_constructor_data(); | 
| 50 |     void copy_constructor(); | 
| 51 |     void assignment_operator_data(); | 
| 52 |     void assignment_operator(); | 
| 53 |  | 
| 54 |     void isReferenceCountingNative(); | 
| 55 |     void isReferenceCountingWaitFree(); | 
| 56 |     void ref_data(); | 
| 57 |     void ref(); | 
| 58 |     void deref_data(); | 
| 59 |     void deref(); | 
| 60 |  | 
| 61 |     void isTestAndSetNative(); | 
| 62 |     void isTestAndSetWaitFree(); | 
| 63 |     void testAndSet_data(); | 
| 64 |     void testAndSet(); | 
| 65 |  | 
| 66 |     void isFetchAndStoreNative(); | 
| 67 |     void isFetchAndStoreWaitFree(); | 
| 68 |     void fetchAndStore_data(); | 
| 69 |     void fetchAndStore(); | 
| 70 |  | 
| 71 |     void isFetchAndAddNative(); | 
| 72 |     void isFetchAndAddWaitFree(); | 
| 73 |     void fetchAndAdd_data(); | 
| 74 |     void fetchAndAdd(); | 
| 75 |  | 
| 76 |     void operators(); | 
| 77 |  | 
| 78 |     // stress tests | 
| 79 |     void testAndSet_loop(); | 
| 80 |     void fetchAndAdd_loop(); | 
| 81 |     void fetchAndAdd_threadedLoop(); | 
| 82 |  | 
| 83 | private: | 
| 84 |     static void warningFreeHelper(); | 
| 85 | }; | 
| 86 |  | 
| 87 | template <int I> | 
| 88 | static inline void assemblyMarker(void *ptr = 0) | 
| 89 | { | 
| 90 |     puts(s: (char *)ptr + I); | 
| 91 | } | 
| 92 |  | 
| 93 | template <typename  T, typename Atomic> | 
| 94 | static void warningFreeHelperTemplate() | 
| 95 | { | 
| 96 |     T expectedValue = 0; | 
| 97 |     T newValue = 0; | 
| 98 |     T valueToAdd = 0; | 
| 99 |  | 
| 100 |     // the marker calls are here only to provide a divider for | 
| 101 |     // those reading the assembly output | 
| 102 |     assemblyMarker<0>(); | 
| 103 |     Atomic i = Q_BASIC_ATOMIC_INITIALIZER(0); | 
| 104 |     printf(format: "%d\n" , int(i.loadAcquire())); | 
| 105 |     assemblyMarker<1>(&i); | 
| 106 |  | 
| 107 |     // the loads sometimes generate no assembly output | 
| 108 |     i.loadRelaxed(); | 
| 109 |     assemblyMarker<11>(&i); | 
| 110 |     i.loadAcquire(); | 
| 111 |     assemblyMarker<12>(&i); | 
| 112 |  | 
| 113 |     i.storeRelaxed(newValue); | 
| 114 |     assemblyMarker<21>(&i); | 
| 115 |     i.storeRelease(newValue); | 
| 116 |     assemblyMarker<22>(&i); | 
| 117 |  | 
| 118 |     i.ref(); | 
| 119 |     assemblyMarker<31>(&i); | 
| 120 |     i.deref(); | 
| 121 |     assemblyMarker<32>(&i); | 
| 122 |  | 
| 123 |     i.testAndSetRelaxed(expectedValue, newValue); | 
| 124 |     assemblyMarker<41>(&i); | 
| 125 |     i.testAndSetAcquire(expectedValue, newValue); | 
| 126 |     assemblyMarker<42>(&i); | 
| 127 |     i.testAndSetRelease(expectedValue, newValue); | 
| 128 |     assemblyMarker<43>(&i); | 
| 129 |     i.testAndSetOrdered(expectedValue, newValue); | 
| 130 |     assemblyMarker<44>(&i); | 
| 131 |  | 
| 132 |     i.fetchAndStoreRelaxed(newValue); | 
| 133 |     assemblyMarker<51>(&i); | 
| 134 |     i.fetchAndStoreAcquire(newValue); | 
| 135 |     assemblyMarker<52>(&i); | 
| 136 |     i.fetchAndStoreRelease(newValue); | 
| 137 |     assemblyMarker<53>(&i); | 
| 138 |     i.fetchAndStoreOrdered(newValue); | 
| 139 |     assemblyMarker<54>(&i); | 
| 140 |  | 
| 141 |     i.fetchAndAddRelaxed(valueToAdd); | 
| 142 |     assemblyMarker<61>(&i); | 
| 143 |     i.fetchAndAddAcquire(valueToAdd); | 
| 144 |     assemblyMarker<62>(&i); | 
| 145 |     i.fetchAndAddRelease(valueToAdd); | 
| 146 |     assemblyMarker<63>(&i); | 
| 147 |     i.fetchAndAddOrdered(valueToAdd); | 
| 148 |     assemblyMarker<64>(&i); | 
| 149 | } | 
| 150 |  | 
| 151 | template <bool> inline void booleanHelper() | 
| 152 | { } | 
| 153 |  | 
| 154 | template <typename Atomic> | 
| 155 | static void constexprFunctionsHelperTemplate() | 
| 156 | { | 
| 157 | #ifdef Q_COMPILER_CONSTEXPR | 
| 158 |     // this is a compile-time test only | 
| 159 |     booleanHelper<Atomic::isReferenceCountingNative()>(); | 
| 160 |     booleanHelper<Atomic::isReferenceCountingWaitFree()>(); | 
| 161 |     booleanHelper<Atomic::isTestAndSetNative()>(); | 
| 162 |     booleanHelper<Atomic::isTestAndSetWaitFree()>(); | 
| 163 |     booleanHelper<Atomic::isFetchAndStoreNative()>(); | 
| 164 |     booleanHelper<Atomic::isFetchAndStoreWaitFree()>(); | 
| 165 |     booleanHelper<Atomic::isFetchAndAddNative()>(); | 
| 166 |     booleanHelper<Atomic::isFetchAndAddWaitFree()>(); | 
| 167 | #endif | 
| 168 | } | 
| 169 |  | 
| 170 | void tst_QAtomicInt::warningFreeHelper() | 
| 171 | { | 
| 172 |     qFatal(msg: "This code is bogus, and shouldn't be run. We're looking for compiler warnings only." ); | 
| 173 |     warningFreeHelperTemplate<int, QBasicAtomicInt>(); | 
| 174 |  | 
| 175 |     // 32-bit are always supported: | 
| 176 |     warningFreeHelperTemplate<int, QBasicAtomicInteger<int> >(); | 
| 177 |     warningFreeHelperTemplate<unsigned int, QBasicAtomicInteger<unsigned int> >(); | 
| 178 |     constexprFunctionsHelperTemplate<QBasicAtomicInteger<int> >(); | 
| 179 |     constexprFunctionsHelperTemplate<QBasicAtomicInteger<unsigned int> >(); | 
| 180 | # ifdef Q_COMPILER_UNICODE_STRINGS | 
| 181 |     warningFreeHelperTemplate<qint16, QBasicAtomicInteger<char32_t> >(); | 
| 182 |     constexprFunctionsHelperTemplate<QBasicAtomicInteger<char32_t> >(); | 
| 183 | # endif | 
| 184 |  | 
| 185 |     // pointer-sized integers are always supported: | 
| 186 |     warningFreeHelperTemplate<int, QBasicAtomicInteger<qptrdiff> >(); | 
| 187 |     warningFreeHelperTemplate<unsigned int, QBasicAtomicInteger<quintptr> >(); | 
| 188 |     constexprFunctionsHelperTemplate<QBasicAtomicInteger<qptrdiff> >(); | 
| 189 |     constexprFunctionsHelperTemplate<QBasicAtomicInteger<quintptr> >(); | 
| 190 |  | 
| 191 |     // long is always supported because it's either 32-bit or pointer-sized: | 
| 192 |     warningFreeHelperTemplate<int, QBasicAtomicInteger<long int> >(); | 
| 193 |     warningFreeHelperTemplate<unsigned int, QBasicAtomicInteger<unsigned long int> >(); | 
| 194 |     constexprFunctionsHelperTemplate<QBasicAtomicInteger<long int> >(); | 
| 195 |     constexprFunctionsHelperTemplate<QBasicAtomicInteger<unsigned long int> >(); | 
| 196 |  | 
| 197 | #ifdef Q_ATOMIC_INT16_IS_SUPPORTED | 
| 198 |     warningFreeHelperTemplate<qint16, QBasicAtomicInteger<qint16> >(); | 
| 199 |     warningFreeHelperTemplate<quint16, QBasicAtomicInteger<quint16> >(); | 
| 200 |     constexprFunctionsHelperTemplate<QBasicAtomicInteger<qint16> >(); | 
| 201 |     constexprFunctionsHelperTemplate<QBasicAtomicInteger<quint16> >(); | 
| 202 | # ifdef Q_COMPILER_UNICODE_STRINGS | 
| 203 |     warningFreeHelperTemplate<qint16, QBasicAtomicInteger<char16_t> >(); | 
| 204 |     constexprFunctionsHelperTemplate<QBasicAtomicInteger<char16_t> >(); | 
| 205 | # endif | 
| 206 | #endif | 
| 207 |  | 
| 208 | #ifdef Q_ATOMIC_INT8_IS_SUPPORTED | 
| 209 |     warningFreeHelperTemplate<char, QBasicAtomicInteger<char> >(); | 
| 210 |     warningFreeHelperTemplate<signed char, QBasicAtomicInteger<signed char> >(); | 
| 211 |     warningFreeHelperTemplate<unsigned char, QBasicAtomicInteger<unsigned char> >(); | 
| 212 |     constexprFunctionsHelperTemplate<QBasicAtomicInteger<char> >(); | 
| 213 |     constexprFunctionsHelperTemplate<QBasicAtomicInteger<signed char> >(); | 
| 214 |     constexprFunctionsHelperTemplate<QBasicAtomicInteger<unsigned char> >(); | 
| 215 | #endif | 
| 216 |  | 
| 217 | #ifdef Q_ATOMIC_INT64_IS_SUPPORTED | 
| 218 | #if !defined(__i386__) || (defined(Q_CC_GNU) && defined(__OPTIMIZE__)) | 
| 219 |     warningFreeHelperTemplate<qlonglong, QBasicAtomicInteger<qlonglong> >(); | 
| 220 |     warningFreeHelperTemplate<qulonglong, QBasicAtomicInteger<qulonglong> >(); | 
| 221 |     constexprFunctionsHelperTemplate<QBasicAtomicInteger<qlonglong> >(); | 
| 222 |     constexprFunctionsHelperTemplate<QBasicAtomicInteger<qulonglong> >(); | 
| 223 | #endif | 
| 224 | #endif | 
| 225 | } | 
| 226 |  | 
| 227 | void tst_QAtomicInt::warningFree() | 
| 228 | { | 
| 229 |     // This is a compile time check for warnings. | 
| 230 |     // No need for actual work here. | 
| 231 |  | 
| 232 |     void (*foo)() = &warningFreeHelper; | 
| 233 |     (void)foo; | 
| 234 | } | 
| 235 |  | 
| 236 | template <typename T> struct TypeInStruct { T type; }; | 
| 237 |  | 
| 238 | void tst_QAtomicInt::alignment() | 
| 239 | { | 
| 240 | #ifdef Q_ALIGNOF | 
| 241 |     // this will cause a build error if the alignment isn't the same | 
| 242 |     char dummy1[Q_ALIGNOF(QBasicAtomicInt) == Q_ALIGNOF(TypeInStruct<int>) ? 1 : -1]; | 
| 243 |     char dummy2[Q_ALIGNOF(QAtomicInt) == Q_ALIGNOF(TypeInStruct<int>) ? 1 : -1]; | 
| 244 |     (void)dummy1; (void)dummy2; | 
| 245 |  | 
| 246 | #ifdef Q_ATOMIC_INT32_IS_SUPPORTED | 
| 247 |     QCOMPARE(Q_ALIGNOF(QBasicAtomicInteger<int>), Q_ALIGNOF(TypeInStruct<int>)); | 
| 248 | #endif | 
| 249 |  | 
| 250 | #ifdef Q_ATOMIC_INT16_IS_SUPPORTED | 
| 251 |     QCOMPARE(Q_ALIGNOF(QBasicAtomicInteger<short>), Q_ALIGNOF(TypeInStruct<short>)); | 
| 252 | #endif | 
| 253 |  | 
| 254 | #ifdef Q_ATOMIC_INT8_IS_SUPPORTED | 
| 255 |     QCOMPARE(Q_ALIGNOF(QBasicAtomicInteger<char>), Q_ALIGNOF(TypeInStruct<char>)); | 
| 256 | #endif | 
| 257 |  | 
| 258 | #ifdef Q_ATOMIC_INT64_IS_SUPPORTED | 
| 259 |     QCOMPARE(Q_ALIGNOF(QBasicAtomicInteger<qlonglong>), Q_ALIGNOF(TypeInStruct<qlonglong>)); | 
| 260 | #endif | 
| 261 |  | 
| 262 | #endif | 
| 263 | } | 
| 264 |  | 
| 265 | void tst_QAtomicInt::constructor_data() | 
| 266 | { | 
| 267 |     QTest::addColumn<int>(name: "value" ); | 
| 268 |  | 
| 269 |     QTest::newRow(dataTag: "0" ) << 31337; | 
| 270 |     QTest::newRow(dataTag: "1" ) << 0; | 
| 271 |     QTest::newRow(dataTag: "2" ) << 1; | 
| 272 |     QTest::newRow(dataTag: "3" ) << -1; | 
| 273 |     QTest::newRow(dataTag: "4" ) << 2; | 
| 274 |     QTest::newRow(dataTag: "5" ) << -2; | 
| 275 |     QTest::newRow(dataTag: "6" ) << 3; | 
| 276 |     QTest::newRow(dataTag: "7" ) << -3; | 
| 277 |     QTest::newRow(dataTag: "8" ) << INT_MAX; | 
| 278 |     QTest::newRow(dataTag: "9" ) << INT_MIN+1; | 
| 279 | } | 
| 280 |  | 
| 281 | void tst_QAtomicInt::constructor() | 
| 282 | { | 
| 283 |     QFETCH(int, value); | 
| 284 |     QAtomicInt atomic1(value); | 
| 285 |     QCOMPARE(atomic1.loadRelaxed(), value); | 
| 286 |     QAtomicInt atomic2 = value; | 
| 287 |     QCOMPARE(atomic2.loadRelaxed(), value); | 
| 288 | } | 
| 289 |  | 
| 290 | void tst_QAtomicInt::copy_constructor_data() | 
| 291 | { constructor_data(); } | 
| 292 |  | 
| 293 | void tst_QAtomicInt::copy_constructor() | 
| 294 | { | 
| 295 |     QFETCH(int, value); | 
| 296 |     QAtomicInt atomic1(value); | 
| 297 |     QCOMPARE(atomic1.loadRelaxed(), value); | 
| 298 |  | 
| 299 |     QAtomicInt atomic2(atomic1); | 
| 300 |     QCOMPARE(atomic2.loadRelaxed(), value); | 
| 301 |     QAtomicInt atomic3 = atomic1; | 
| 302 |     QCOMPARE(atomic3.loadRelaxed(), value); | 
| 303 |     QAtomicInt atomic4(atomic2); | 
| 304 |     QCOMPARE(atomic4.loadRelaxed(), value); | 
| 305 |     QAtomicInt atomic5 = atomic2; | 
| 306 |     QCOMPARE(atomic5.loadRelaxed(), value); | 
| 307 | } | 
| 308 |  | 
| 309 | void tst_QAtomicInt::assignment_operator_data() | 
| 310 | { | 
| 311 |     QTest::addColumn<int>(name: "value" ); | 
| 312 |     QTest::addColumn<int>(name: "newval" ); | 
| 313 |  | 
| 314 |     QTest::newRow(dataTag: "value0" ) <<  0 <<  1; | 
| 315 |     QTest::newRow(dataTag: "value1" ) <<  1 <<  0; | 
| 316 |     QTest::newRow(dataTag: "value2" ) <<  0 << -1; | 
| 317 |     QTest::newRow(dataTag: "value3" ) << -1 <<  0; | 
| 318 |     QTest::newRow(dataTag: "value4" ) << -1 <<  1; | 
| 319 |     QTest::newRow(dataTag: "value5" ) <<  1 << -1; | 
| 320 | } | 
| 321 |  | 
| 322 | void tst_QAtomicInt::assignment_operator() | 
| 323 | { | 
| 324 |     QFETCH(int, value); | 
| 325 |     QFETCH(int, newval); | 
| 326 |  | 
| 327 |     { | 
| 328 |         QAtomicInt atomic1 = value; | 
| 329 |         atomic1 = newval; | 
| 330 |         QCOMPARE(atomic1.loadRelaxed(), newval); | 
| 331 |         atomic1 = value; | 
| 332 |         QCOMPARE(atomic1.loadRelaxed(), value); | 
| 333 |  | 
| 334 |         QAtomicInt atomic2 = newval; | 
| 335 |         atomic1 = atomic2; | 
| 336 |         QCOMPARE(atomic1.loadRelaxed(), atomic2.loadRelaxed()); | 
| 337 |     } | 
| 338 | } | 
| 339 |  | 
| 340 | void tst_QAtomicInt::isReferenceCountingNative() | 
| 341 | { | 
| 342 | #if defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE) | 
| 343 |     // the runtime test should say the same thing | 
| 344 |     QVERIFY(QAtomicInt::isReferenceCountingNative()); | 
| 345 |  | 
| 346 | #  if (defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_SOMETIMES_NATIVE)     \ | 
| 347 |        || defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NOT_NATIVE)) | 
| 348 | #    error "Define only one of Q_ATOMIC_INT_REFERENCE_COUNTING_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" | 
| 349 | #  endif | 
| 350 | #elif defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_SOMETIMES_NATIVE) | 
| 351 |     // could be either, just want to make sure the function is implemented | 
| 352 |     QVERIFY(QAtomicInt::isReferenceCountingNative() || !QAtomicInt::isReferenceCountingNative()); | 
| 353 |  | 
| 354 | #  if (defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE) \ | 
| 355 |        || defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NOT_NATIVE)) | 
| 356 | #    error "Define only one of Q_ATOMIC_INT_REFERENCE_COUNTING_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" | 
| 357 | #  endif | 
| 358 | #elif defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NOT_NATIVE) | 
| 359 |     // the runtime test should say the same thing | 
| 360 |     QVERIFY(!QAtomicInt::isReferenceCountingNative()); | 
| 361 |  | 
| 362 | #  if (defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE) \ | 
| 363 |        || defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_SOMETIMES_NATIVE)) | 
| 364 | #    error "Define only one of Q_ATOMIC_INT_REFERENCE_COUNTING_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" | 
| 365 | #  endif | 
| 366 | #else | 
| 367 | #  error "Q_ATOMIC_INT_REFERENCE_COUNTING_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE is not defined" | 
| 368 | #endif | 
| 369 | } | 
| 370 |  | 
| 371 | void tst_QAtomicInt::isReferenceCountingWaitFree() | 
| 372 | { | 
| 373 | #if defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_WAIT_FREE) | 
| 374 |     // the runtime test should say the same thing | 
| 375 |     QVERIFY(QAtomicInt::isReferenceCountingWaitFree()); | 
| 376 |  | 
| 377 |     // enforce some invariants | 
| 378 |     QVERIFY(QAtomicInt::isReferenceCountingNative()); | 
| 379 | #  if defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NOT_NATIVE) | 
| 380 | #    error "Reference counting cannot be wait-free and unsupported at the same time!" | 
| 381 | #  endif | 
| 382 | #else | 
| 383 |     // the runtime test should say the same thing | 
| 384 |     QVERIFY(!QAtomicInt::isReferenceCountingWaitFree()); | 
| 385 | #endif | 
| 386 | } | 
| 387 |  | 
| 388 | void tst_QAtomicInt::ref_data() | 
| 389 | { | 
| 390 |     QTest::addColumn<int>(name: "value" ); | 
| 391 |     QTest::addColumn<int>(name: "result" ); | 
| 392 |     QTest::addColumn<int>(name: "expected" ); | 
| 393 |  | 
| 394 |     QTest::newRow(dataTag: "data0" ) <<  0 << 1 << 1; | 
| 395 |     QTest::newRow(dataTag: "data1" ) << -1 << 0 << 0; | 
| 396 |     QTest::newRow(dataTag: "data2" ) <<  1 << 1 << 2; | 
| 397 | } | 
| 398 |  | 
| 399 | void tst_QAtomicInt::ref() | 
| 400 | { | 
| 401 |     QFETCH(int, value); | 
| 402 |     QAtomicInt x = value; | 
| 403 |     QTEST(x.ref() ? 1 : 0, "result" ); | 
| 404 |     QTEST(x.loadRelaxed(), "expected" ); | 
| 405 | } | 
| 406 |  | 
| 407 | void tst_QAtomicInt::deref_data() | 
| 408 | { | 
| 409 |     QTest::addColumn<int>(name: "value" ); | 
| 410 |     QTest::addColumn<int>(name: "result" ); | 
| 411 |     QTest::addColumn<int>(name: "expected" ); | 
| 412 |  | 
| 413 |     QTest::newRow(dataTag: "data0" ) <<  0 << 1 << -1; | 
| 414 |     QTest::newRow(dataTag: "data1" ) <<  1 << 0 <<  0; | 
| 415 |     QTest::newRow(dataTag: "data2" ) <<  2 << 1 <<  1; | 
| 416 | } | 
| 417 |  | 
| 418 | void tst_QAtomicInt::deref() | 
| 419 | { | 
| 420 |     QFETCH(int, value); | 
| 421 |     QAtomicInt x = value; | 
| 422 |     QTEST(x.deref() ? 1 : 0, "result" ); | 
| 423 |     QTEST(x.loadRelaxed(), "expected" ); | 
| 424 | } | 
| 425 |  | 
| 426 | void tst_QAtomicInt::isTestAndSetNative() | 
| 427 | { | 
| 428 | #if defined(Q_ATOMIC_INT_TEST_AND_SET_IS_ALWAYS_NATIVE) | 
| 429 |     // the runtime test should say the same thing | 
| 430 |     QVERIFY(QAtomicInt::isTestAndSetNative()); | 
| 431 |  | 
| 432 | #  if (defined(Q_ATOMIC_INT_TEST_AND_SET_IS_SOMETIMES_NATIVE)     \ | 
| 433 |        || defined(Q_ATOMIC_INT_TEST_AND_SET_IS_NOT_NATIVE)) | 
| 434 | #    error "Define only one of Q_ATOMIC_INT_TEST_AND_SET_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" | 
| 435 | #  endif | 
| 436 | #elif defined(Q_ATOMIC_INT_TEST_AND_SET_IS_SOMETIMES_NATIVE) | 
| 437 |     // could be either, just want to make sure the function is implemented | 
| 438 |     QVERIFY(QAtomicInt::isTestAndSetNative() || !QAtomicInt::isTestAndSetNative()); | 
| 439 |  | 
| 440 | #  if (defined(Q_ATOMIC_INT_TEST_AND_SET_IS_ALWAYS_NATIVE) \ | 
| 441 |        || defined(Q_ATOMIC_INT_TEST_AND_SET_IS_NOT_NATIVE)) | 
| 442 | #    error "Define only one of Q_ATOMIC_INT_TEST_AND_SET_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" | 
| 443 | #  endif | 
| 444 | #elif defined(Q_ATOMIC_INT_TEST_AND_SET_IS_NOT_NATIVE) | 
| 445 |     // the runtime test should say the same thing | 
| 446 |     QVERIFY(!QAtomicInt::isTestAndSetNative()); | 
| 447 |  | 
| 448 | #  if (defined(Q_ATOMIC_INT_TEST_AND_SET_IS_ALWAYS_NATIVE) \ | 
| 449 |        || defined(Q_ATOMIC_INT_TEST_AND_SET_IS_SOMETIMES_NATIVE)) | 
| 450 | #    error "Define only one of Q_ATOMIC_INT_TEST_AND_SET_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" | 
| 451 | #  endif | 
| 452 | #else | 
| 453 | #  error "Q_ATOMIC_INT_TEST_AND_SET_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE is not defined" | 
| 454 | #endif | 
| 455 | } | 
| 456 |  | 
| 457 | void tst_QAtomicInt::isTestAndSetWaitFree() | 
| 458 | { | 
| 459 | #if defined(Q_ATOMIC_INT_TEST_AND_SET_IS_WAIT_FREE) | 
| 460 |     // the runtime test should say the same thing | 
| 461 |     QVERIFY(QAtomicInt::isTestAndSetWaitFree()); | 
| 462 |  | 
| 463 |     // enforce some invariants | 
| 464 |     QVERIFY(QAtomicInt::isTestAndSetNative()); | 
| 465 | #  if defined(Q_ATOMIC_INT_TEST_AND_SET_IS_NOT_NATIVE) | 
| 466 | #    error "Reference counting cannot be wait-free and unsupported at the same time!" | 
| 467 | #  endif | 
| 468 | #else | 
| 469 |     // the runtime test should say the same thing | 
| 470 |     QVERIFY(!QAtomicInt::isTestAndSetWaitFree()); | 
| 471 | #endif | 
| 472 | } | 
| 473 |  | 
| 474 | void tst_QAtomicInt::testAndSet_data() | 
| 475 | { | 
| 476 |     QTest::addColumn<int>(name: "value" ); | 
| 477 |     QTest::addColumn<int>(name: "expected" ); | 
| 478 |     QTest::addColumn<int>(name: "newval" ); | 
| 479 |     QTest::addColumn<bool>(name: "result" ); | 
| 480 |  | 
| 481 |     // these should succeed | 
| 482 |     QTest::newRow(dataTag: "success0" ) <<         0 <<         0 <<         0 << true; | 
| 483 |     QTest::newRow(dataTag: "success1" ) <<         0 <<         0 <<         1 << true; | 
| 484 |     QTest::newRow(dataTag: "success2" ) <<         0 <<         0 <<        -1 << true; | 
| 485 |     QTest::newRow(dataTag: "success3" ) <<         1 <<         1 <<         0 << true; | 
| 486 |     QTest::newRow(dataTag: "success4" ) <<         1 <<         1 <<         1 << true; | 
| 487 |     QTest::newRow(dataTag: "success5" ) <<         1 <<         1 <<        -1 << true; | 
| 488 |     QTest::newRow(dataTag: "success6" ) <<        -1 <<        -1 <<         0 << true; | 
| 489 |     QTest::newRow(dataTag: "success7" ) <<        -1 <<        -1 <<         1 << true; | 
| 490 |     QTest::newRow(dataTag: "success8" ) <<        -1 <<        -1 <<        -1 << true; | 
| 491 |     QTest::newRow(dataTag: "success9" ) << INT_MIN+1 << INT_MIN+1 << INT_MIN+1 << true; | 
| 492 |     QTest::newRow(dataTag: "successA" ) << INT_MIN+1 << INT_MIN+1 <<         1 << true; | 
| 493 |     QTest::newRow(dataTag: "successB" ) << INT_MIN+1 << INT_MIN+1 <<        -1 << true; | 
| 494 |     QTest::newRow(dataTag: "successC" ) << INT_MAX   << INT_MAX   << INT_MAX   << true; | 
| 495 |     QTest::newRow(dataTag: "successD" ) << INT_MAX   << INT_MAX   <<         1 << true; | 
| 496 |     QTest::newRow(dataTag: "successE" ) << INT_MAX   << INT_MAX   <<        -1 << true; | 
| 497 |  | 
| 498 |     // these should fail | 
| 499 |     QTest::newRow(dataTag: "failure0" ) <<       0   <<       1   <<        ~0 << false; | 
| 500 |     QTest::newRow(dataTag: "failure1" ) <<       0   <<      -1   <<        ~0 << false; | 
| 501 |     QTest::newRow(dataTag: "failure2" ) <<       1   <<       0   <<        ~0 << false; | 
| 502 |     QTest::newRow(dataTag: "failure3" ) <<      -1   <<       0   <<        ~0 << false; | 
| 503 |     QTest::newRow(dataTag: "failure4" ) <<       1   <<      -1   <<        ~0 << false; | 
| 504 |     QTest::newRow(dataTag: "failure5" ) <<      -1   <<       1   <<        ~0 << false; | 
| 505 |     QTest::newRow(dataTag: "failure6" ) << INT_MIN+1 << INT_MAX   <<        ~0 << false; | 
| 506 |     QTest::newRow(dataTag: "failure7" ) << INT_MAX   << INT_MIN+1 <<        ~0 << false; | 
| 507 | } | 
| 508 |  | 
| 509 | void tst_QAtomicInt::testAndSet() | 
| 510 | { | 
| 511 |     QFETCH(int, value); | 
| 512 |     QFETCH(int, expected); | 
| 513 |     QFETCH(int, newval); | 
| 514 |  | 
| 515 |     { | 
| 516 |         QAtomicInt atomic = value; | 
| 517 |         QTEST(atomic.testAndSetRelaxed(expected, newval), "result" ); | 
| 518 |     } | 
| 519 |  | 
| 520 |     { | 
| 521 |         QAtomicInt atomic = value; | 
| 522 |         QTEST(atomic.testAndSetAcquire(expected, newval), "result" ); | 
| 523 |     } | 
| 524 |  | 
| 525 |     { | 
| 526 |         QAtomicInt atomic = value; | 
| 527 |         QTEST(atomic.testAndSetRelease(expected, newval), "result" ); | 
| 528 |     } | 
| 529 |  | 
| 530 |     { | 
| 531 |         QAtomicInt atomic = value; | 
| 532 |         QTEST(atomic.testAndSetOrdered(expected, newval), "result" ); | 
| 533 |     } | 
| 534 |  | 
| 535 | #ifdef Q_ATOMIC_INT32_IS_SUPPORTED | 
| 536 |     QFETCH(bool, result); | 
| 537 |     // the new implementation has the version that loads the current value | 
| 538 |  | 
| 539 |     { | 
| 540 |         QAtomicInt atomic = value; | 
| 541 |         int currentval = 0xdeadbeef; | 
| 542 |         QCOMPARE(atomic.testAndSetRelaxed(expected, newval, currentval), result); | 
| 543 |         if (!result) | 
| 544 |             QCOMPARE(currentval, value); | 
| 545 |     } | 
| 546 |  | 
| 547 |     { | 
| 548 |         QAtomicInt atomic = value; | 
| 549 |         int currentval = 0xdeadbeef; | 
| 550 |         QCOMPARE(atomic.testAndSetAcquire(expected, newval, currentval), result); | 
| 551 |         if (!result) | 
| 552 |             QCOMPARE(currentval, value); | 
| 553 |     } | 
| 554 |  | 
| 555 |     { | 
| 556 |         QAtomicInt atomic = value; | 
| 557 |         int currentval = 0xdeadbeef; | 
| 558 |         QCOMPARE(atomic.testAndSetRelease(expected, newval, currentval), result); | 
| 559 |         if (!result) | 
| 560 |             QCOMPARE(currentval, value); | 
| 561 |     } | 
| 562 |  | 
| 563 |     { | 
| 564 |         QAtomicInt atomic = value; | 
| 565 |         int currentval = 0xdeadbeef; | 
| 566 |         QCOMPARE(atomic.testAndSetOrdered(expected, newval, currentval), result); | 
| 567 |         if (!result) | 
| 568 |             QCOMPARE(currentval, value); | 
| 569 |     } | 
| 570 | #endif | 
| 571 | } | 
| 572 |  | 
| 573 | void tst_QAtomicInt::isFetchAndStoreNative() | 
| 574 | { | 
| 575 | #if defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE) | 
| 576 |     // the runtime test should say the same thing | 
| 577 |     QVERIFY(QAtomicInt::isFetchAndStoreNative()); | 
| 578 |  | 
| 579 | #  if (defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_SOMETIMES_NATIVE)     \ | 
| 580 |        || defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_NOT_NATIVE)) | 
| 581 | #    error "Define only one of Q_ATOMIC_INT_FETCH_AND_STORE_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" | 
| 582 | #  endif | 
| 583 | #elif defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_SOMETIMES_NATIVE) | 
| 584 |     // could be either, just want to make sure the function is implemented | 
| 585 |     QVERIFY(QAtomicInt::isFetchAndStoreNative() || !QAtomicInt::isFetchAndStoreNative()); | 
| 586 |  | 
| 587 | #  if (defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE) \ | 
| 588 |        || defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_NOT_NATIVE)) | 
| 589 | #    error "Define only one of Q_ATOMIC_INT_FETCH_AND_STORE_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" | 
| 590 | #  endif | 
| 591 | #elif defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_NOT_NATIVE) | 
| 592 |     // the runtime test should say the same thing | 
| 593 |     QVERIFY(!QAtomicInt::isFetchAndStoreNative()); | 
| 594 |  | 
| 595 | #  if (defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE) \ | 
| 596 |        || defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_SOMETIMES_NATIVE)) | 
| 597 | #    error "Define only one of Q_ATOMIC_INT_FETCH_AND_STORE_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" | 
| 598 | #  endif | 
| 599 | #else | 
| 600 | #  error "Q_ATOMIC_INT_FETCH_AND_STORE_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE is not defined" | 
| 601 | #endif | 
| 602 | } | 
| 603 |  | 
| 604 | void tst_QAtomicInt::isFetchAndStoreWaitFree() | 
| 605 | { | 
| 606 | #if defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_WAIT_FREE) | 
| 607 |     // the runtime test should say the same thing | 
| 608 |     QVERIFY(QAtomicInt::isFetchAndStoreWaitFree()); | 
| 609 |  | 
| 610 |     // enforce some invariants | 
| 611 |     QVERIFY(QAtomicInt::isFetchAndStoreNative()); | 
| 612 | #  if defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_NOT_NATIVE) | 
| 613 | #    error "Reference counting cannot be wait-free and unsupported at the same time!" | 
| 614 | #  endif | 
| 615 | #else | 
| 616 |     // the runtime test should say the same thing | 
| 617 |     QVERIFY(!QAtomicInt::isFetchAndStoreWaitFree()); | 
| 618 | #endif | 
| 619 | } | 
| 620 |  | 
| 621 | void tst_QAtomicInt::fetchAndStore_data() | 
| 622 | { | 
| 623 |     QTest::addColumn<int>(name: "value" ); | 
| 624 |     QTest::addColumn<int>(name: "newval" ); | 
| 625 |  | 
| 626 |     QTest::newRow(dataTag: "data0" ) << 0 << 1; | 
| 627 |     QTest::newRow(dataTag: "data1" ) << 1 << 2; | 
| 628 |     QTest::newRow(dataTag: "data2" ) << 3 << 8; | 
| 629 | } | 
| 630 |  | 
| 631 | void tst_QAtomicInt::fetchAndStore() | 
| 632 | { | 
| 633 |     QFETCH(int, value); | 
| 634 |     QFETCH(int, newval); | 
| 635 |  | 
| 636 |     { | 
| 637 |         QAtomicInt atomic = value; | 
| 638 |         QCOMPARE(atomic.fetchAndStoreRelaxed(newval), value); | 
| 639 |         QCOMPARE(atomic.loadRelaxed(), newval); | 
| 640 |     } | 
| 641 |  | 
| 642 |     { | 
| 643 |         QAtomicInt atomic = value; | 
| 644 |         QCOMPARE(atomic.fetchAndStoreAcquire(newval), value); | 
| 645 |         QCOMPARE(atomic.loadRelaxed(), newval); | 
| 646 |     } | 
| 647 |  | 
| 648 |     { | 
| 649 |         QAtomicInt atomic = value; | 
| 650 |         QCOMPARE(atomic.fetchAndStoreRelease(newval), value); | 
| 651 |         QCOMPARE(atomic.loadRelaxed(), newval); | 
| 652 |     } | 
| 653 |  | 
| 654 |     { | 
| 655 |         QAtomicInt atomic = value; | 
| 656 |         QCOMPARE(atomic.fetchAndStoreOrdered(newval), value); | 
| 657 |         QCOMPARE(atomic.loadRelaxed(), newval); | 
| 658 |     } | 
| 659 | } | 
| 660 |  | 
| 661 | void tst_QAtomicInt::isFetchAndAddNative() | 
| 662 | { | 
| 663 | #if defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_ALWAYS_NATIVE) | 
| 664 |     // the runtime test should say the same thing | 
| 665 |     QVERIFY(QAtomicInt::isFetchAndAddNative()); | 
| 666 |  | 
| 667 | #  if (defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_SOMETIMES_NATIVE)     \ | 
| 668 |        || defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_NOT_NATIVE)) | 
| 669 | #    error "Define only one of Q_ATOMIC_INT_FETCH_AND_ADD_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" | 
| 670 | #  endif | 
| 671 | #elif defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_SOMETIMES_NATIVE) | 
| 672 |     // could be either, just want to make sure the function is implemented | 
| 673 |     QVERIFY(QAtomicInt::isFetchAndAddNative() || !QAtomicInt::isFetchAndAddNative()); | 
| 674 |  | 
| 675 | #  if (defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_ALWAYS_NATIVE) \ | 
| 676 |        || defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_NOT_NATIVE)) | 
| 677 | #    error "Define only one of Q_ATOMIC_INT_FETCH_AND_ADD_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" | 
| 678 | #  endif | 
| 679 | #elif defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_NOT_NATIVE) | 
| 680 |     // the runtime test should say the same thing | 
| 681 |     QVERIFY(!QAtomicInt::isFetchAndAddNative()); | 
| 682 |  | 
| 683 | #  if (defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_ALWAYS_NATIVE) \ | 
| 684 |        || defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_SOMETIMES_NATIVE)) | 
| 685 | #    error "Define only one of Q_ATOMIC_INT_FETCH_AND_ADD_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" | 
| 686 | #  endif | 
| 687 | #else | 
| 688 | #  error "Q_ATOMIC_INT_FETCH_AND_ADD_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE is not defined" | 
| 689 | #endif | 
| 690 | } | 
| 691 |  | 
| 692 | void tst_QAtomicInt::isFetchAndAddWaitFree() | 
| 693 | { | 
| 694 | #if defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_WAIT_FREE) | 
| 695 |     // the runtime test should say the same thing | 
| 696 |     QVERIFY(QAtomicInt::isFetchAndAddWaitFree()); | 
| 697 |  | 
| 698 |     // enforce some invariants | 
| 699 |     QVERIFY(QAtomicInt::isFetchAndAddNative()); | 
| 700 | #  if defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_NOT_NATIVE) | 
| 701 | #    error "Reference counting cannot be wait-free and unsupported at the same time!" | 
| 702 | #  endif | 
| 703 | #else | 
| 704 |     // the runtime test should say the same thing | 
| 705 |     QVERIFY(!QAtomicInt::isFetchAndAddWaitFree()); | 
| 706 | #endif | 
| 707 | } | 
| 708 |  | 
| 709 | void tst_QAtomicInt::fetchAndAdd_data() | 
| 710 | { | 
| 711 |     QTest::addColumn<int>(name: "value1" ); | 
| 712 |     QTest::addColumn<int>(name: "value2" ); | 
| 713 |  | 
| 714 |     QTest::newRow(dataTag: "0+1" ) << 0 << 1; | 
| 715 |     QTest::newRow(dataTag: "1+0" ) << 1 << 0; | 
| 716 |     QTest::newRow(dataTag: "1+2" ) << 1 << 2; | 
| 717 |     QTest::newRow(dataTag: "2+1" ) << 2 << 1; | 
| 718 |     QTest::newRow(dataTag: "10+21" ) << 10 << 21; | 
| 719 |     QTest::newRow(dataTag: "31+40" ) << 31 << 40; | 
| 720 |     QTest::newRow(dataTag: "51+62" ) << 51 << 62; | 
| 721 |     QTest::newRow(dataTag: "72+81" ) << 72 << 81; | 
| 722 |     QTest::newRow(dataTag: "810+721" ) << 810 << 721; | 
| 723 |     QTest::newRow(dataTag: "631+540" ) << 631 << 540; | 
| 724 |     QTest::newRow(dataTag: "451+362" ) << 451 << 362; | 
| 725 |     QTest::newRow(dataTag: "272+181" ) << 272 << 181; | 
| 726 |     QTest::newRow(dataTag: "1810+8721" ) << 1810 << 8721; | 
| 727 |     QTest::newRow(dataTag: "3631+6540" ) << 3631 << 6540; | 
| 728 |     QTest::newRow(dataTag: "5451+4362" ) << 5451 << 4362; | 
| 729 |     QTest::newRow(dataTag: "7272+2181" ) << 7272 << 2181; | 
| 730 |  | 
| 731 |     QTest::newRow(dataTag: "0+-1" ) << 0 << -1; | 
| 732 |     QTest::newRow(dataTag: "1+0" ) << 1 << 0; | 
| 733 |     QTest::newRow(dataTag: "1+-2" ) << 1 << -2; | 
| 734 |     QTest::newRow(dataTag: "2+-1" ) << 2 << -1; | 
| 735 |     QTest::newRow(dataTag: "10+-21" ) << 10 << -21; | 
| 736 |     QTest::newRow(dataTag: "31+-40" ) << 31 << -40; | 
| 737 |     QTest::newRow(dataTag: "51+-62" ) << 51 << -62; | 
| 738 |     QTest::newRow(dataTag: "72+-81" ) << 72 << -81; | 
| 739 |     QTest::newRow(dataTag: "810+-721" ) << 810 << -721; | 
| 740 |     QTest::newRow(dataTag: "631+-540" ) << 631 << -540; | 
| 741 |     QTest::newRow(dataTag: "451+-362" ) << 451 << -362; | 
| 742 |     QTest::newRow(dataTag: "272+-181" ) << 272 << -181; | 
| 743 |     QTest::newRow(dataTag: "1810+-8721" ) << 1810 << -8721; | 
| 744 |     QTest::newRow(dataTag: "3631+-6540" ) << 3631 << -6540; | 
| 745 |     QTest::newRow(dataTag: "5451+-4362" ) << 5451 << -4362; | 
| 746 |     QTest::newRow(dataTag: "7272+-2181" ) << 7272 << -2181; | 
| 747 |  | 
| 748 |     QTest::newRow(dataTag: "0+1" ) << 0 << 1; | 
| 749 |     QTest::newRow(dataTag: "-1+0" ) << -1 << 0; | 
| 750 |     QTest::newRow(dataTag: "-1+2" ) << -1 << 2; | 
| 751 |     QTest::newRow(dataTag: "-2+1" ) << -2 << 1; | 
| 752 |     QTest::newRow(dataTag: "-10+21" ) << -10 << 21; | 
| 753 |     QTest::newRow(dataTag: "-31+40" ) << -31 << 40; | 
| 754 |     QTest::newRow(dataTag: "-51+62" ) << -51 << 62; | 
| 755 |     QTest::newRow(dataTag: "-72+81" ) << -72 << 81; | 
| 756 |     QTest::newRow(dataTag: "-810+721" ) << -810 << 721; | 
| 757 |     QTest::newRow(dataTag: "-631+540" ) << -631 << 540; | 
| 758 |     QTest::newRow(dataTag: "-451+362" ) << -451 << 362; | 
| 759 |     QTest::newRow(dataTag: "-272+181" ) << -272 << 181; | 
| 760 |     QTest::newRow(dataTag: "-1810+8721" ) << -1810 << 8721; | 
| 761 |     QTest::newRow(dataTag: "-3631+6540" ) << -3631 << 6540; | 
| 762 |     QTest::newRow(dataTag: "-5451+4362" ) << -5451 << 4362; | 
| 763 |     QTest::newRow(dataTag: "-7272+2181" ) << -7272 << 2181; | 
| 764 | } | 
| 765 |  | 
| 766 | void tst_QAtomicInt::fetchAndAdd() | 
| 767 | { | 
| 768 |     QFETCH(int, value1); | 
| 769 |     QFETCH(int, value2); | 
| 770 |     int result; | 
| 771 |  | 
| 772 |     { | 
| 773 |         QAtomicInt atomic = value1; | 
| 774 |         result = atomic.fetchAndAddRelaxed(valueToAdd: value2); | 
| 775 |         QCOMPARE(result, value1); | 
| 776 |         QCOMPARE(atomic.loadRelaxed(), value1 + value2); | 
| 777 |     } | 
| 778 |  | 
| 779 |     { | 
| 780 |         QAtomicInt atomic = value1; | 
| 781 |         result = atomic.fetchAndAddAcquire(valueToAdd: value2); | 
| 782 |         QCOMPARE(result, value1); | 
| 783 |         QCOMPARE(atomic.loadRelaxed(), value1 + value2); | 
| 784 |     } | 
| 785 |  | 
| 786 |     { | 
| 787 |         QAtomicInt atomic = value1; | 
| 788 |         result = atomic.fetchAndAddRelease(valueToAdd: value2); | 
| 789 |         QCOMPARE(result, value1); | 
| 790 |         QCOMPARE(atomic.loadRelaxed(), value1 + value2); | 
| 791 |     } | 
| 792 |  | 
| 793 |     { | 
| 794 |         QAtomicInt atomic = value1; | 
| 795 |         result = atomic.fetchAndAddOrdered(valueToAdd: value2); | 
| 796 |         QCOMPARE(result, value1); | 
| 797 |         QCOMPARE(atomic.loadRelaxed(), value1 + value2); | 
| 798 |     } | 
| 799 | } | 
| 800 |  | 
| 801 | void tst_QAtomicInt::operators() | 
| 802 | { | 
| 803 |     { | 
| 804 |         // Test that QBasicAtomicInt also has operator= and cast operators | 
| 805 |         // We've been using them for QAtomicInt elsewhere | 
| 806 |         QBasicAtomicInt atomic = Q_BASIC_ATOMIC_INITIALIZER(0); | 
| 807 |         atomic = 1; | 
| 808 |         QCOMPARE(int(atomic), 1); | 
| 809 |     } | 
| 810 |  | 
| 811 |     QAtomicInt atomic = 0; | 
| 812 |     int x = ++atomic; | 
| 813 |     QCOMPARE(int(atomic), x); | 
| 814 |     QCOMPARE(int(atomic), 1); | 
| 815 |  | 
| 816 |     x = atomic++; | 
| 817 |     QCOMPARE(int(atomic), x + 1); | 
| 818 |     QCOMPARE(int(atomic), 2); | 
| 819 |  | 
| 820 |     x = atomic--; | 
| 821 |     QCOMPARE(int(atomic), x - 1); | 
| 822 |     QCOMPARE(int(atomic), 1); | 
| 823 |  | 
| 824 |     x = --atomic; | 
| 825 |     QCOMPARE(int(atomic), x); | 
| 826 |     QCOMPARE(int(atomic), 0); | 
| 827 |  | 
| 828 |     x = (atomic += 1); | 
| 829 |     QCOMPARE(int(atomic), x); | 
| 830 |     QCOMPARE(int(atomic), 1); | 
| 831 |  | 
| 832 |     x = (atomic -= 1); | 
| 833 |     QCOMPARE(int(atomic), x); | 
| 834 |     QCOMPARE(int(atomic), 0); | 
| 835 |  | 
| 836 |     x = (atomic |= 0xf); | 
| 837 |     QCOMPARE(int(atomic), x); | 
| 838 |     QCOMPARE(int(atomic), 0xf); | 
| 839 |  | 
| 840 |     x = (atomic &= 0x17); | 
| 841 |     QCOMPARE(int(atomic), x); | 
| 842 |     QCOMPARE(int(atomic), 7); | 
| 843 |  | 
| 844 |     x = (atomic ^= 0x14); | 
| 845 |     QCOMPARE(int(atomic), x); | 
| 846 |     QCOMPARE(int(atomic), 0x13); | 
| 847 |  | 
| 848 |     x = (atomic ^= atomic); | 
| 849 |     QCOMPARE(int(atomic), x); | 
| 850 |     QCOMPARE(int(atomic), 0); | 
| 851 | } | 
| 852 |  | 
| 853 | void tst_QAtomicInt::testAndSet_loop() | 
| 854 | { | 
| 855 |     QElapsedTimer stopWatch; | 
| 856 |     stopWatch.start(); | 
| 857 |  | 
| 858 |     int iterations = 10000000; | 
| 859 |  | 
| 860 |     QAtomicInt val=0; | 
| 861 |     for (int i = 0; i < iterations; ++i) { | 
| 862 |         int v = val.loadRelaxed(); | 
| 863 |         QVERIFY(val.testAndSetRelaxed(v, v+1)); | 
| 864 |         if ((i % 1000) == 999) { | 
| 865 |             if (stopWatch.elapsed() > 60 * 1000) { | 
| 866 |                 // This test shouldn't run for more than two minutes. | 
| 867 |                 qDebug(msg: "Interrupted test after %d iterations (%.2f iterations/sec)" , | 
| 868 |                        i, (i * 1000.0) / double(stopWatch.elapsed())); | 
| 869 |                 break; | 
| 870 |             } | 
| 871 |         } | 
| 872 |     } | 
| 873 | } | 
| 874 |  | 
| 875 | void tst_QAtomicInt::fetchAndAdd_loop() | 
| 876 | { | 
| 877 |     int iterations = 10000000; | 
| 878 | #if defined (Q_OS_HPUX) | 
| 879 |     iterations = 1000000; | 
| 880 | #endif | 
| 881 |  | 
| 882 |     QAtomicInt val=0; | 
| 883 |     for (int i = 0; i < iterations; ++i) { | 
| 884 |         const int prev = val.fetchAndAddRelaxed(valueToAdd: 1); | 
| 885 |         QCOMPARE(prev, val.loadRelaxed() -1); | 
| 886 |     } | 
| 887 | } | 
| 888 |  | 
| 889 | class FetchAndAddThread : public QThread | 
| 890 | { | 
| 891 | public: | 
| 892 |     void run() | 
| 893 |     { | 
| 894 |  | 
| 895 |         for (int i = 0; i < iterations; ++i) | 
| 896 |             val->fetchAndAddAcquire(valueToAdd: 1); | 
| 897 |  | 
| 898 |         for (int i = 0; i < iterations; ++i) | 
| 899 |             val->fetchAndAddAcquire(valueToAdd: -1); | 
| 900 |  | 
| 901 |     } | 
| 902 | QAtomicInt *val; | 
| 903 | int iterations; | 
| 904 | }; | 
| 905 |  | 
| 906 |  | 
| 907 | void tst_QAtomicInt::fetchAndAdd_threadedLoop() | 
| 908 | { | 
| 909 |     QAtomicInt val; | 
| 910 |     FetchAndAddThread t1; | 
| 911 |     t1.val = &val; | 
| 912 |     t1.iterations = 1000000; | 
| 913 |  | 
| 914 |     FetchAndAddThread t2; | 
| 915 |     t2.val = &val; | 
| 916 |     t2.iterations = 2000000; | 
| 917 |  | 
| 918 |     t1.start(); | 
| 919 |     t2.start(); | 
| 920 |     t1.wait(); | 
| 921 |     t2.wait(); | 
| 922 |  | 
| 923 |     QCOMPARE(val.loadRelaxed(), 0); | 
| 924 | } | 
| 925 |  | 
| 926 | QTEST_MAIN(tst_QAtomicInt) | 
| 927 | #include "tst_qatomicint.moc" | 
| 928 |  |