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 | |
35 | class tst_QAtomicPointer : public QObject |
36 | { |
37 | Q_OBJECT |
38 | private 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(); |
63 | private: |
64 | static void warningFreeHelper(); |
65 | }; |
66 | |
67 | struct WFHC |
68 | { |
69 | void bar() {} |
70 | }; |
71 | |
72 | void 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 | |
100 | void 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 | |
109 | void 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 | |
118 | void 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 | |
133 | void 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 | |
154 | void 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 | |
177 | void 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 | |
209 | void 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 | |
226 | void 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 | |
305 | void 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 | |
337 | void 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 | |
354 | void 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 | |
433 | void 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 | |
465 | void 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 | |
482 | void 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 | |
517 | void 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 | |
590 | template <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 | |
633 | void 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 | |
641 | struct ForwardDeclared; |
642 | struct ContainsForwardDeclared |
643 | { |
644 | QAtomicPointer<ForwardDeclared> ptr; |
645 | }; |
646 | |
647 | void 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 | |
657 | template <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 | |
699 | struct Big { double d[10]; }; |
700 | void tst_QAtomicPointer::operators() |
701 | { |
702 | operators_helper<char>(); |
703 | operators_helper<int>(); |
704 | operators_helper<double>(); |
705 | operators_helper<Big>(); |
706 | } |
707 | |
708 | QTEST_APPLESS_MAIN(tst_QAtomicPointer) |
709 | #include "tst_qatomicpointer.moc" |
710 | |