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 <qcoreapplication.h>
34#include <qelapsedtimer.h>
35#include <qmutex.h>
36#include <qthread.h>
37#include <qwaitcondition.h>
38
39class tst_QMutex : public QObject
40{
41 Q_OBJECT
42public:
43 enum class TimeUnit {
44 Nanoseconds,
45 Microseconds,
46 Milliseconds,
47 Seconds,
48 };
49 Q_ENUM(TimeUnit);
50
51private slots:
52 void convertToMilliseconds_data();
53 void convertToMilliseconds();
54 void tryLock_non_recursive();
55 void try_lock_for_non_recursive();
56 void try_lock_until_non_recursive();
57 void tryLock_recursive();
58 void try_lock_for_recursive();
59 void try_lock_until_recursive();
60 void lock_unlock_locked_tryLock();
61 void stressTest();
62 void tryLockRace();
63 void tryLockDeadlock();
64 void tryLockNegative_data();
65 void tryLockNegative();
66 void moreStress();
67};
68
69static const int iterations = 100;
70
71QAtomicInt lockCount(0);
72QMutex normalMutex;
73QRecursiveMutex recursiveMutex;
74QSemaphore testsTurn;
75QSemaphore threadsTurn;
76
77/*
78 Depending on the OS, tryWaits may return early than expected because of the
79 resolution of the underlying timer is too coarse. E.g.: on Windows
80 WaitForSingleObjectEx does *not* use high resolution multimedia timers, and
81 it's actually very coarse, about 16msec by default.
82*/
83enum {
84#ifdef Q_OS_WIN
85 systemTimersResolution = 16,
86#else
87 systemTimersResolution = 1,
88#endif
89 waitTime = 100
90};
91
92#if __has_include(<chrono>)
93static Q_CONSTEXPR std::chrono::milliseconds waitTimeAsDuration(waitTime);
94#endif
95
96void tst_QMutex::convertToMilliseconds_data()
97{
98 QTest::addColumn<TimeUnit>(name: "unit");
99 QTest::addColumn<double>(name: "doubleValue");
100 QTest::addColumn<qint64>(name: "intValue");
101 QTest::addColumn<qint64>(name: "expected");
102
103#if !__has_include(<chrono>)
104 QSKIP("This test requires <chrono>");
105#endif
106
107 auto add = [](TimeUnit unit, double d, long long i, qint64 expected) {
108 const QScopedArrayPointer<char> enumName(QTest::toString(t: unit));
109 QTest::addRow(format: "%s:%f:%lld", enumName.data(), d, i)
110 << unit << d << qint64(i) << expected;
111 };
112
113 auto forAllUnitsAdd = [=](double d, long long i, qint64 expected) {
114 for (auto unit : {TimeUnit::Nanoseconds, TimeUnit::Microseconds, TimeUnit::Milliseconds, TimeUnit::Seconds})
115 add(unit, d, i, expected);
116 };
117
118 forAllUnitsAdd(-0.5, -1, 0); // all negative values result in 0
119
120 forAllUnitsAdd(0, 0, 0);
121
122 add(TimeUnit::Nanoseconds, 1, 1, 1);
123 add(TimeUnit::Nanoseconds, 1000 * 1000, 1000 * 1000, 1);
124 add(TimeUnit::Nanoseconds, 1000 * 1000 + 0.5, 1000 * 1000 + 1, 2);
125
126 add(TimeUnit::Microseconds, 1, 1, 1);
127 add(TimeUnit::Microseconds, 1000, 1000, 1);
128 add(TimeUnit::Microseconds, 1000 + 0.5, 1000 + 1, 2);
129
130 add(TimeUnit::Milliseconds, 1, 1, 1);
131 add(TimeUnit::Milliseconds, 1.5, 2, 2);
132
133 add(TimeUnit::Seconds, 0.9991, 1, 1000);
134
135 //
136 // overflowing int results in INT_MAX (equivalent to a spurious wakeup after ~24 days); check it:
137 //
138
139 // spot on:
140 add(TimeUnit::Nanoseconds, INT_MAX * 1000. * 1000, INT_MAX * Q_INT64_C(1000) * 1000, INT_MAX);
141 add(TimeUnit::Microseconds, INT_MAX * 1000., INT_MAX * Q_INT64_C(1000), INT_MAX);
142 add(TimeUnit::Milliseconds, INT_MAX, INT_MAX, INT_MAX);
143
144 // minimally above:
145 add(TimeUnit::Nanoseconds, INT_MAX * 1000. * 1000 + 1, INT_MAX * Q_INT64_C(1000) * 1000 + 1, INT_MAX);
146 add(TimeUnit::Microseconds, INT_MAX * 1000. + 1, INT_MAX * Q_INT64_C(1000) + 1, INT_MAX);
147 add(TimeUnit::Milliseconds, INT_MAX + 1., INT_MAX + Q_INT64_C(1), INT_MAX);
148 add(TimeUnit::Seconds, INT_MAX / 1000. + 1, INT_MAX / 1000 + 1, INT_MAX);
149
150 // minimally below:
151 add(TimeUnit::Nanoseconds, INT_MAX * 1000. * 1000 - 1, INT_MAX * Q_INT64_C(1000) * 1000 - 1, INT_MAX);
152 add(TimeUnit::Microseconds, INT_MAX * 1000. - 1, INT_MAX * Q_INT64_C(1000) - 1, INT_MAX);
153 add(TimeUnit::Milliseconds, INT_MAX - 0.1, INT_MAX , INT_MAX);
154
155}
156
157void tst_QMutex::convertToMilliseconds()
158{
159#if !__has_include(<chrono>)
160 QSKIP("This test requires <chrono>");
161#else
162 QFETCH(TimeUnit, unit);
163 QFETCH(double, doubleValue);
164 QFETCH(qint64, intValue);
165 QFETCH(qint64, expected);
166
167 Q_CONSTEXPR qint64 maxShort = std::numeric_limits<short>::max();
168 Q_CONSTEXPR qint64 maxInt = std::numeric_limits<int>::max();
169 Q_CONSTEXPR qint64 maxUInt = std::numeric_limits<uint>::max();
170
171 switch (unit) {
172#define CASE(Unit, Period) \
173 case TimeUnit::Unit: \
174 DO(double, Period, doubleValue); \
175 if (intValue < maxShort) \
176 DO(short, Period, short(intValue)); \
177 if (intValue < maxInt) \
178 DO(int, Period, int(intValue)); \
179 DO(qint64, Period, intValue); \
180 if (intValue >= 0) { \
181 if (intValue < maxUInt) \
182 DO(uint, Period, uint(intValue)); \
183 DO(quint64, Period, quint64(intValue)); \
184 } \
185 break
186#define DO(Rep, Period, val) \
187 do { \
188 const std::chrono::duration<Rep, Period> wait((val)); \
189 QCOMPARE(QMutex::convertToMilliseconds(wait), expected); \
190 } while (0)
191
192 CASE(Nanoseconds, std::nano);
193 CASE(Microseconds, std::micro);
194 CASE(Milliseconds, std::milli);
195 CASE(Seconds, std::ratio<1>);
196#undef DO
197#undef CASE
198 }
199#endif
200}
201
202void tst_QMutex::tryLock_non_recursive()
203{
204 class Thread : public QThread
205 {
206 public:
207 void run()
208 {
209 testsTurn.release();
210
211 // TEST 1: thread can't acquire lock
212 threadsTurn.acquire();
213 QVERIFY(!normalMutex.tryLock());
214 testsTurn.release();
215
216 // TEST 2: thread can acquire lock
217 threadsTurn.acquire();
218 QVERIFY(normalMutex.tryLock());
219 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
220 QVERIFY(!normalMutex.tryLock());
221 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
222 normalMutex.unlock();
223 testsTurn.release();
224
225 // TEST 3: thread can't acquire lock, timeout = waitTime
226 threadsTurn.acquire();
227 QElapsedTimer timer;
228 timer.start();
229 QVERIFY(!normalMutex.tryLock(waitTime));
230 QVERIFY(timer.elapsed() >= waitTime - systemTimersResolution);
231 testsTurn.release();
232
233 // TEST 4: thread can acquire lock, timeout = waitTime
234 threadsTurn.acquire();
235 timer.start();
236 QVERIFY(normalMutex.tryLock(waitTime));
237 QVERIFY(timer.elapsed() <= waitTime + systemTimersResolution);
238 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
239 timer.start();
240 // it's non-recursive, so the following lock needs to fail
241 QVERIFY(!normalMutex.tryLock(waitTime));
242 QVERIFY(timer.elapsed() >= waitTime - systemTimersResolution);
243 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
244 normalMutex.unlock();
245 testsTurn.release();
246
247 // TEST 5: thread can't acquire lock, timeout = 0
248 threadsTurn.acquire();
249 QVERIFY(!normalMutex.tryLock(0));
250 testsTurn.release();
251
252 // TEST 6: thread can acquire lock, timeout = 0
253 threadsTurn.acquire();
254 timer.start();
255 QVERIFY(normalMutex.tryLock(0));
256 QVERIFY(timer.elapsed() < waitTime + systemTimersResolution);
257 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
258 QVERIFY(!normalMutex.tryLock(0));
259 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
260 normalMutex.unlock();
261 testsTurn.release();
262
263 // TEST 7 overflow: thread can acquire lock, timeout = 3000 (QTBUG-24795)
264 threadsTurn.acquire();
265 timer.start();
266 QVERIFY(normalMutex.tryLock(3000));
267 QVERIFY(timer.elapsed() < 3000 + systemTimersResolution);
268 normalMutex.unlock();
269 testsTurn.release();
270
271 threadsTurn.acquire();
272 }
273 };
274
275 Thread thread;
276 thread.start();
277
278 // TEST 1: thread can't acquire lock
279 testsTurn.acquire();
280 normalMutex.lock();
281 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
282 threadsTurn.release();
283
284 // TEST 2: thread can acquire lock
285 testsTurn.acquire();
286 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
287 normalMutex.unlock();
288 threadsTurn.release();
289
290 // TEST 3: thread can't acquire lock, timeout = waitTime
291 testsTurn.acquire();
292 normalMutex.lock();
293 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
294 threadsTurn.release();
295
296 // TEST 4: thread can acquire lock, timeout = waitTime
297 testsTurn.acquire();
298 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
299 normalMutex.unlock();
300 threadsTurn.release();
301
302 // TEST 5: thread can't acquire lock, timeout = 0
303 testsTurn.acquire();
304 normalMutex.lock();
305 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
306 threadsTurn.release();
307
308 // TEST 6: thread can acquire lock, timeout = 0
309 testsTurn.acquire();
310 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
311 normalMutex.unlock();
312 threadsTurn.release();
313
314 // TEST 7: thread can acquire lock, timeout = 3000 (QTBUG-24795)
315 testsTurn.acquire();
316 normalMutex.lock();
317 threadsTurn.release();
318 QThread::msleep(100);
319 normalMutex.unlock();
320
321 // wait for thread to finish
322 testsTurn.acquire();
323 threadsTurn.release();
324 thread.wait();
325}
326
327void tst_QMutex::try_lock_for_non_recursive() {
328#if !__has_include(<chrono>)
329 QSKIP("This test requires <chrono>");
330#else
331 class Thread : public QThread
332 {
333 public:
334 void run()
335 {
336 testsTurn.release();
337
338 // TEST 1: thread can't acquire lock
339 threadsTurn.acquire();
340 QVERIFY(!normalMutex.try_lock());
341 testsTurn.release();
342
343 // TEST 2: thread can acquire lock
344 threadsTurn.acquire();
345 QVERIFY(normalMutex.try_lock());
346 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
347 QVERIFY(!normalMutex.try_lock());
348 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
349 normalMutex.unlock();
350 testsTurn.release();
351
352 // TEST 3: thread can't acquire lock, timeout = waitTime
353 threadsTurn.acquire();
354 QElapsedTimer timer;
355 timer.start();
356 QVERIFY(!normalMutex.try_lock_for(waitTimeAsDuration));
357 QVERIFY(timer.elapsed() >= waitTime - systemTimersResolution);
358 testsTurn.release();
359
360 // TEST 4: thread can acquire lock, timeout = waitTime
361 threadsTurn.acquire();
362 timer.start();
363 QVERIFY(normalMutex.try_lock_for(waitTimeAsDuration));
364 QVERIFY(timer.elapsed() <= waitTime + systemTimersResolution);
365 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
366 timer.start();
367 // it's non-recursive, so the following lock needs to fail
368 QVERIFY(!normalMutex.try_lock_for(waitTimeAsDuration));
369 QVERIFY(timer.elapsed() >= waitTime - systemTimersResolution);
370 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
371 normalMutex.unlock();
372 testsTurn.release();
373
374 // TEST 5: thread can't acquire lock, timeout = 0
375 threadsTurn.acquire();
376 QVERIFY(!normalMutex.try_lock_for(std::chrono::milliseconds::zero()));
377 testsTurn.release();
378
379 // TEST 6: thread can acquire lock, timeout = 0
380 threadsTurn.acquire();
381 timer.start();
382 QVERIFY(normalMutex.try_lock_for(std::chrono::milliseconds::zero()));
383 QVERIFY(timer.elapsed() < waitTime + systemTimersResolution);
384 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
385 QVERIFY(!normalMutex.try_lock_for(std::chrono::milliseconds::zero()));
386 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
387 normalMutex.unlock();
388 testsTurn.release();
389
390 // TEST 7 overflow: thread can acquire lock, timeout = 3000 (QTBUG-24795)
391 threadsTurn.acquire();
392 timer.start();
393 QVERIFY(normalMutex.try_lock_for(std::chrono::milliseconds(3000)));
394 QVERIFY(timer.elapsed() < 3000 + systemTimersResolution);
395 normalMutex.unlock();
396 testsTurn.release();
397
398 threadsTurn.acquire();
399 }
400 };
401
402 Thread thread;
403 thread.start();
404
405 // TEST 1: thread can't acquire lock
406 testsTurn.acquire();
407 normalMutex.lock();
408 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
409 threadsTurn.release();
410
411 // TEST 2: thread can acquire lock
412 testsTurn.acquire();
413 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
414 normalMutex.unlock();
415 threadsTurn.release();
416
417 // TEST 3: thread can't acquire lock, timeout = waitTime
418 testsTurn.acquire();
419 normalMutex.lock();
420 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
421 threadsTurn.release();
422
423 // TEST 4: thread can acquire lock, timeout = waitTime
424 testsTurn.acquire();
425 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
426 normalMutex.unlock();
427 threadsTurn.release();
428
429 // TEST 5: thread can't acquire lock, timeout = 0
430 testsTurn.acquire();
431 normalMutex.lock();
432 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
433 threadsTurn.release();
434
435 // TEST 6: thread can acquire lock, timeout = 0
436 testsTurn.acquire();
437 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
438 normalMutex.unlock();
439 threadsTurn.release();
440
441 // TEST 7: thread can acquire lock, timeout = 3000 (QTBUG-24795)
442 testsTurn.acquire();
443 normalMutex.lock();
444 threadsTurn.release();
445 QThread::msleep(100);
446 normalMutex.unlock();
447
448 // wait for thread to finish
449 testsTurn.acquire();
450 threadsTurn.release();
451 thread.wait();
452#endif
453}
454
455void tst_QMutex::try_lock_until_non_recursive()
456{
457#if !__has_include(<chrono>)
458 QSKIP("This test requires <chrono>");
459#else
460 class Thread : public QThread
461 {
462 public:
463 void run()
464 {
465 const std::chrono::milliseconds systemTimersResolutionAsDuration(systemTimersResolution);
466 testsTurn.release();
467
468 // TEST 1: thread can't acquire lock
469 threadsTurn.acquire();
470 QVERIFY(!normalMutex.try_lock());
471 testsTurn.release();
472
473 // TEST 2: thread can acquire lock
474 threadsTurn.acquire();
475 QVERIFY(normalMutex.try_lock());
476 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
477 QVERIFY(!normalMutex.try_lock());
478 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
479 normalMutex.unlock();
480 testsTurn.release();
481
482 // TEST 3: thread can't acquire lock, timeout = waitTime
483 threadsTurn.acquire();
484 auto endTimePoint = std::chrono::steady_clock::now() + waitTimeAsDuration;
485 QVERIFY(!normalMutex.try_lock_until(endTimePoint));
486 QVERIFY(std::chrono::steady_clock::now() >= endTimePoint - systemTimersResolutionAsDuration);
487 testsTurn.release();
488
489 // TEST 4: thread can acquire lock, timeout = waitTime
490 threadsTurn.acquire();
491 endTimePoint = std::chrono::steady_clock::now() + waitTimeAsDuration;
492 QVERIFY(normalMutex.try_lock_until(endTimePoint));
493 QVERIFY(std::chrono::steady_clock::now() <= endTimePoint + systemTimersResolutionAsDuration);
494 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
495 endTimePoint = std::chrono::steady_clock::now() + waitTimeAsDuration;
496 // it's non-recursive, so the following lock needs to fail
497 QVERIFY(!normalMutex.try_lock_until(endTimePoint));
498 QVERIFY(std::chrono::steady_clock::now() >= endTimePoint - systemTimersResolutionAsDuration);
499 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
500 normalMutex.unlock();
501 testsTurn.release();
502
503 // TEST 5: thread can't acquire lock, timeout = 0
504 threadsTurn.acquire();
505 QVERIFY(!normalMutex.try_lock_until(std::chrono::steady_clock::now()));
506 testsTurn.release();
507
508 // TEST 6: thread can acquire lock, timeout = 0
509 threadsTurn.acquire();
510 endTimePoint = std::chrono::steady_clock::now() + waitTimeAsDuration;
511 QVERIFY(normalMutex.try_lock_until(std::chrono::steady_clock::now()));
512 QVERIFY(std::chrono::steady_clock::now() < endTimePoint + systemTimersResolutionAsDuration);
513 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
514 QVERIFY(!normalMutex.try_lock_until(std::chrono::steady_clock::now()));
515 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
516 normalMutex.unlock();
517 testsTurn.release();
518
519 // TEST 7 overflow: thread can acquire lock, timeout = 3000 (QTBUG-24795)
520 threadsTurn.acquire();
521 endTimePoint = std::chrono::steady_clock::now() + std::chrono::milliseconds(3000);
522 QVERIFY(normalMutex.try_lock_until(endTimePoint));
523 QVERIFY(std::chrono::steady_clock::now() < endTimePoint + systemTimersResolutionAsDuration);
524 normalMutex.unlock();
525 testsTurn.release();
526
527 threadsTurn.acquire();
528 }
529 };
530
531 Thread thread;
532 thread.start();
533
534 // TEST 1: thread can't acquire lock
535 testsTurn.acquire();
536 normalMutex.lock();
537 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
538 threadsTurn.release();
539
540 // TEST 2: thread can acquire lock
541 testsTurn.acquire();
542 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
543 normalMutex.unlock();
544 threadsTurn.release();
545
546 // TEST 3: thread can't acquire lock, timeout = waitTime
547 testsTurn.acquire();
548 normalMutex.lock();
549 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
550 threadsTurn.release();
551
552 // TEST 4: thread can acquire lock, timeout = waitTime
553 testsTurn.acquire();
554 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
555 normalMutex.unlock();
556 threadsTurn.release();
557
558 // TEST 5: thread can't acquire lock, timeout = 0
559 testsTurn.acquire();
560 normalMutex.lock();
561 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
562 threadsTurn.release();
563
564 // TEST 6: thread can acquire lock, timeout = 0
565 testsTurn.acquire();
566 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
567 normalMutex.unlock();
568 threadsTurn.release();
569
570 // TEST 7: thread can acquire lock, timeout = 3000 (QTBUG-24795)
571 testsTurn.acquire();
572 normalMutex.lock();
573 threadsTurn.release();
574 QThread::msleep(100);
575 normalMutex.unlock();
576
577 // wait for thread to finish
578 testsTurn.acquire();
579 threadsTurn.release();
580 thread.wait();
581#endif
582}
583
584void tst_QMutex::tryLock_recursive()
585{
586 class Thread : public QThread
587 {
588 public:
589 void run()
590 {
591 testsTurn.release();
592
593 threadsTurn.acquire();
594 QVERIFY(!recursiveMutex.tryLock());
595 testsTurn.release();
596
597 threadsTurn.acquire();
598 QVERIFY(recursiveMutex.tryLock());
599 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
600 QVERIFY(recursiveMutex.tryLock());
601 QVERIFY(lockCount.testAndSetRelaxed(1, 2));
602 QVERIFY(lockCount.testAndSetRelaxed(2, 1));
603 recursiveMutex.unlock();
604 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
605 recursiveMutex.unlock();
606 testsTurn.release();
607
608 threadsTurn.acquire();
609 QElapsedTimer timer;
610 timer.start();
611 QVERIFY(!recursiveMutex.tryLock(waitTime));
612 QVERIFY(timer.elapsed() >= waitTime - systemTimersResolution);
613 QVERIFY(!recursiveMutex.tryLock(0));
614 testsTurn.release();
615
616 threadsTurn.acquire();
617 timer.start();
618 QVERIFY(recursiveMutex.tryLock(waitTime));
619 QVERIFY(timer.elapsed() <= waitTime + systemTimersResolution);
620 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
621 QVERIFY(recursiveMutex.tryLock(waitTime));
622 QVERIFY(lockCount.testAndSetRelaxed(1, 2));
623 QVERIFY(lockCount.testAndSetRelaxed(2, 1));
624 recursiveMutex.unlock();
625 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
626 recursiveMutex.unlock();
627 testsTurn.release();
628
629 threadsTurn.acquire();
630 QVERIFY(!recursiveMutex.tryLock(0));
631 QVERIFY(!recursiveMutex.tryLock(0));
632 testsTurn.release();
633
634 threadsTurn.acquire();
635 timer.start();
636 QVERIFY(recursiveMutex.tryLock(0));
637 QVERIFY(timer.elapsed() < waitTime + systemTimersResolution);
638 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
639 QVERIFY(recursiveMutex.tryLock(0));
640 QVERIFY(lockCount.testAndSetRelaxed(1, 2));
641 QVERIFY(lockCount.testAndSetRelaxed(2, 1));
642 recursiveMutex.unlock();
643 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
644 recursiveMutex.unlock();
645 testsTurn.release();
646
647 threadsTurn.acquire();
648 }
649 };
650
651 Thread thread;
652 thread.start();
653
654 // thread can't acquire lock
655 testsTurn.acquire();
656 recursiveMutex.lock();
657 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
658 recursiveMutex.lock();
659 QVERIFY(lockCount.testAndSetRelaxed(1, 2));
660 threadsTurn.release();
661
662 // thread can acquire lock
663 testsTurn.acquire();
664 QVERIFY(lockCount.testAndSetRelaxed(2, 1));
665 recursiveMutex.unlock();
666 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
667 recursiveMutex.unlock();
668 threadsTurn.release();
669
670 // thread can't acquire lock, timeout = waitTime
671 testsTurn.acquire();
672 recursiveMutex.lock();
673 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
674 recursiveMutex.lock();
675 QVERIFY(lockCount.testAndSetRelaxed(1, 2));
676 threadsTurn.release();
677
678 // thread can acquire lock, timeout = waitTime
679 testsTurn.acquire();
680 QVERIFY(lockCount.testAndSetRelaxed(2, 1));
681 recursiveMutex.unlock();
682 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
683 recursiveMutex.unlock();
684 threadsTurn.release();
685
686 // thread can't acquire lock, timeout = 0
687 testsTurn.acquire();
688 recursiveMutex.lock();
689 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
690 recursiveMutex.lock();
691 QVERIFY(lockCount.testAndSetRelaxed(1, 2));
692 threadsTurn.release();
693
694 // thread can acquire lock, timeout = 0
695 testsTurn.acquire();
696 QVERIFY(lockCount.testAndSetRelaxed(2, 1));
697 recursiveMutex.unlock();
698 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
699 recursiveMutex.unlock();
700 threadsTurn.release();
701
702 // stop thread
703 testsTurn.acquire();
704 threadsTurn.release();
705 thread.wait();
706}
707
708void tst_QMutex::try_lock_for_recursive()
709{
710#if !__has_include(<chrono>)
711 QSKIP("This test requires <chrono>");
712#else
713 class Thread : public QThread
714 {
715 public:
716 void run()
717 {
718 const std::chrono::milliseconds systemTimersResolutionAsDuration(systemTimersResolution);
719 testsTurn.release();
720
721 threadsTurn.acquire();
722 QVERIFY(!recursiveMutex.try_lock());
723 testsTurn.release();
724
725 threadsTurn.acquire();
726 QVERIFY(recursiveMutex.try_lock());
727 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
728 QVERIFY(recursiveMutex.try_lock());
729 QVERIFY(lockCount.testAndSetRelaxed(1, 2));
730 QVERIFY(lockCount.testAndSetRelaxed(2, 1));
731 recursiveMutex.unlock();
732 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
733 recursiveMutex.unlock();
734 testsTurn.release();
735
736 threadsTurn.acquire();
737 QElapsedTimer timer;
738 timer.start();
739 QVERIFY(!recursiveMutex.try_lock_for(waitTimeAsDuration));
740 QVERIFY(timer.elapsed() >= waitTime - systemTimersResolution);
741 QVERIFY(!recursiveMutex.try_lock_for(std::chrono::milliseconds::zero()));
742 testsTurn.release();
743
744 threadsTurn.acquire();
745 timer.start();
746 QVERIFY(recursiveMutex.try_lock_for(waitTimeAsDuration));
747 QVERIFY(timer.elapsed() <= waitTime + systemTimersResolution);
748 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
749 QVERIFY(recursiveMutex.try_lock_for(waitTimeAsDuration));
750 QVERIFY(lockCount.testAndSetRelaxed(1, 2));
751 QVERIFY(lockCount.testAndSetRelaxed(2, 1));
752 recursiveMutex.unlock();
753 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
754 recursiveMutex.unlock();
755 testsTurn.release();
756
757 threadsTurn.acquire();
758 QVERIFY(!recursiveMutex.try_lock_for(std::chrono::milliseconds::zero()));
759 QVERIFY(!recursiveMutex.try_lock_for(std::chrono::milliseconds::zero()));
760 testsTurn.release();
761
762 threadsTurn.acquire();
763 timer.start();
764 QVERIFY(recursiveMutex.try_lock_for(std::chrono::milliseconds::zero()));
765 QVERIFY(timer.elapsed() < waitTime + systemTimersResolution);
766 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
767 QVERIFY(recursiveMutex.try_lock_for(std::chrono::milliseconds::zero()));
768 QVERIFY(lockCount.testAndSetRelaxed(1, 2));
769 QVERIFY(lockCount.testAndSetRelaxed(2, 1));
770 recursiveMutex.unlock();
771 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
772 recursiveMutex.unlock();
773 testsTurn.release();
774
775 threadsTurn.acquire();
776 }
777 };
778
779 Thread thread;
780 thread.start();
781
782 // thread can't acquire lock
783 testsTurn.acquire();
784 recursiveMutex.lock();
785 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
786 recursiveMutex.lock();
787 QVERIFY(lockCount.testAndSetRelaxed(1, 2));
788 threadsTurn.release();
789
790 // thread can acquire lock
791 testsTurn.acquire();
792 QVERIFY(lockCount.testAndSetRelaxed(2, 1));
793 recursiveMutex.unlock();
794 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
795 recursiveMutex.unlock();
796 threadsTurn.release();
797
798 // thread can't acquire lock, timeout = waitTime
799 testsTurn.acquire();
800 recursiveMutex.lock();
801 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
802 recursiveMutex.lock();
803 QVERIFY(lockCount.testAndSetRelaxed(1, 2));
804 threadsTurn.release();
805
806 // thread can acquire lock, timeout = waitTime
807 testsTurn.acquire();
808 QVERIFY(lockCount.testAndSetRelaxed(2, 1));
809 recursiveMutex.unlock();
810 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
811 recursiveMutex.unlock();
812 threadsTurn.release();
813
814 // thread can't acquire lock, timeout = 0
815 testsTurn.acquire();
816 recursiveMutex.lock();
817 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
818 recursiveMutex.lock();
819 QVERIFY(lockCount.testAndSetRelaxed(1, 2));
820 threadsTurn.release();
821
822 // thread can acquire lock, timeout = 0
823 testsTurn.acquire();
824 QVERIFY(lockCount.testAndSetRelaxed(2, 1));
825 recursiveMutex.unlock();
826 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
827 recursiveMutex.unlock();
828 threadsTurn.release();
829
830 // stop thread
831 testsTurn.acquire();
832 threadsTurn.release();
833 thread.wait();
834#endif
835}
836
837void tst_QMutex::try_lock_until_recursive()
838{
839#if !__has_include(<chrono>)
840 QSKIP("This test requires <chrono>");
841#else
842 class Thread : public QThread
843 {
844 public:
845 void run()
846 {
847 const std::chrono::milliseconds systemTimersResolutionAsDuration(systemTimersResolution);
848 testsTurn.release();
849
850 threadsTurn.acquire();
851 QVERIFY(!recursiveMutex.try_lock());
852 testsTurn.release();
853
854 threadsTurn.acquire();
855 QVERIFY(recursiveMutex.try_lock());
856 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
857 QVERIFY(recursiveMutex.try_lock());
858 QVERIFY(lockCount.testAndSetRelaxed(1, 2));
859 QVERIFY(lockCount.testAndSetRelaxed(2, 1));
860 recursiveMutex.unlock();
861 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
862 recursiveMutex.unlock();
863 testsTurn.release();
864
865 threadsTurn.acquire();
866 auto endTimePoint = std::chrono::steady_clock::now() + waitTimeAsDuration;
867 QVERIFY(!recursiveMutex.try_lock_until(endTimePoint));
868 QVERIFY(std::chrono::steady_clock::now() >= endTimePoint - systemTimersResolutionAsDuration);
869 QVERIFY(!recursiveMutex.try_lock());
870 testsTurn.release();
871
872 threadsTurn.acquire();
873 endTimePoint = std::chrono::steady_clock::now() + waitTimeAsDuration;
874 QVERIFY(recursiveMutex.try_lock_until(endTimePoint));
875 QVERIFY(std::chrono::steady_clock::now() <= endTimePoint + systemTimersResolutionAsDuration);
876 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
877 endTimePoint = std::chrono::steady_clock::now() + waitTimeAsDuration;
878 QVERIFY(recursiveMutex.try_lock_until(endTimePoint));
879 QVERIFY(lockCount.testAndSetRelaxed(1, 2));
880 QVERIFY(lockCount.testAndSetRelaxed(2, 1));
881 recursiveMutex.unlock();
882 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
883 recursiveMutex.unlock();
884 testsTurn.release();
885
886 threadsTurn.acquire();
887 QVERIFY(!recursiveMutex.try_lock_until(std::chrono::steady_clock::now()));
888 QVERIFY(!recursiveMutex.try_lock_until(std::chrono::steady_clock::now()));
889 testsTurn.release();
890
891 threadsTurn.acquire();
892 endTimePoint = std::chrono::steady_clock::now() + waitTimeAsDuration;
893 QVERIFY(recursiveMutex.try_lock_until(std::chrono::steady_clock::now()));
894 QVERIFY(std::chrono::steady_clock::now() <= endTimePoint + systemTimersResolutionAsDuration);
895 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
896 QVERIFY(recursiveMutex.try_lock_until(std::chrono::steady_clock::now()));
897 QVERIFY(lockCount.testAndSetRelaxed(1, 2));
898 QVERIFY(lockCount.testAndSetRelaxed(2, 1));
899 recursiveMutex.unlock();
900 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
901 recursiveMutex.unlock();
902 testsTurn.release();
903
904 threadsTurn.acquire();
905 }
906 };
907
908 Thread thread;
909 thread.start();
910
911 // thread can't acquire lock
912 testsTurn.acquire();
913 recursiveMutex.lock();
914 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
915 recursiveMutex.lock();
916 QVERIFY(lockCount.testAndSetRelaxed(1, 2));
917 threadsTurn.release();
918
919 // thread can acquire lock
920 testsTurn.acquire();
921 QVERIFY(lockCount.testAndSetRelaxed(2, 1));
922 recursiveMutex.unlock();
923 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
924 recursiveMutex.unlock();
925 threadsTurn.release();
926
927 // thread can't acquire lock, timeout = waitTime
928 testsTurn.acquire();
929 recursiveMutex.lock();
930 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
931 recursiveMutex.lock();
932 QVERIFY(lockCount.testAndSetRelaxed(1, 2));
933 threadsTurn.release();
934
935 // thread can acquire lock, timeout = waitTime
936 testsTurn.acquire();
937 QVERIFY(lockCount.testAndSetRelaxed(2, 1));
938 recursiveMutex.unlock();
939 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
940 recursiveMutex.unlock();
941 threadsTurn.release();
942
943 // thread can't acquire lock, timeout = 0
944 testsTurn.acquire();
945 recursiveMutex.lock();
946 QVERIFY(lockCount.testAndSetRelaxed(0, 1));
947 recursiveMutex.lock();
948 QVERIFY(lockCount.testAndSetRelaxed(1, 2));
949 threadsTurn.release();
950
951 // thread can acquire lock, timeout = 0
952 testsTurn.acquire();
953 QVERIFY(lockCount.testAndSetRelaxed(2, 1));
954 recursiveMutex.unlock();
955 QVERIFY(lockCount.testAndSetRelaxed(1, 0));
956 recursiveMutex.unlock();
957 threadsTurn.release();
958
959 // stop thread
960 testsTurn.acquire();
961 threadsTurn.release();
962 thread.wait();
963#endif
964}
965
966class mutex_Thread : public QThread
967{
968public:
969 QMutex mutex;
970 QWaitCondition cond;
971
972 QMutex &test_mutex;
973
974 inline mutex_Thread(QMutex &m) : test_mutex(m) { }
975
976 void run()
977 {
978 test_mutex.lock();
979
980 mutex.lock();
981 for (int i = 0; i < iterations; ++i) {
982 cond.wakeOne();
983 cond.wait(lockedMutex: &mutex);
984 }
985 mutex.unlock();
986
987 test_mutex.unlock();
988 }
989};
990
991class rmutex_Thread : public QThread
992{
993public:
994 QMutex mutex;
995 QWaitCondition cond;
996
997 QRecursiveMutex &test_mutex;
998
999 inline rmutex_Thread(QRecursiveMutex &m) : test_mutex(m) { }
1000
1001 void run()
1002 {
1003 test_mutex.lock();
1004 test_mutex.lock();
1005 test_mutex.lock();
1006 test_mutex.lock();
1007
1008 mutex.lock();
1009 for (int i = 0; i < iterations; ++i) {
1010 cond.wakeOne();
1011 cond.wait(lockedMutex: &mutex);
1012 }
1013 mutex.unlock();
1014
1015 test_mutex.unlock();
1016 test_mutex.unlock();
1017 test_mutex.unlock();
1018 test_mutex.unlock();
1019 }
1020};
1021
1022void tst_QMutex::lock_unlock_locked_tryLock()
1023{
1024 // normal mutex
1025 QMutex mutex;
1026 mutex_Thread thread(mutex);
1027
1028 QRecursiveMutex rmutex;
1029 rmutex_Thread rthread(rmutex);
1030
1031 for (int i = 0; i < iterations; ++i) {
1032 // normal mutex
1033 QVERIFY(mutex.tryLock());
1034 mutex.unlock();
1035
1036 thread.mutex.lock();
1037 thread.start();
1038
1039 for (int j = 0; j < iterations; ++j) {
1040 QVERIFY(thread.cond.wait(&thread.mutex, 10000));
1041 QVERIFY(!mutex.tryLock());
1042
1043 thread.cond.wakeOne();
1044 }
1045
1046 thread.mutex.unlock();
1047
1048 QVERIFY(thread.wait(10000));
1049 QVERIFY(mutex.tryLock());
1050
1051 mutex.unlock();
1052
1053 // recursive mutex
1054 QVERIFY(rmutex.tryLock());
1055 QVERIFY(rmutex.tryLock());
1056 QVERIFY(rmutex.tryLock());
1057 QVERIFY(rmutex.tryLock());
1058
1059 rmutex.unlock();
1060 rmutex.unlock();
1061 rmutex.unlock();
1062 rmutex.unlock();
1063
1064 rthread.mutex.lock();
1065 rthread.start();
1066
1067 for (int k = 0; k < iterations; ++k) {
1068 QVERIFY(rthread.cond.wait(&rthread.mutex, 10000));
1069 QVERIFY(!rmutex.tryLock());
1070
1071 rthread.cond.wakeOne();
1072 }
1073
1074 rthread.mutex.unlock();
1075
1076 QVERIFY(rthread.wait(10000));
1077 QVERIFY(rmutex.tryLock());
1078 QVERIFY(rmutex.tryLock());
1079 QVERIFY(rmutex.tryLock());
1080 QVERIFY(rmutex.tryLock());
1081
1082 rmutex.unlock();
1083 rmutex.unlock();
1084 rmutex.unlock();
1085 rmutex.unlock();
1086 }
1087}
1088
1089enum { one_minute = 6 * 1000, //not really one minute, but else it is too long.
1090 threadCount = 10 };
1091
1092class StressTestThread : public QThread
1093{
1094 QElapsedTimer t;
1095public:
1096 static QBasicAtomicInt lockCount;
1097 static QBasicAtomicInt sentinel;
1098 static QMutex mutex;
1099 static int errorCount;
1100 void start()
1101 {
1102 t.start();
1103 QThread::start();
1104 }
1105 void run()
1106 {
1107 while (t.elapsed() < one_minute) {
1108 mutex.lock();
1109 if (sentinel.ref()) ++errorCount;
1110 if (!sentinel.deref()) ++errorCount;
1111 lockCount.ref();
1112 mutex.unlock();
1113 if (mutex.tryLock()) {
1114 if (sentinel.ref()) ++errorCount;
1115 if (!sentinel.deref()) ++errorCount;
1116 lockCount.ref();
1117 mutex.unlock();
1118 }
1119 }
1120 }
1121};
1122QMutex StressTestThread::mutex;
1123QBasicAtomicInt StressTestThread::lockCount = Q_BASIC_ATOMIC_INITIALIZER(0);
1124QBasicAtomicInt StressTestThread::sentinel = Q_BASIC_ATOMIC_INITIALIZER(-1);
1125int StressTestThread::errorCount = 0;
1126
1127void tst_QMutex::stressTest()
1128{
1129 StressTestThread threads[threadCount];
1130 for (int i = 0; i < threadCount; ++i)
1131 threads[i].start();
1132 QVERIFY(threads[0].wait(one_minute + 10000));
1133 for (int i = 1; i < threadCount; ++i)
1134 QVERIFY(threads[i].wait(10000));
1135 QCOMPARE(StressTestThread::errorCount, 0);
1136 qDebug(msg: "locked %d times", int(StressTestThread::lockCount.loadRelaxed()));
1137}
1138
1139class TryLockRaceThread : public QThread
1140{
1141public:
1142 static QMutex mutex;
1143
1144 void run()
1145 {
1146 QElapsedTimer t;
1147 t.start();
1148 do {
1149 if (mutex.tryLock())
1150 mutex.unlock();
1151 } while (t.elapsed() < one_minute/2);
1152 }
1153};
1154QMutex TryLockRaceThread::mutex;
1155
1156void tst_QMutex::tryLockRace()
1157{
1158 // mutex not in use, should be able to lock it
1159 QVERIFY(TryLockRaceThread::mutex.tryLock());
1160 TryLockRaceThread::mutex.unlock();
1161
1162 // try to break tryLock
1163 TryLockRaceThread thread[threadCount];
1164 for (int i = 0; i < threadCount; ++i)
1165 thread[i].start();
1166 for (int i = 0; i < threadCount; ++i)
1167 QVERIFY(thread[i].wait());
1168
1169 // mutex not in use, should be able to lock it
1170 QVERIFY(TryLockRaceThread::mutex.tryLock());
1171 TryLockRaceThread::mutex.unlock();
1172}
1173
1174// The following is a regression test for QTBUG-16115, where QMutex could
1175// deadlock after calling tryLock repeatedly.
1176
1177// Variable that will be protected by the mutex. Volatile so that the
1178// the optimiser doesn't mess with it based on the increment-then-decrement
1179// usage pattern.
1180static volatile int tryLockDeadlockCounter;
1181// Counter for how many times the protected variable has an incorrect value.
1182static int tryLockDeadlockFailureCount = 0;
1183
1184void tst_QMutex::tryLockDeadlock()
1185{
1186 //Used to deadlock on unix
1187 struct TrylockThread : QThread {
1188 TrylockThread(QMutex &mut) : mut(mut) {}
1189 QMutex &mut;
1190 void run() {
1191 for (int i = 0; i < 100000; ++i) {
1192 if (mut.tryLock(timeout: 0)) {
1193 if ((++tryLockDeadlockCounter) != 1)
1194 ++tryLockDeadlockFailureCount;
1195 if ((--tryLockDeadlockCounter) != 0)
1196 ++tryLockDeadlockFailureCount;
1197 mut.unlock();
1198 }
1199 }
1200 }
1201 };
1202 QMutex mut;
1203 TrylockThread t1(mut);
1204 TrylockThread t2(mut);
1205 TrylockThread t3(mut);
1206 t1.start();
1207 t2.start();
1208 t3.start();
1209
1210 for (int i = 0; i < 100000; ++i) {
1211 mut.lock();
1212 if ((++tryLockDeadlockCounter) != 1)
1213 ++tryLockDeadlockFailureCount;
1214 if ((--tryLockDeadlockCounter) != 0)
1215 ++tryLockDeadlockFailureCount;
1216 mut.unlock();
1217 }
1218 t1.wait();
1219 t2.wait();
1220 t3.wait();
1221 QCOMPARE(tryLockDeadlockFailureCount, 0);
1222}
1223
1224void tst_QMutex::tryLockNegative_data()
1225{
1226 QTest::addColumn<int>(name: "timeout");
1227 QTest::newRow(dataTag: "-1") << -1;
1228 QTest::newRow(dataTag: "-2") << -2;
1229 QTest::newRow(dataTag: "INT_MIN/2") << INT_MIN/2;
1230 QTest::newRow(dataTag: "INT_MIN") << INT_MIN;
1231}
1232
1233void tst_QMutex::tryLockNegative()
1234{
1235 // the documentation says tryLock() with a negative number is the same as lock()
1236 struct TrylockThread : QThread {
1237 TrylockThread(QMutex &mut, int timeout)
1238 : mut(mut), timeout(timeout), tryLockResult(-1)
1239 {}
1240 QMutex &mut;
1241 int timeout;
1242 int tryLockResult;
1243 void run() {
1244 tryLockResult = mut.tryLock(timeout);
1245 mut.unlock();
1246 }
1247 };
1248
1249 QFETCH(int, timeout);
1250
1251 QMutex mutex;
1252 TrylockThread thr(mutex, timeout);
1253 mutex.lock();
1254 thr.start();
1255
1256 // the thread should have stopped in tryLock(), waiting for us to unlock
1257 // the mutex. The following test can be falsely positive due to timing:
1258 // tryLock may still fail but hasn't failed yet. But it certainly cannot be
1259 // a false negative: if wait() returns true, tryLock failed.
1260 QVERIFY(!thr.wait(200));
1261
1262 // after we unlock the mutex, the thread should succeed in locking, then
1263 // unlock and exit. Do this before more tests to avoid deadlocking due to
1264 // ~QThread waiting forever on a thread that won't exit.
1265 mutex.unlock();
1266
1267 QVERIFY(thr.wait());
1268 QCOMPARE(thr.tryLockResult, 1);
1269}
1270
1271
1272class MoreStressTestThread : public QThread
1273{
1274 QElapsedTimer t;
1275public:
1276 static QAtomicInt lockCount;
1277 static QAtomicInt sentinel[threadCount];
1278 static QMutex mutex[threadCount];
1279 static QAtomicInt errorCount;
1280 void start()
1281 {
1282 t.start();
1283 QThread::start();
1284 }
1285 void run()
1286 {
1287 quint64 i = 0;
1288 while (t.elapsed() < one_minute) {
1289 i++;
1290 uint nb = (i * 9 + lockCount.loadRelaxed() * 13) % threadCount;
1291 QMutexLocker locker(&mutex[nb]);
1292 if (sentinel[nb].loadRelaxed()) errorCount.ref();
1293 if (sentinel[nb].fetchAndAddRelaxed(valueToAdd: 5)) errorCount.ref();
1294 if (!sentinel[nb].testAndSetRelaxed(expectedValue: 5, newValue: 0)) errorCount.ref();
1295 if (sentinel[nb].loadRelaxed()) errorCount.ref();
1296 lockCount.ref();
1297 nb = (nb * 17 + i * 5 + lockCount.loadRelaxed() * 3) % threadCount;
1298 if (mutex[nb].tryLock()) {
1299 if (sentinel[nb].loadRelaxed()) errorCount.ref();
1300 if (sentinel[nb].fetchAndAddRelaxed(valueToAdd: 16)) errorCount.ref();
1301 if (!sentinel[nb].testAndSetRelaxed(expectedValue: 16, newValue: 0)) errorCount.ref();
1302 if (sentinel[nb].loadRelaxed()) errorCount.ref();
1303 lockCount.ref();
1304 mutex[nb].unlock();
1305 }
1306 nb = (nb * 15 + i * 47 + lockCount.loadRelaxed() * 31) % threadCount;
1307 if (mutex[nb].tryLock(timeout: 2)) {
1308 if (sentinel[nb].loadRelaxed()) errorCount.ref();
1309 if (sentinel[nb].fetchAndAddRelaxed(valueToAdd: 53)) errorCount.ref();
1310 if (!sentinel[nb].testAndSetRelaxed(expectedValue: 53, newValue: 0)) errorCount.ref();
1311 if (sentinel[nb].loadRelaxed()) errorCount.ref();
1312 lockCount.ref();
1313 mutex[nb].unlock();
1314 }
1315 }
1316 }
1317};
1318QMutex MoreStressTestThread::mutex[threadCount];
1319QAtomicInt MoreStressTestThread::lockCount;
1320QAtomicInt MoreStressTestThread::sentinel[threadCount];
1321QAtomicInt MoreStressTestThread::errorCount = 0;
1322
1323void tst_QMutex::moreStress()
1324{
1325 MoreStressTestThread threads[threadCount];
1326 for (int i = 0; i < threadCount; ++i)
1327 threads[i].start();
1328 QVERIFY(threads[0].wait(one_minute + 10000));
1329 for (int i = 1; i < threadCount; ++i)
1330 QVERIFY(threads[i].wait(10000));
1331 qDebug(msg: "locked %d times", MoreStressTestThread::lockCount.loadRelaxed());
1332 QCOMPARE(MoreStressTestThread::errorCount.loadRelaxed(), 0);
1333}
1334
1335
1336QTEST_MAIN(tst_QMutex)
1337#include "tst_qmutex.moc"
1338

source code of qtbase/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp