summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/corelib/thread/qmutex/tst_qmutex.cpp')
-rw-r--r--tests/auto/corelib/thread/qmutex/tst_qmutex.cpp1065
1 files changed, 820 insertions, 245 deletions
diff --git a/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp b/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp
index 594bae674c..b24ecfcd43 100644
--- a/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp
+++ b/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp
@@ -31,16 +31,27 @@
#include <qatomic.h>
#include <qcoreapplication.h>
-#include <qdatetime.h>
+#include <qelapsedtimer.h>
#include <qmutex.h>
#include <qthread.h>
#include <qwaitcondition.h>
+#ifdef Q_OS_WIN
+#include <private/qsystemlibrary_p.h>
+#include <cmath>
+#endif
+
class tst_QMutex : public QObject
{
Q_OBJECT
private slots:
- void tryLock();
+ void initTestCase();
+ void tryLock_non_recursive();
+ void try_lock_for_non_recursive();
+ void try_lock_until_non_recursive();
+ void tryLock_recursive();
+ void try_lock_for_recursive();
+ void try_lock_until_recursive();
void lock_unlock_locked_tryLock();
void stressTest();
void tryLockRace();
@@ -48,6 +59,8 @@ private slots:
void tryLockNegative_data();
void tryLockNegative();
void moreStress();
+private:
+ void initializeSystemTimersResolution();
};
static const int iterations = 100;
@@ -58,257 +71,819 @@ QSemaphore testsTurn;
QSemaphore threadsTurn;
enum { waitTime = 100 };
+uint systemTimersResolution = 1;
+
+#if QT_HAS_INCLUDE(<chrono>)
+static Q_CONSTEXPR std::chrono::milliseconds waitTimeAsDuration(waitTime);
+#endif
+
+/*
+ Depending on the OS, tryWaits may return early than expected because of the
+ resolution of the underlying timer is too coarse. E.g.: on Windows
+ WaitForSingleObjectEx does *not* use high resolution multimedia timers, and
+ it's actually very coarse, about 16msec by default.
+
+ Try to find out the timer resolution in here, so that the tryLock tests can
+ actually take into account early wakes.
+*/
+void tst_QMutex::initializeSystemTimersResolution()
+{
+#ifdef Q_OS_WIN
+ // according to MSDN, Windows can default up to this
+ systemTimersResolution = 16;
+
+ // private API. There's no way on Windows to otherwise know the
+ // actual resolution of the application's timers (you can only set it)
+ // cf. https://stackoverflow.com/questions/7685762/windows-7-timing-functions-how-to-use-getsystemtimeadjustment-correctly/11743614#11743614
+ typedef NTSTATUS (NTAPI *NtQueryTimerResolutionType)(OUT PULONG MinimumResolution,
+ OUT PULONG MaximumResolution,
+ OUT PULONG ActualResolution);
+
+ const NtQueryTimerResolutionType NtQueryTimerResolutionPtr =
+ reinterpret_cast<NtQueryTimerResolutionType>(QSystemLibrary::resolve(QStringLiteral("ntdll"), "NtQueryTimerResolution"));
+
+ if (!NtQueryTimerResolutionPtr)
+ return;
+
+ ULONG minimumResolution;
+ ULONG maximumResolution;
+ ULONG actualResolution;
+
+ if (!NtQueryTimerResolutionPtr(&minimumResolution, &maximumResolution, &actualResolution)) {
+ // the result is in 100ns units => adjust to msec
+ const double actualResolutionMsec = actualResolution / 10000.0;
+ systemTimersResolution = static_cast<int>(std::ceil(actualResolutionMsec));
+ }
+#endif // Q_OS_WIN
+}
+
+void tst_QMutex::initTestCase()
+{
+ initializeSystemTimersResolution();
+}
-void tst_QMutex::tryLock()
+void tst_QMutex::tryLock_non_recursive()
{
- // test non-recursive mutex
+ class Thread : public QThread
{
- class Thread : public QThread
+ public:
+ void run()
{
- public:
- void run()
- {
- testsTurn.release();
-
- // TEST 1: thread can't acquire lock
- threadsTurn.acquire();
- QVERIFY(!normalMutex.tryLock());
- testsTurn.release();
-
- // TEST 2: thread can acquire lock
- threadsTurn.acquire();
- QVERIFY(normalMutex.tryLock());
- QVERIFY(lockCount.testAndSetRelaxed(0, 1));
- QVERIFY(!normalMutex.tryLock());
- QVERIFY(lockCount.testAndSetRelaxed(1, 0));
- normalMutex.unlock();
- testsTurn.release();
-
- // TEST 3: thread can't acquire lock, timeout = waitTime
- threadsTurn.acquire();
- QTime timer;
- timer.start();
- QVERIFY(!normalMutex.tryLock(waitTime));
- QVERIFY(timer.elapsed() >= waitTime);
- testsTurn.release();
-
- // TEST 4: thread can acquire lock, timeout = waitTime
- threadsTurn.acquire();
- timer.start();
- QVERIFY(normalMutex.tryLock(waitTime));
- QVERIFY(timer.elapsed() <= waitTime);
- QVERIFY(lockCount.testAndSetRelaxed(0, 1));
- timer.start();
- // it's non-recursive, so the following lock needs to fail
- QVERIFY(!normalMutex.tryLock(waitTime));
- QVERIFY(timer.elapsed() >= waitTime);
- QVERIFY(lockCount.testAndSetRelaxed(1, 0));
- normalMutex.unlock();
- testsTurn.release();
-
- // TEST 5: thread can't acquire lock, timeout = 0
- threadsTurn.acquire();
- QVERIFY(!normalMutex.tryLock(0));
- testsTurn.release();
-
- // TEST 6: thread can acquire lock, timeout = 0
- threadsTurn.acquire();
- timer.start();
- QVERIFY(normalMutex.tryLock(0));
- QVERIFY(timer.elapsed() < waitTime);
- QVERIFY(lockCount.testAndSetRelaxed(0, 1));
- QVERIFY(!normalMutex.tryLock(0));
- QVERIFY(lockCount.testAndSetRelaxed(1, 0));
- normalMutex.unlock();
- testsTurn.release();
-
- // TEST 7 overflow: thread can acquire lock, timeout = 3000 (QTBUG-24795)
- threadsTurn.acquire();
- timer.start();
- QVERIFY(normalMutex.tryLock(3000));
- QVERIFY(timer.elapsed() < 3000);
- normalMutex.unlock();
- testsTurn.release();
-
- threadsTurn.acquire();
- }
- };
+ testsTurn.release();
+
+ // TEST 1: thread can't acquire lock
+ threadsTurn.acquire();
+ QVERIFY(!normalMutex.tryLock());
+ testsTurn.release();
+
+ // TEST 2: thread can acquire lock
+ threadsTurn.acquire();
+ QVERIFY(normalMutex.tryLock());
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ QVERIFY(!normalMutex.tryLock());
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ normalMutex.unlock();
+ testsTurn.release();
+
+ // TEST 3: thread can't acquire lock, timeout = waitTime
+ threadsTurn.acquire();
+ QElapsedTimer timer;
+ timer.start();
+ QVERIFY(!normalMutex.tryLock(waitTime));
+ QVERIFY(timer.elapsed() >= waitTime - systemTimersResolution);
+ testsTurn.release();
+
+ // TEST 4: thread can acquire lock, timeout = waitTime
+ threadsTurn.acquire();
+ timer.start();
+ QVERIFY(normalMutex.tryLock(waitTime));
+ QVERIFY(timer.elapsed() <= waitTime + systemTimersResolution);
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ timer.start();
+ // it's non-recursive, so the following lock needs to fail
+ QVERIFY(!normalMutex.tryLock(waitTime));
+ QVERIFY(timer.elapsed() >= waitTime - systemTimersResolution);
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ normalMutex.unlock();
+ testsTurn.release();
+
+ // TEST 5: thread can't acquire lock, timeout = 0
+ threadsTurn.acquire();
+ QVERIFY(!normalMutex.tryLock(0));
+ testsTurn.release();
+
+ // TEST 6: thread can acquire lock, timeout = 0
+ threadsTurn.acquire();
+ timer.start();
+ QVERIFY(normalMutex.tryLock(0));
+ QVERIFY(timer.elapsed() < waitTime + systemTimersResolution);
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ QVERIFY(!normalMutex.tryLock(0));
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ normalMutex.unlock();
+ testsTurn.release();
+
+ // TEST 7 overflow: thread can acquire lock, timeout = 3000 (QTBUG-24795)
+ threadsTurn.acquire();
+ timer.start();
+ QVERIFY(normalMutex.tryLock(3000));
+ QVERIFY(timer.elapsed() < 3000 + systemTimersResolution);
+ normalMutex.unlock();
+ testsTurn.release();
+
+ threadsTurn.acquire();
+ }
+ };
- Thread thread;
- thread.start();
+ Thread thread;
+ thread.start();
+
+ // TEST 1: thread can't acquire lock
+ testsTurn.acquire();
+ normalMutex.lock();
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ threadsTurn.release();
+
+ // TEST 2: thread can acquire lock
+ testsTurn.acquire();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ normalMutex.unlock();
+ threadsTurn.release();
+
+ // TEST 3: thread can't acquire lock, timeout = waitTime
+ testsTurn.acquire();
+ normalMutex.lock();
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ threadsTurn.release();
+
+ // TEST 4: thread can acquire lock, timeout = waitTime
+ testsTurn.acquire();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ normalMutex.unlock();
+ threadsTurn.release();
+
+ // TEST 5: thread can't acquire lock, timeout = 0
+ testsTurn.acquire();
+ normalMutex.lock();
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ threadsTurn.release();
+
+ // TEST 6: thread can acquire lock, timeout = 0
+ testsTurn.acquire();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ normalMutex.unlock();
+ threadsTurn.release();
+
+ // TEST 7: thread can acquire lock, timeout = 3000 (QTBUG-24795)
+ testsTurn.acquire();
+ normalMutex.lock();
+ threadsTurn.release();
+ QThread::msleep(100);
+ normalMutex.unlock();
+
+ // wait for thread to finish
+ testsTurn.acquire();
+ threadsTurn.release();
+ thread.wait();
+}
- // TEST 1: thread can't acquire lock
- testsTurn.acquire();
- normalMutex.lock();
- QVERIFY(lockCount.testAndSetRelaxed(0, 1));
- threadsTurn.release();
-
- // TEST 2: thread can acquire lock
- testsTurn.acquire();
- QVERIFY(lockCount.testAndSetRelaxed(1, 0));
- normalMutex.unlock();
- threadsTurn.release();
-
- // TEST 3: thread can't acquire lock, timeout = waitTime
- testsTurn.acquire();
- normalMutex.lock();
- QVERIFY(lockCount.testAndSetRelaxed(0, 1));
- threadsTurn.release();
-
- // TEST 4: thread can acquire lock, timeout = waitTime
- testsTurn.acquire();
- QVERIFY(lockCount.testAndSetRelaxed(1, 0));
- normalMutex.unlock();
- threadsTurn.release();
-
- // TEST 5: thread can't acquire lock, timeout = 0
- testsTurn.acquire();
- normalMutex.lock();
- QVERIFY(lockCount.testAndSetRelaxed(0, 1));
- threadsTurn.release();
-
- // TEST 6: thread can acquire lock, timeout = 0
- testsTurn.acquire();
- QVERIFY(lockCount.testAndSetRelaxed(1, 0));
- normalMutex.unlock();
- threadsTurn.release();
-
- // TEST 7: thread can acquire lock, timeout = 3000 (QTBUG-24795)
- testsTurn.acquire();
- normalMutex.lock();
- threadsTurn.release();
- QThread::msleep(100);
- normalMutex.unlock();
-
- // wait for thread to finish
- testsTurn.acquire();
- threadsTurn.release();
- thread.wait();
- }
+void tst_QMutex::try_lock_for_non_recursive() {
+#if !QT_HAS_INCLUDE(<chrono>)
+ QSKIP("This test requires <chrono>");
+#else
+ class Thread : public QThread
+ {
+ public:
+ void run()
+ {
+ testsTurn.release();
+
+ // TEST 1: thread can't acquire lock
+ threadsTurn.acquire();
+ QVERIFY(!normalMutex.try_lock());
+ testsTurn.release();
+
+ // TEST 2: thread can acquire lock
+ threadsTurn.acquire();
+ QVERIFY(normalMutex.try_lock());
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ QVERIFY(!normalMutex.try_lock());
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ normalMutex.unlock();
+ testsTurn.release();
+
+ // TEST 3: thread can't acquire lock, timeout = waitTime
+ threadsTurn.acquire();
+ QElapsedTimer timer;
+ timer.start();
+ QVERIFY(!normalMutex.try_lock_for(waitTimeAsDuration));
+ QVERIFY(timer.elapsed() >= waitTime - systemTimersResolution);
+ testsTurn.release();
+
+ // TEST 4: thread can acquire lock, timeout = waitTime
+ threadsTurn.acquire();
+ timer.start();
+ QVERIFY(normalMutex.try_lock_for(waitTimeAsDuration));
+ QVERIFY(timer.elapsed() <= waitTime + systemTimersResolution);
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ timer.start();
+ // it's non-recursive, so the following lock needs to fail
+ QVERIFY(!normalMutex.try_lock_for(waitTimeAsDuration));
+ QVERIFY(timer.elapsed() >= waitTime - systemTimersResolution);
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ normalMutex.unlock();
+ testsTurn.release();
+
+ // TEST 5: thread can't acquire lock, timeout = 0
+ threadsTurn.acquire();
+ QVERIFY(!normalMutex.try_lock_for(std::chrono::milliseconds::zero()));
+ testsTurn.release();
+
+ // TEST 6: thread can acquire lock, timeout = 0
+ threadsTurn.acquire();
+ timer.start();
+ QVERIFY(normalMutex.try_lock_for(std::chrono::milliseconds::zero()));
+ QVERIFY(timer.elapsed() < waitTime + systemTimersResolution);
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ QVERIFY(!normalMutex.try_lock_for(std::chrono::milliseconds::zero()));
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ normalMutex.unlock();
+ testsTurn.release();
+
+ // TEST 7 overflow: thread can acquire lock, timeout = 3000 (QTBUG-24795)
+ threadsTurn.acquire();
+ timer.start();
+ QVERIFY(normalMutex.try_lock_for(std::chrono::milliseconds(3000)));
+ QVERIFY(timer.elapsed() < 3000 + systemTimersResolution);
+ normalMutex.unlock();
+ testsTurn.release();
+
+ threadsTurn.acquire();
+ }
+ };
+
+ Thread thread;
+ thread.start();
+
+ // TEST 1: thread can't acquire lock
+ testsTurn.acquire();
+ normalMutex.lock();
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ threadsTurn.release();
+
+ // TEST 2: thread can acquire lock
+ testsTurn.acquire();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ normalMutex.unlock();
+ threadsTurn.release();
+
+ // TEST 3: thread can't acquire lock, timeout = waitTime
+ testsTurn.acquire();
+ normalMutex.lock();
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ threadsTurn.release();
+
+ // TEST 4: thread can acquire lock, timeout = waitTime
+ testsTurn.acquire();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ normalMutex.unlock();
+ threadsTurn.release();
+
+ // TEST 5: thread can't acquire lock, timeout = 0
+ testsTurn.acquire();
+ normalMutex.lock();
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ threadsTurn.release();
+
+ // TEST 6: thread can acquire lock, timeout = 0
+ testsTurn.acquire();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ normalMutex.unlock();
+ threadsTurn.release();
+
+ // TEST 7: thread can acquire lock, timeout = 3000 (QTBUG-24795)
+ testsTurn.acquire();
+ normalMutex.lock();
+ threadsTurn.release();
+ QThread::msleep(100);
+ normalMutex.unlock();
+
+ // wait for thread to finish
+ testsTurn.acquire();
+ threadsTurn.release();
+ thread.wait();
+#endif
+}
- // test recursive mutex
+void tst_QMutex::try_lock_until_non_recursive()
+{
+#if !QT_HAS_INCLUDE(<chrono>)
+ QSKIP("This test requires <chrono>");
+#else
+ class Thread : public QThread
{
- class Thread : public QThread
+ public:
+ void run()
{
- public:
- void run()
- {
- testsTurn.release();
-
- threadsTurn.acquire();
- QVERIFY(!recursiveMutex.tryLock());
- testsTurn.release();
-
- threadsTurn.acquire();
- QVERIFY(recursiveMutex.tryLock());
- QVERIFY(lockCount.testAndSetRelaxed(0, 1));
- QVERIFY(recursiveMutex.tryLock());
- QVERIFY(lockCount.testAndSetRelaxed(1, 2));
- QVERIFY(lockCount.testAndSetRelaxed(2, 1));
- recursiveMutex.unlock();
- QVERIFY(lockCount.testAndSetRelaxed(1, 0));
- recursiveMutex.unlock();
- testsTurn.release();
-
- threadsTurn.acquire();
- QTime timer;
- timer.start();
- QVERIFY(!recursiveMutex.tryLock(waitTime));
- QVERIFY(timer.elapsed() >= waitTime);
- QVERIFY(!recursiveMutex.tryLock(0));
- testsTurn.release();
-
- threadsTurn.acquire();
- timer.start();
- QVERIFY(recursiveMutex.tryLock(waitTime));
- QVERIFY(timer.elapsed() <= waitTime);
- QVERIFY(lockCount.testAndSetRelaxed(0, 1));
- QVERIFY(recursiveMutex.tryLock(waitTime));
- QVERIFY(lockCount.testAndSetRelaxed(1, 2));
- QVERIFY(lockCount.testAndSetRelaxed(2, 1));
- recursiveMutex.unlock();
- QVERIFY(lockCount.testAndSetRelaxed(1, 0));
- recursiveMutex.unlock();
- testsTurn.release();
-
- threadsTurn.acquire();
- QVERIFY(!recursiveMutex.tryLock(0));
- QVERIFY(!recursiveMutex.tryLock(0));
- testsTurn.release();
-
- threadsTurn.acquire();
- timer.start();
- QVERIFY(recursiveMutex.tryLock(0));
- QVERIFY(timer.elapsed() < waitTime);
- QVERIFY(lockCount.testAndSetRelaxed(0, 1));
- QVERIFY(recursiveMutex.tryLock(0));
- QVERIFY(lockCount.testAndSetRelaxed(1, 2));
- QVERIFY(lockCount.testAndSetRelaxed(2, 1));
- recursiveMutex.unlock();
- QVERIFY(lockCount.testAndSetRelaxed(1, 0));
- recursiveMutex.unlock();
- testsTurn.release();
-
- threadsTurn.acquire();
- }
- };
+ const std::chrono::milliseconds systemTimersResolutionAsDuration(systemTimersResolution);
+ testsTurn.release();
+
+ // TEST 1: thread can't acquire lock
+ threadsTurn.acquire();
+ QVERIFY(!normalMutex.try_lock());
+ testsTurn.release();
+
+ // TEST 2: thread can acquire lock
+ threadsTurn.acquire();
+ QVERIFY(normalMutex.try_lock());
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ QVERIFY(!normalMutex.try_lock());
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ normalMutex.unlock();
+ testsTurn.release();
+
+ // TEST 3: thread can't acquire lock, timeout = waitTime
+ threadsTurn.acquire();
+ auto endTimePoint = std::chrono::steady_clock::now() + waitTimeAsDuration;
+ QVERIFY(!normalMutex.try_lock_until(endTimePoint));
+ QVERIFY(std::chrono::steady_clock::now() >= endTimePoint - systemTimersResolutionAsDuration);
+ testsTurn.release();
+
+ // TEST 4: thread can acquire lock, timeout = waitTime
+ threadsTurn.acquire();
+ endTimePoint = std::chrono::steady_clock::now() + waitTimeAsDuration;
+ QVERIFY(normalMutex.try_lock_until(endTimePoint));
+ QVERIFY(std::chrono::steady_clock::now() <= endTimePoint + systemTimersResolutionAsDuration);
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ endTimePoint = std::chrono::steady_clock::now() + waitTimeAsDuration;
+ // it's non-recursive, so the following lock needs to fail
+ QVERIFY(!normalMutex.try_lock_until(endTimePoint));
+ QVERIFY(std::chrono::steady_clock::now() >= endTimePoint - systemTimersResolutionAsDuration);
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ normalMutex.unlock();
+ testsTurn.release();
+
+ // TEST 5: thread can't acquire lock, timeout = 0
+ threadsTurn.acquire();
+ QVERIFY(!normalMutex.try_lock_until(std::chrono::steady_clock::now()));
+ testsTurn.release();
+
+ // TEST 6: thread can acquire lock, timeout = 0
+ threadsTurn.acquire();
+ endTimePoint = std::chrono::steady_clock::now() + waitTimeAsDuration;
+ QVERIFY(normalMutex.try_lock_until(std::chrono::steady_clock::now()));
+ QVERIFY(std::chrono::steady_clock::now() < endTimePoint + systemTimersResolutionAsDuration);
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ QVERIFY(!normalMutex.try_lock_until(std::chrono::steady_clock::now()));
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ normalMutex.unlock();
+ testsTurn.release();
+
+ // TEST 7 overflow: thread can acquire lock, timeout = 3000 (QTBUG-24795)
+ threadsTurn.acquire();
+ endTimePoint = std::chrono::steady_clock::now() + std::chrono::milliseconds(3000);
+ QVERIFY(normalMutex.try_lock_until(endTimePoint));
+ QVERIFY(std::chrono::steady_clock::now() < endTimePoint + systemTimersResolutionAsDuration);
+ normalMutex.unlock();
+ testsTurn.release();
+
+ threadsTurn.acquire();
+ }
+ };
- Thread thread;
- thread.start();
+ Thread thread;
+ thread.start();
+
+ // TEST 1: thread can't acquire lock
+ testsTurn.acquire();
+ normalMutex.lock();
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ threadsTurn.release();
+
+ // TEST 2: thread can acquire lock
+ testsTurn.acquire();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ normalMutex.unlock();
+ threadsTurn.release();
+
+ // TEST 3: thread can't acquire lock, timeout = waitTime
+ testsTurn.acquire();
+ normalMutex.lock();
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ threadsTurn.release();
+
+ // TEST 4: thread can acquire lock, timeout = waitTime
+ testsTurn.acquire();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ normalMutex.unlock();
+ threadsTurn.release();
+
+ // TEST 5: thread can't acquire lock, timeout = 0
+ testsTurn.acquire();
+ normalMutex.lock();
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ threadsTurn.release();
+
+ // TEST 6: thread can acquire lock, timeout = 0
+ testsTurn.acquire();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ normalMutex.unlock();
+ threadsTurn.release();
+
+ // TEST 7: thread can acquire lock, timeout = 3000 (QTBUG-24795)
+ testsTurn.acquire();
+ normalMutex.lock();
+ threadsTurn.release();
+ QThread::msleep(100);
+ normalMutex.unlock();
+
+ // wait for thread to finish
+ testsTurn.acquire();
+ threadsTurn.release();
+ thread.wait();
+#endif
+}
- // thread can't acquire lock
- testsTurn.acquire();
- recursiveMutex.lock();
- QVERIFY(lockCount.testAndSetRelaxed(0, 1));
- recursiveMutex.lock();
- QVERIFY(lockCount.testAndSetRelaxed(1, 2));
- threadsTurn.release();
-
- // thread can acquire lock
- testsTurn.acquire();
- QVERIFY(lockCount.testAndSetRelaxed(2, 1));
- recursiveMutex.unlock();
- QVERIFY(lockCount.testAndSetRelaxed(1, 0));
- recursiveMutex.unlock();
- threadsTurn.release();
-
- // thread can't acquire lock, timeout = waitTime
- testsTurn.acquire();
- recursiveMutex.lock();
- QVERIFY(lockCount.testAndSetRelaxed(0, 1));
- recursiveMutex.lock();
- QVERIFY(lockCount.testAndSetRelaxed(1, 2));
- threadsTurn.release();
-
- // thread can acquire lock, timeout = waitTime
- testsTurn.acquire();
- QVERIFY(lockCount.testAndSetRelaxed(2, 1));
- recursiveMutex.unlock();
- QVERIFY(lockCount.testAndSetRelaxed(1, 0));
- recursiveMutex.unlock();
- threadsTurn.release();
-
- // thread can't acquire lock, timeout = 0
- testsTurn.acquire();
- recursiveMutex.lock();
- QVERIFY(lockCount.testAndSetRelaxed(0, 1));
- recursiveMutex.lock();
- QVERIFY(lockCount.testAndSetRelaxed(1, 2));
- threadsTurn.release();
-
- // thread can acquire lock, timeout = 0
- testsTurn.acquire();
- QVERIFY(lockCount.testAndSetRelaxed(2, 1));
- recursiveMutex.unlock();
- QVERIFY(lockCount.testAndSetRelaxed(1, 0));
- recursiveMutex.unlock();
- threadsTurn.release();
-
- // stop thread
- testsTurn.acquire();
- threadsTurn.release();
- thread.wait();
- }
+void tst_QMutex::tryLock_recursive()
+{
+ class Thread : public QThread
+ {
+ public:
+ void run()
+ {
+ testsTurn.release();
+
+ threadsTurn.acquire();
+ QVERIFY(!recursiveMutex.tryLock());
+ testsTurn.release();
+
+ threadsTurn.acquire();
+ QVERIFY(recursiveMutex.tryLock());
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ QVERIFY(recursiveMutex.tryLock());
+ QVERIFY(lockCount.testAndSetRelaxed(1, 2));
+ QVERIFY(lockCount.testAndSetRelaxed(2, 1));
+ recursiveMutex.unlock();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ recursiveMutex.unlock();
+ testsTurn.release();
+
+ threadsTurn.acquire();
+ QElapsedTimer timer;
+ timer.start();
+ QVERIFY(!recursiveMutex.tryLock(waitTime));
+ QVERIFY(timer.elapsed() >= waitTime - systemTimersResolution);
+ QVERIFY(!recursiveMutex.tryLock(0));
+ testsTurn.release();
+
+ threadsTurn.acquire();
+ timer.start();
+ QVERIFY(recursiveMutex.tryLock(waitTime));
+ QVERIFY(timer.elapsed() <= waitTime + systemTimersResolution);
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ QVERIFY(recursiveMutex.tryLock(waitTime));
+ QVERIFY(lockCount.testAndSetRelaxed(1, 2));
+ QVERIFY(lockCount.testAndSetRelaxed(2, 1));
+ recursiveMutex.unlock();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ recursiveMutex.unlock();
+ testsTurn.release();
+
+ threadsTurn.acquire();
+ QVERIFY(!recursiveMutex.tryLock(0));
+ QVERIFY(!recursiveMutex.tryLock(0));
+ testsTurn.release();
+
+ threadsTurn.acquire();
+ timer.start();
+ QVERIFY(recursiveMutex.tryLock(0));
+ QVERIFY(timer.elapsed() < waitTime + systemTimersResolution);
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ QVERIFY(recursiveMutex.tryLock(0));
+ QVERIFY(lockCount.testAndSetRelaxed(1, 2));
+ QVERIFY(lockCount.testAndSetRelaxed(2, 1));
+ recursiveMutex.unlock();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ recursiveMutex.unlock();
+ testsTurn.release();
+
+ threadsTurn.acquire();
+ }
+ };
+
+ Thread thread;
+ thread.start();
+
+ // thread can't acquire lock
+ testsTurn.acquire();
+ recursiveMutex.lock();
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ recursiveMutex.lock();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 2));
+ threadsTurn.release();
+
+ // thread can acquire lock
+ testsTurn.acquire();
+ QVERIFY(lockCount.testAndSetRelaxed(2, 1));
+ recursiveMutex.unlock();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ recursiveMutex.unlock();
+ threadsTurn.release();
+
+ // thread can't acquire lock, timeout = waitTime
+ testsTurn.acquire();
+ recursiveMutex.lock();
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ recursiveMutex.lock();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 2));
+ threadsTurn.release();
+
+ // thread can acquire lock, timeout = waitTime
+ testsTurn.acquire();
+ QVERIFY(lockCount.testAndSetRelaxed(2, 1));
+ recursiveMutex.unlock();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ recursiveMutex.unlock();
+ threadsTurn.release();
+
+ // thread can't acquire lock, timeout = 0
+ testsTurn.acquire();
+ recursiveMutex.lock();
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ recursiveMutex.lock();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 2));
+ threadsTurn.release();
+
+ // thread can acquire lock, timeout = 0
+ testsTurn.acquire();
+ QVERIFY(lockCount.testAndSetRelaxed(2, 1));
+ recursiveMutex.unlock();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ recursiveMutex.unlock();
+ threadsTurn.release();
+
+ // stop thread
+ testsTurn.acquire();
+ threadsTurn.release();
+ thread.wait();
+}
+
+void tst_QMutex::try_lock_for_recursive()
+{
+#if !QT_HAS_INCLUDE(<chrono>)
+ QSKIP("This test requires <chrono>");
+#else
+ class Thread : public QThread
+ {
+ public:
+ void run()
+ {
+ const std::chrono::milliseconds systemTimersResolutionAsDuration(systemTimersResolution);
+ testsTurn.release();
+
+ threadsTurn.acquire();
+ QVERIFY(!recursiveMutex.try_lock());
+ testsTurn.release();
+
+ threadsTurn.acquire();
+ QVERIFY(recursiveMutex.try_lock());
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ QVERIFY(recursiveMutex.try_lock());
+ QVERIFY(lockCount.testAndSetRelaxed(1, 2));
+ QVERIFY(lockCount.testAndSetRelaxed(2, 1));
+ recursiveMutex.unlock();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ recursiveMutex.unlock();
+ testsTurn.release();
+
+ threadsTurn.acquire();
+ QElapsedTimer timer;
+ timer.start();
+ QVERIFY(!recursiveMutex.try_lock_for(waitTimeAsDuration));
+ QVERIFY(timer.elapsed() >= waitTime - systemTimersResolution);
+ QVERIFY(!recursiveMutex.try_lock_for(std::chrono::milliseconds::zero()));
+ testsTurn.release();
+
+ threadsTurn.acquire();
+ timer.start();
+ QVERIFY(recursiveMutex.try_lock_for(waitTimeAsDuration));
+ QVERIFY(timer.elapsed() <= waitTime + systemTimersResolution);
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ QVERIFY(recursiveMutex.try_lock_for(waitTimeAsDuration));
+ QVERIFY(lockCount.testAndSetRelaxed(1, 2));
+ QVERIFY(lockCount.testAndSetRelaxed(2, 1));
+ recursiveMutex.unlock();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ recursiveMutex.unlock();
+ testsTurn.release();
+
+ threadsTurn.acquire();
+ QVERIFY(!recursiveMutex.try_lock_for(std::chrono::milliseconds::zero()));
+ QVERIFY(!recursiveMutex.try_lock_for(std::chrono::milliseconds::zero()));
+ testsTurn.release();
+
+ threadsTurn.acquire();
+ timer.start();
+ QVERIFY(recursiveMutex.try_lock_for(std::chrono::milliseconds::zero()));
+ QVERIFY(timer.elapsed() < waitTime + systemTimersResolution);
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ QVERIFY(recursiveMutex.try_lock_for(std::chrono::milliseconds::zero()));
+ QVERIFY(lockCount.testAndSetRelaxed(1, 2));
+ QVERIFY(lockCount.testAndSetRelaxed(2, 1));
+ recursiveMutex.unlock();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ recursiveMutex.unlock();
+ testsTurn.release();
+
+ threadsTurn.acquire();
+ }
+ };
+
+ Thread thread;
+ thread.start();
+
+ // thread can't acquire lock
+ testsTurn.acquire();
+ recursiveMutex.lock();
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ recursiveMutex.lock();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 2));
+ threadsTurn.release();
+
+ // thread can acquire lock
+ testsTurn.acquire();
+ QVERIFY(lockCount.testAndSetRelaxed(2, 1));
+ recursiveMutex.unlock();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ recursiveMutex.unlock();
+ threadsTurn.release();
+
+ // thread can't acquire lock, timeout = waitTime
+ testsTurn.acquire();
+ recursiveMutex.lock();
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ recursiveMutex.lock();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 2));
+ threadsTurn.release();
+
+ // thread can acquire lock, timeout = waitTime
+ testsTurn.acquire();
+ QVERIFY(lockCount.testAndSetRelaxed(2, 1));
+ recursiveMutex.unlock();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ recursiveMutex.unlock();
+ threadsTurn.release();
+
+ // thread can't acquire lock, timeout = 0
+ testsTurn.acquire();
+ recursiveMutex.lock();
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ recursiveMutex.lock();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 2));
+ threadsTurn.release();
+
+ // thread can acquire lock, timeout = 0
+ testsTurn.acquire();
+ QVERIFY(lockCount.testAndSetRelaxed(2, 1));
+ recursiveMutex.unlock();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ recursiveMutex.unlock();
+ threadsTurn.release();
+
+ // stop thread
+ testsTurn.acquire();
+ threadsTurn.release();
+ thread.wait();
+#endif
+}
+
+void tst_QMutex::try_lock_until_recursive()
+{
+#if !QT_HAS_INCLUDE(<chrono>)
+ QSKIP("This test requires <chrono>");
+#else
+ class Thread : public QThread
+ {
+ public:
+ void run()
+ {
+ const std::chrono::milliseconds systemTimersResolutionAsDuration(systemTimersResolution);
+ testsTurn.release();
+
+ threadsTurn.acquire();
+ QVERIFY(!recursiveMutex.try_lock());
+ testsTurn.release();
+
+ threadsTurn.acquire();
+ QVERIFY(recursiveMutex.try_lock());
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ QVERIFY(recursiveMutex.try_lock());
+ QVERIFY(lockCount.testAndSetRelaxed(1, 2));
+ QVERIFY(lockCount.testAndSetRelaxed(2, 1));
+ recursiveMutex.unlock();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ recursiveMutex.unlock();
+ testsTurn.release();
+
+ threadsTurn.acquire();
+ auto endTimePoint = std::chrono::steady_clock::now() + waitTimeAsDuration;
+ QVERIFY(!recursiveMutex.try_lock_until(endTimePoint));
+ QVERIFY(std::chrono::steady_clock::now() >= endTimePoint - systemTimersResolutionAsDuration);
+ QVERIFY(!recursiveMutex.try_lock());
+ testsTurn.release();
+
+ threadsTurn.acquire();
+ endTimePoint = std::chrono::steady_clock::now() + waitTimeAsDuration;
+ QVERIFY(recursiveMutex.try_lock_until(endTimePoint));
+ QVERIFY(std::chrono::steady_clock::now() <= endTimePoint + systemTimersResolutionAsDuration);
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ endTimePoint = std::chrono::steady_clock::now() + waitTimeAsDuration;
+ QVERIFY(recursiveMutex.try_lock_until(endTimePoint));
+ QVERIFY(lockCount.testAndSetRelaxed(1, 2));
+ QVERIFY(lockCount.testAndSetRelaxed(2, 1));
+ recursiveMutex.unlock();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ recursiveMutex.unlock();
+ testsTurn.release();
+
+ threadsTurn.acquire();
+ QVERIFY(!recursiveMutex.try_lock_until(std::chrono::steady_clock::now()));
+ QVERIFY(!recursiveMutex.try_lock_until(std::chrono::steady_clock::now()));
+ testsTurn.release();
+
+ threadsTurn.acquire();
+ endTimePoint = std::chrono::steady_clock::now() + waitTimeAsDuration;
+ QVERIFY(recursiveMutex.try_lock_until(std::chrono::steady_clock::now()));
+ QVERIFY(std::chrono::steady_clock::now() <= endTimePoint + systemTimersResolutionAsDuration);
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ QVERIFY(recursiveMutex.try_lock_until(std::chrono::steady_clock::now()));
+ QVERIFY(lockCount.testAndSetRelaxed(1, 2));
+ QVERIFY(lockCount.testAndSetRelaxed(2, 1));
+ recursiveMutex.unlock();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ recursiveMutex.unlock();
+ testsTurn.release();
+
+ threadsTurn.acquire();
+ }
+ };
+
+ Thread thread;
+ thread.start();
+
+ // thread can't acquire lock
+ testsTurn.acquire();
+ recursiveMutex.lock();
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ recursiveMutex.lock();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 2));
+ threadsTurn.release();
+
+ // thread can acquire lock
+ testsTurn.acquire();
+ QVERIFY(lockCount.testAndSetRelaxed(2, 1));
+ recursiveMutex.unlock();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ recursiveMutex.unlock();
+ threadsTurn.release();
+
+ // thread can't acquire lock, timeout = waitTime
+ testsTurn.acquire();
+ recursiveMutex.lock();
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ recursiveMutex.lock();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 2));
+ threadsTurn.release();
+
+ // thread can acquire lock, timeout = waitTime
+ testsTurn.acquire();
+ QVERIFY(lockCount.testAndSetRelaxed(2, 1));
+ recursiveMutex.unlock();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ recursiveMutex.unlock();
+ threadsTurn.release();
+
+ // thread can't acquire lock, timeout = 0
+ testsTurn.acquire();
+ recursiveMutex.lock();
+ QVERIFY(lockCount.testAndSetRelaxed(0, 1));
+ recursiveMutex.lock();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 2));
+ threadsTurn.release();
+
+ // thread can acquire lock, timeout = 0
+ testsTurn.acquire();
+ QVERIFY(lockCount.testAndSetRelaxed(2, 1));
+ recursiveMutex.unlock();
+ QVERIFY(lockCount.testAndSetRelaxed(1, 0));
+ recursiveMutex.unlock();
+ threadsTurn.release();
+
+ // stop thread
+ testsTurn.acquire();
+ threadsTurn.release();
+ thread.wait();
+#endif
}
class mutex_Thread : public QThread
@@ -439,7 +1014,7 @@ enum { one_minute = 6 * 1000, //not really one minute, but else it is too long.
class StressTestThread : public QThread
{
- QTime t;
+ QElapsedTimer t;
public:
static QBasicAtomicInt lockCount;
static QBasicAtomicInt sentinel;
@@ -491,7 +1066,7 @@ public:
void run()
{
- QTime t;
+ QElapsedTimer t;
t.start();
do {
if (mutex.tryLock())
@@ -619,7 +1194,7 @@ void tst_QMutex::tryLockNegative()
class MoreStressTestThread : public QThread
{
- QTime t;
+ QElapsedTimer t;
public:
static QAtomicInt lockCount;
static QAtomicInt sentinel[threadCount];