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 <qatomic.h>
33#include <limits.h>
34
35class tst_QAtomicPointer : public QObject
36{
37 Q_OBJECT
38private slots:
39 void warningFree();
40 void alignment();
41
42 void constructor();
43 void copy_constructor();
44 void assignment_operator();
45
46 void isTestAndSetNative();
47 void isTestAndSetWaitFree();
48 void testAndSet();
49
50 void isFetchAndStoreNative();
51 void isFetchAndStoreWaitFree();
52 void fetchAndStore();
53
54 void isFetchAndAddNative();
55 void isFetchAndAddWaitFree();
56 void fetchAndAdd_data();
57 void fetchAndAdd();
58
59 void constAndVolatile();
60 void forwardDeclared();
61
62 void operators();
63private:
64 static void warningFreeHelper();
65};
66
67struct WFHC
68{
69 void bar() {}
70};
71
72void tst_QAtomicPointer::warningFreeHelper()
73{
74 qFatal(msg: "This code is bogus, and shouldn't be run. We're looking for compiler warnings only.");
75
76 QBasicAtomicPointer<WFHC> p = Q_BASIC_ATOMIC_INITIALIZER(0);
77
78 p.loadRelaxed()->bar();
79
80 WFHC *expectedValue = 0;
81 WFHC *newValue = 0;
82 qptrdiff valueToAdd = 0;
83
84 p.testAndSetRelaxed(expectedValue, newValue);
85 p.testAndSetAcquire(expectedValue, newValue);
86 p.testAndSetRelease(expectedValue, newValue);
87 p.testAndSetOrdered(expectedValue, newValue);
88
89 p.fetchAndStoreRelaxed(newValue);
90 p.fetchAndStoreAcquire(newValue);
91 p.fetchAndStoreRelease(newValue);
92 p.fetchAndStoreOrdered(newValue);
93
94 p.fetchAndAddRelaxed(valueToAdd);
95 p.fetchAndAddAcquire(valueToAdd);
96 p.fetchAndAddRelease(valueToAdd);
97 p.fetchAndAddOrdered(valueToAdd);
98}
99
100void tst_QAtomicPointer::warningFree()
101{
102 // This is a compile time check for warnings.
103 // No need for actual work here.
104
105 void (*foo)() = &warningFreeHelper;
106 (void)foo;
107}
108
109void tst_QAtomicPointer::alignment()
110{
111#ifdef Q_ALIGNOF
112 // this will cause a build error if the alignment isn't the same
113 char dummy[Q_ALIGNOF(QBasicAtomicPointer<void>) == Q_ALIGNOF(void*) ? 1 : -1];
114 (void)dummy;
115#endif
116}
117
118void tst_QAtomicPointer::constructor()
119{
120 void *one = this;
121 QAtomicPointer<void> atomic1 = one;
122 QCOMPARE(atomic1.loadRelaxed(), one);
123
124 void *two = &one;
125 QAtomicPointer<void> atomic2 = two;
126 QCOMPARE(atomic2.loadRelaxed(), two);
127
128 void *three = &two;
129 QAtomicPointer<void> atomic3 = three;
130 QCOMPARE(atomic3.loadRelaxed(), three);
131}
132
133void tst_QAtomicPointer::copy_constructor()
134{
135 void *one = this;
136 QAtomicPointer<void> atomic1 = one;
137 QAtomicPointer<void> atomic1_copy = atomic1;
138 QCOMPARE(atomic1_copy.loadRelaxed(), one);
139 QCOMPARE(atomic1_copy.loadRelaxed(), atomic1.loadRelaxed());
140
141 void *two = &one;
142 QAtomicPointer<void> atomic2 = two;
143 QAtomicPointer<void> atomic2_copy = atomic2;
144 QCOMPARE(atomic2_copy.loadRelaxed(), two);
145 QCOMPARE(atomic2_copy.loadRelaxed(), atomic2.loadRelaxed());
146
147 void *three = &two;
148 QAtomicPointer<void> atomic3 = three;
149 QAtomicPointer<void> atomic3_copy = atomic3;
150 QCOMPARE(atomic3_copy.loadRelaxed(), three);
151 QCOMPARE(atomic3_copy.loadRelaxed(), atomic3.loadRelaxed());
152}
153
154void tst_QAtomicPointer::assignment_operator()
155{
156 void *one = this;
157 void *two = &one;
158 void *three = &two;
159
160 QAtomicPointer<void> atomic1 = one;
161 QAtomicPointer<void> atomic2 = two;
162 QAtomicPointer<void> atomic3 = three;
163
164 QCOMPARE(atomic1.loadRelaxed(), one);
165 QCOMPARE(atomic2.loadRelaxed(), two);
166 QCOMPARE(atomic3.loadRelaxed(), three);
167
168 atomic1 = two;
169 atomic2 = three;
170 atomic3 = one;
171
172 QCOMPARE(atomic1.loadRelaxed(), two);
173 QCOMPARE(atomic2.loadRelaxed(), three);
174 QCOMPARE(atomic3.loadRelaxed(), one);
175}
176
177void tst_QAtomicPointer::isTestAndSetNative()
178{
179#if defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE)
180 // the runtime test should say the same thing
181 QVERIFY(QAtomicPointer<void>::isTestAndSetNative());
182
183# if (defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_SOMETIMES_NATIVE) \
184 || defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_NOT_NATIVE))
185# error "Define only one of Q_ATOMIC_POINTER_TEST_AND_SET_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE"
186# endif
187#elif defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_SOMETIMES_NATIVE)
188 // could be either, just want to make sure the function is implemented
189 QVERIFY(QAtomicPointer<void>::isTestAndSetNative()
190 || !QAtomicPointer<void>::isTestAndSetNative());
191
192# if (defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE) \
193 || defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_NOT_NATIVE))
194# error "Define only one of Q_ATOMIC_POINTER_TEST_AND_SET_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE"
195# endif
196#elif defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_NOT_NATIVE)
197 // the runtime test should say the same thing
198 QVERIFY(!QAtomicPointer<void>::isTestAndSetNative());
199
200# if (defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE) \
201 || defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_SOMETIMES_NATIVE))
202# error "Define only one of Q_ATOMIC_POINTER_TEST_AND_SET_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE"
203# endif
204#else
205# error "Q_ATOMIC_POINTER_TEST_AND_SET_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE is not defined"
206#endif
207}
208
209void tst_QAtomicPointer::isTestAndSetWaitFree()
210{
211#if defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_WAIT_FREE)
212 // the runtime test should say the same thing
213 QVERIFY(QAtomicPointer<void>::isTestAndSetWaitFree());
214
215 // enforce some invariants
216 QVERIFY(QAtomicPointer<void>::isTestAndSetNative());
217# if defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_NOT_NATIVE)
218# error "Reference counting cannot be wait-free and unsupported at the same time!"
219# endif
220#else
221 // the runtime test should say the same thing
222 QVERIFY(!QAtomicPointer<void>::isTestAndSetWaitFree());
223#endif
224}
225
226void tst_QAtomicPointer::testAndSet()
227{
228 void *one = this;
229 void *two = &one;
230 void *three = &two;
231
232 {
233 QAtomicPointer<void> atomic1 = one;
234 QAtomicPointer<void> atomic2 = two;
235 QAtomicPointer<void> atomic3 = three;
236
237 QCOMPARE(atomic1.loadRelaxed(), one);
238 QCOMPARE(atomic2.loadRelaxed(), two);
239 QCOMPARE(atomic3.loadRelaxed(), three);
240
241 QVERIFY(atomic1.testAndSetRelaxed(one, two));
242 QVERIFY(atomic2.testAndSetRelaxed(two, three));
243 QVERIFY(atomic3.testAndSetRelaxed(three, one));
244
245 QCOMPARE(atomic1.loadRelaxed(), two);
246 QCOMPARE(atomic2.loadRelaxed(), three);
247 QCOMPARE(atomic3.loadRelaxed(), one);
248 }
249
250 {
251 QAtomicPointer<void> atomic1 = one;
252 QAtomicPointer<void> atomic2 = two;
253 QAtomicPointer<void> atomic3 = three;
254
255 QCOMPARE(atomic1.loadRelaxed(), one);
256 QCOMPARE(atomic2.loadRelaxed(), two);
257 QCOMPARE(atomic3.loadRelaxed(), three);
258
259 QVERIFY(atomic1.testAndSetAcquire(one, two));
260 QVERIFY(atomic2.testAndSetAcquire(two, three));
261 QVERIFY(atomic3.testAndSetAcquire(three, one));
262
263 QCOMPARE(atomic1.loadRelaxed(), two);
264 QCOMPARE(atomic2.loadRelaxed(), three);
265 QCOMPARE(atomic3.loadRelaxed(), one);
266 }
267
268 {
269 QAtomicPointer<void> atomic1 = one;
270 QAtomicPointer<void> atomic2 = two;
271 QAtomicPointer<void> atomic3 = three;
272
273 QCOMPARE(atomic1.loadRelaxed(), one);
274 QCOMPARE(atomic2.loadRelaxed(), two);
275 QCOMPARE(atomic3.loadRelaxed(), three);
276
277 QVERIFY(atomic1.testAndSetRelease(one, two));
278 QVERIFY(atomic2.testAndSetRelease(two, three));
279 QVERIFY(atomic3.testAndSetRelease(three, one));
280
281 QCOMPARE(atomic1.loadRelaxed(), two);
282 QCOMPARE(atomic2.loadRelaxed(), three);
283 QCOMPARE(atomic3.loadRelaxed(), one);
284 }
285
286 {
287 QAtomicPointer<void> atomic1 = one;
288 QAtomicPointer<void> atomic2 = two;
289 QAtomicPointer<void> atomic3 = three;
290
291 QCOMPARE(atomic1.loadRelaxed(), one);
292 QCOMPARE(atomic2.loadRelaxed(), two);
293 QCOMPARE(atomic3.loadRelaxed(), three);
294
295 QVERIFY(atomic1.testAndSetOrdered(one, two));
296 QVERIFY(atomic2.testAndSetOrdered(two, three));
297 QVERIFY(atomic3.testAndSetOrdered(three, one));
298
299 QCOMPARE(atomic1.loadRelaxed(), two);
300 QCOMPARE(atomic2.loadRelaxed(), three);
301 QCOMPARE(atomic3.loadRelaxed(), one);
302 }
303}
304
305void tst_QAtomicPointer::isFetchAndStoreNative()
306{
307#if defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE)
308 // the runtime test should say the same thing
309 QVERIFY(QAtomicPointer<void>::isFetchAndStoreNative());
310
311# if (defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_SOMETIMES_NATIVE) \
312 || defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_NOT_NATIVE))
313# error "Define only one of Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE"
314# endif
315#elif defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_SOMETIMES_NATIVE)
316 // could be either, just want to make sure the function is implemented
317 QVERIFY(QAtomicPointer<void>::isFetchAndStoreNative()
318 || !QAtomicPointer<void>::isFetchAndStoreNative());
319
320# if (defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE) \
321 || defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_NOT_NATIVE))
322# error "Define only one of Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE"
323# endif
324#elif defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_NOT_NATIVE)
325 // the runtime test should say the same thing
326 QVERIFY(!QAtomicPointer<void>::isFetchAndStoreNative());
327
328# if (defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE) \
329 || defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_SOMETIMES_NATIVE))
330# error "Define only one of Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE"
331# endif
332#else
333# error "Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE is not defined"
334#endif
335}
336
337void tst_QAtomicPointer::isFetchAndStoreWaitFree()
338{
339#if defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_WAIT_FREE)
340 // the runtime test should say the same thing
341 QVERIFY(QAtomicPointer<void>::isFetchAndStoreWaitFree());
342
343 // enforce some invariants
344 QVERIFY(QAtomicPointer<void>::isFetchAndStoreNative());
345# if defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_NOT_NATIVE)
346# error "Reference counting cannot be wait-free and unsupported at the same time!"
347# endif
348#else
349 // the runtime test should say the same thing
350 QVERIFY(!QAtomicPointer<void>::isFetchAndStoreWaitFree());
351#endif
352}
353
354void tst_QAtomicPointer::fetchAndStore()
355{
356 void *one = this;
357 void *two = &one;
358 void *three = &two;
359
360 {
361 QAtomicPointer<void> atomic1 = one;
362 QAtomicPointer<void> atomic2 = two;
363 QAtomicPointer<void> atomic3 = three;
364
365 QCOMPARE(atomic1.loadRelaxed(), one);
366 QCOMPARE(atomic2.loadRelaxed(), two);
367 QCOMPARE(atomic3.loadRelaxed(), three);
368
369 QCOMPARE(atomic1.fetchAndStoreRelaxed(two), one);
370 QCOMPARE(atomic2.fetchAndStoreRelaxed(three), two);
371 QCOMPARE(atomic3.fetchAndStoreRelaxed(one), three);
372
373 QCOMPARE(atomic1.loadRelaxed(), two);
374 QCOMPARE(atomic2.loadRelaxed(), three);
375 QCOMPARE(atomic3.loadRelaxed(), one);
376 }
377
378 {
379 QAtomicPointer<void> atomic1 = one;
380 QAtomicPointer<void> atomic2 = two;
381 QAtomicPointer<void> atomic3 = three;
382
383 QCOMPARE(atomic1.loadRelaxed(), one);
384 QCOMPARE(atomic2.loadRelaxed(), two);
385 QCOMPARE(atomic3.loadRelaxed(), three);
386
387 QCOMPARE(atomic1.fetchAndStoreAcquire(two), one);
388 QCOMPARE(atomic2.fetchAndStoreAcquire(three), two);
389 QCOMPARE(atomic3.fetchAndStoreAcquire(one), three);
390
391 QCOMPARE(atomic1.loadRelaxed(), two);
392 QCOMPARE(atomic2.loadRelaxed(), three);
393 QCOMPARE(atomic3.loadRelaxed(), one);
394 }
395
396 {
397 QAtomicPointer<void> atomic1 = one;
398 QAtomicPointer<void> atomic2 = two;
399 QAtomicPointer<void> atomic3 = three;
400
401 QCOMPARE(atomic1.loadRelaxed(), one);
402 QCOMPARE(atomic2.loadRelaxed(), two);
403 QCOMPARE(atomic3.loadRelaxed(), three);
404
405 QCOMPARE(atomic1.fetchAndStoreRelease(two), one);
406 QCOMPARE(atomic2.fetchAndStoreRelease(three), two);
407 QCOMPARE(atomic3.fetchAndStoreRelease(one), three);
408
409 QCOMPARE(atomic1.loadRelaxed(), two);
410 QCOMPARE(atomic2.loadRelaxed(), three);
411 QCOMPARE(atomic3.loadRelaxed(), one);
412 }
413
414 {
415 QAtomicPointer<void> atomic1 = one;
416 QAtomicPointer<void> atomic2 = two;
417 QAtomicPointer<void> atomic3 = three;
418
419 QCOMPARE(atomic1.loadRelaxed(), one);
420 QCOMPARE(atomic2.loadRelaxed(), two);
421 QCOMPARE(atomic3.loadRelaxed(), three);
422
423 QCOMPARE(atomic1.fetchAndStoreOrdered(two), one);
424 QCOMPARE(atomic2.fetchAndStoreOrdered(three), two);
425 QCOMPARE(atomic3.fetchAndStoreOrdered(one), three);
426
427 QCOMPARE(atomic1.loadRelaxed(), two);
428 QCOMPARE(atomic2.loadRelaxed(), three);
429 QCOMPARE(atomic3.loadRelaxed(), one);
430 }
431}
432
433void tst_QAtomicPointer::isFetchAndAddNative()
434{
435#if defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE)
436 // the runtime test should say the same thing
437 QVERIFY(QAtomicPointer<void>::isFetchAndAddNative());
438
439# if (defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_SOMETIMES_NATIVE) \
440 || defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_NOT_NATIVE))
441# error "Define only one of Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE"
442# endif
443#elif defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_SOMETIMES_NATIVE)
444 // could be either, just want to make sure the function is implemented
445 QVERIFY(QAtomicPointer<void>::isFetchAndAddNative()
446 || !QAtomicPointer<void>::isFetchAndAddNative());
447
448# if (defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE) \
449 || defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_NOT_NATIVE))
450# error "Define only one of Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE"
451# endif
452#elif defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_NOT_NATIVE)
453 // the runtime test should say the same thing
454 QVERIFY(!QAtomicPointer<void>::isFetchAndAddNative());
455
456# if (defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE) \
457 || defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_SOMETIMES_NATIVE))
458# error "Define only one of Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE"
459# endif
460#else
461# error "Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE is not defined"
462#endif
463}
464
465void tst_QAtomicPointer::isFetchAndAddWaitFree()
466{
467#if defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_WAIT_FREE)
468 // the runtime test should say the same thing
469 QVERIFY(QAtomicPointer<void>::isFetchAndAddWaitFree());
470
471 // enforce some invariants
472 QVERIFY(QAtomicPointer<void>::isFetchAndAddNative());
473# if defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_NOT_NATIVE)
474# error "Reference counting cannot be wait-free and unsupported at the same time!"
475# endif
476#else
477 // the runtime test should say the same thing
478 QVERIFY(!QAtomicPointer<void>::isFetchAndAddWaitFree());
479#endif
480}
481
482void tst_QAtomicPointer::fetchAndAdd_data()
483{
484 QTest::addColumn<int>(name: "valueToAdd");
485
486 QTest::newRow(dataTag: "0") << 0;
487 QTest::newRow(dataTag: "1") << 1;
488 QTest::newRow(dataTag: "2") << 2;
489 QTest::newRow(dataTag: "10") << 10;
490 QTest::newRow(dataTag: "31") << 31;
491 QTest::newRow(dataTag: "51") << 51;
492 QTest::newRow(dataTag: "72") << 72;
493 QTest::newRow(dataTag: "810") << 810;
494 QTest::newRow(dataTag: "631") << 631;
495 QTest::newRow(dataTag: "451") << 451;
496 QTest::newRow(dataTag: "272") << 272;
497 QTest::newRow(dataTag: "1810") << 1810;
498 QTest::newRow(dataTag: "3631") << 3631;
499 QTest::newRow(dataTag: "5451") << 5451;
500 QTest::newRow(dataTag: "7272") << 7272;
501 QTest::newRow(dataTag: "-1") << -1;
502 QTest::newRow(dataTag: "-2") << -2;
503 QTest::newRow(dataTag: "-10") << -10;
504 QTest::newRow(dataTag: "-31") << -31;
505 QTest::newRow(dataTag: "-51") << -51;
506 QTest::newRow(dataTag: "-72") << -72;
507 QTest::newRow(dataTag: "-810") << -810;
508 QTest::newRow(dataTag: "-631") << -631;
509 QTest::newRow(dataTag: "-451") << -451;
510 QTest::newRow(dataTag: "-272") << -272;
511 QTest::newRow(dataTag: "-1810") << -1810;
512 QTest::newRow(dataTag: "-3631") << -3631;
513 QTest::newRow(dataTag: "-5451") << -5451;
514 QTest::newRow(dataTag: "-7272") << -7272;
515}
516
517void tst_QAtomicPointer::fetchAndAdd()
518{
519 QFETCH(int, valueToAdd);
520
521 char c;
522 char *pc = &c;
523 short s;
524 short *ps = &s;
525 int i;
526 int *pi = &i;
527
528 {
529 QAtomicPointer<char> pointer1 = pc;
530 // cast to void* in order to avoid QCOMPARE to compare string content of the char*
531 QCOMPARE(static_cast<void*>(pointer1.fetchAndAddRelaxed(valueToAdd)), static_cast<void*>(pc));
532 QCOMPARE(static_cast<void*>(pointer1.fetchAndAddRelaxed(-valueToAdd)), static_cast<void*>(pc + valueToAdd));
533 QCOMPARE(static_cast<void*>(pointer1.loadRelaxed()), static_cast<void*>(pc));
534 QAtomicPointer<short> pointer2 = ps;
535 QCOMPARE(pointer2.fetchAndAddRelaxed(valueToAdd), ps);
536 QCOMPARE(pointer2.fetchAndAddRelaxed(-valueToAdd), ps + valueToAdd);
537 QCOMPARE(pointer2.loadRelaxed(), ps);
538 QAtomicPointer<int> pointer3 = pi;
539 QCOMPARE(pointer3.fetchAndAddRelaxed(valueToAdd), pi);
540 QCOMPARE(pointer3.fetchAndAddRelaxed(-valueToAdd), pi + valueToAdd);
541 QCOMPARE(pointer3.loadRelaxed(), pi);
542 }
543
544 {
545 QAtomicPointer<char> pointer1 = pc;
546 QCOMPARE(static_cast<void*>(pointer1.fetchAndAddAcquire(valueToAdd)), static_cast<void*>(pc));
547 QCOMPARE(static_cast<void*>(pointer1.fetchAndAddAcquire(-valueToAdd)), static_cast<void*>(pc + valueToAdd));
548 QCOMPARE(static_cast<void*>(pointer1.loadRelaxed()), static_cast<void*>(pc));
549 QAtomicPointer<short> pointer2 = ps;
550 QCOMPARE(pointer2.fetchAndAddAcquire(valueToAdd), ps);
551 QCOMPARE(pointer2.fetchAndAddAcquire(-valueToAdd), ps + valueToAdd);
552 QCOMPARE(pointer2.loadRelaxed(), ps);
553 QAtomicPointer<int> pointer3 = pi;
554 QCOMPARE(pointer3.fetchAndAddAcquire(valueToAdd), pi);
555 QCOMPARE(pointer3.fetchAndAddAcquire(-valueToAdd), pi + valueToAdd);
556 QCOMPARE(pointer3.loadRelaxed(), pi);
557 }
558
559 {
560 QAtomicPointer<char> pointer1 = pc;
561 QCOMPARE(static_cast<void*>(pointer1.fetchAndAddRelease(valueToAdd)), static_cast<void*>(pc));
562 QCOMPARE(static_cast<void*>(pointer1.fetchAndAddRelease(-valueToAdd)), static_cast<void*>(pc + valueToAdd));
563 QCOMPARE(static_cast<void*>(pointer1.loadRelaxed()), static_cast<void*>(pc));
564 QAtomicPointer<short> pointer2 = ps;
565 QCOMPARE(pointer2.fetchAndAddRelease(valueToAdd), ps);
566 QCOMPARE(pointer2.fetchAndAddRelease(-valueToAdd), ps + valueToAdd);
567 QCOMPARE(pointer2.loadRelaxed(), ps);
568 QAtomicPointer<int> pointer3 = pi;
569 QCOMPARE(pointer3.fetchAndAddRelease(valueToAdd), pi);
570 QCOMPARE(pointer3.fetchAndAddRelease(-valueToAdd), pi + valueToAdd);
571 QCOMPARE(pointer3.loadRelaxed(), pi);
572 }
573
574 {
575 QAtomicPointer<char> pointer1 = pc;
576 QCOMPARE(static_cast<void*>(pointer1.fetchAndAddOrdered(valueToAdd)), static_cast<void*>(pc));
577 QCOMPARE(static_cast<void*>(pointer1.fetchAndAddOrdered(-valueToAdd)), static_cast<void*>(pc + valueToAdd));
578 QCOMPARE(static_cast<void*>(pointer1.loadRelaxed()), static_cast<void*>(pc));
579 QAtomicPointer<short> pointer2 = ps;
580 QCOMPARE(pointer2.fetchAndAddOrdered(valueToAdd), ps);
581 QCOMPARE(pointer2.fetchAndAddOrdered(-valueToAdd), ps + valueToAdd);
582 QCOMPARE(pointer2.loadRelaxed(), ps);
583 QAtomicPointer<int> pointer3 = pi;
584 QCOMPARE(pointer3.fetchAndAddOrdered(valueToAdd), pi);
585 QCOMPARE(pointer3.fetchAndAddOrdered(-valueToAdd), pi + valueToAdd);
586 QCOMPARE(pointer3.loadRelaxed(), pi);
587 }
588}
589
590template <typename T> void constAndVolatile_helper()
591{
592 T *one = 0;
593 T *two = &one;
594 T *three = &two;
595
596 {
597 QAtomicPointer<T> atomic1 = one;
598 QAtomicPointer<T> atomic2 = two;
599 QAtomicPointer<T> atomic3 = three;
600
601 QVERIFY(atomic1.loadRelaxed() == one);
602 QVERIFY(atomic2.loadRelaxed() == two);
603 QVERIFY(atomic3.loadRelaxed() == three);
604
605 QVERIFY(atomic1.fetchAndStoreRelaxed(two) == one);
606 QVERIFY(atomic2.fetchAndStoreRelaxed(three) == two);
607 QVERIFY(atomic3.fetchAndStoreRelaxed(one) == three);
608
609 QVERIFY(atomic1.loadRelaxed() == two);
610 QVERIFY(atomic2.loadRelaxed() == three);
611 QVERIFY(atomic3.loadRelaxed() == one);
612 }
613 {
614 QAtomicPointer<T> atomic1 = one;
615 QAtomicPointer<T> atomic2 = two;
616 QAtomicPointer<T> atomic3 = three;
617
618 QVERIFY(atomic1.loadRelaxed() == one);
619 QVERIFY(atomic2.loadRelaxed() == two);
620 QVERIFY(atomic3.loadRelaxed() == three);
621
622 QVERIFY(atomic1.testAndSetRelaxed(one, two));
623 QVERIFY(atomic2.testAndSetRelaxed(two, three));
624 QVERIFY(atomic3.testAndSetRelaxed(three, one));
625
626 QVERIFY(atomic1.loadRelaxed() == two);
627 QVERIFY(atomic2.loadRelaxed() == three);
628 QVERIFY(atomic3.loadRelaxed() == one);
629 }
630
631}
632
633void tst_QAtomicPointer::constAndVolatile()
634{
635 constAndVolatile_helper<void>();
636 constAndVolatile_helper<const void>();
637 constAndVolatile_helper<volatile void>();
638 constAndVolatile_helper<const volatile void>();
639}
640
641struct ForwardDeclared;
642struct ContainsForwardDeclared
643{
644 QAtomicPointer<ForwardDeclared> ptr;
645};
646
647void tst_QAtomicPointer::forwardDeclared()
648{
649 // this is just a compilation test
650 QAtomicPointer<ForwardDeclared> ptr;
651 ContainsForwardDeclared cfd;
652 Q_UNUSED(ptr);
653 Q_UNUSED(cfd);
654 QVERIFY(true);
655}
656
657template <typename T> static void operators_helper()
658{
659 typedef T *Ptr;
660 T array[3] = {};
661 Ptr zero = array;
662 Ptr one = array + 1;
663 Ptr two = array + 2;
664
665 {
666 // Test that QBasicAtomicPointer also has operator= and cast operators
667 // We've been using them for QAtomicPointer<T> elsewhere
668 QBasicAtomicPointer<T> atomic = Q_BASIC_ATOMIC_INITIALIZER(0);
669 atomic = one;
670 QCOMPARE(Ptr(atomic), one);
671 }
672
673 QAtomicPointer<T> atomic = zero;
674 Ptr x = ++atomic;
675 QCOMPARE(Ptr(atomic), x);
676 QCOMPARE(Ptr(atomic), one);
677
678 x = atomic++;
679 QCOMPARE(Ptr(atomic), x + 1);
680 QCOMPARE(Ptr(atomic), two);
681
682 x = atomic--;
683 QCOMPARE(Ptr(atomic), x - 1);
684 QCOMPARE(Ptr(atomic), one);
685
686 x = --atomic;
687 QCOMPARE(Ptr(atomic), x);
688 QCOMPARE(Ptr(atomic), zero);
689
690 x = (atomic += 1);
691 QCOMPARE(Ptr(atomic), x);
692 QCOMPARE(Ptr(atomic), one);
693
694 x = (atomic -= 1);
695 QCOMPARE(Ptr(atomic), x);
696 QCOMPARE(Ptr(atomic), zero);
697}
698
699struct Big { double d[10]; };
700void tst_QAtomicPointer::operators()
701{
702 operators_helper<char>();
703 operators_helper<int>();
704 operators_helper<double>();
705 operators_helper<Big>();
706}
707
708QTEST_APPLESS_MAIN(tst_QAtomicPointer)
709#include "tst_qatomicpointer.moc"
710

source code of qtbase/tests/auto/corelib/thread/qatomicpointer/tst_qatomicpointer.cpp