summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/thread/qmutex
diff options
context:
space:
mode:
authorGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2016-07-16 18:06:48 +0200
committerGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2016-07-22 23:18:27 +0000
commit7814bf126a50b7afa1dc46059b685f82f1b171f0 (patch)
tree440f310f3fb1e813e0d24a2c0070c71b523222a2 /tests/auto/corelib/thread/qmutex
parent8ea51f8aaa426fa14393b83082f9eec076d7d72a (diff)
Use QElapsedTimer in tst_qmutex
This requires fixing the test on Windows: QMutex internally uses WaitForSingleObjectEx which can wake up early, according to the system timer resolution: https://msdn.microsoft.com/en-us/library/windows/desktop/ms687069(v=vs.85).aspx#waitfunctionsandtime-outintervals QTime must be so slow that it hides the early wakes, but QElapsedTimer is accurate enough to make the test fail unless we add back some tolerance to compensate for the early wakeups. Change-Id: I20b38af9c87a0b0e38a19b9bff1c3c24975c78f5 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'tests/auto/corelib/thread/qmutex')
-rw-r--r--tests/auto/corelib/thread/qmutex/qmutex.pro1
-rw-r--r--tests/auto/corelib/thread/qmutex/tst_qmutex.cpp82
2 files changed, 69 insertions, 14 deletions
diff --git a/tests/auto/corelib/thread/qmutex/qmutex.pro b/tests/auto/corelib/thread/qmutex/qmutex.pro
index 229e57eb89..cb9d364b71 100644
--- a/tests/auto/corelib/thread/qmutex/qmutex.pro
+++ b/tests/auto/corelib/thread/qmutex/qmutex.pro
@@ -2,3 +2,4 @@ CONFIG += testcase
TARGET = tst_qmutex
QT = core testlib
SOURCES = tst_qmutex.cpp
+win32:QT += core-private
diff --git a/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp b/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp
index 594bae674c..5037e42beb 100644
--- a/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp
+++ b/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp
@@ -31,15 +31,21 @@
#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 initTestCase();
void tryLock();
void lock_unlock_locked_tryLock();
void stressTest();
@@ -48,6 +54,8 @@ private slots:
void tryLockNegative_data();
void tryLockNegative();
void moreStress();
+private:
+ void initializeSystemTimersResolution();
};
static const int iterations = 100;
@@ -58,6 +66,52 @@ QSemaphore testsTurn;
QSemaphore threadsTurn;
enum { waitTime = 100 };
+uint systemTimersResolution = 1;
+
+/*
+ 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()
{
@@ -86,22 +140,22 @@ void tst_QMutex::tryLock()
// TEST 3: thread can't acquire lock, timeout = waitTime
threadsTurn.acquire();
- QTime timer;
+ QElapsedTimer timer;
timer.start();
QVERIFY(!normalMutex.tryLock(waitTime));
- QVERIFY(timer.elapsed() >= 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);
+ 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);
+ QVERIFY(timer.elapsed() >= waitTime - systemTimersResolution);
QVERIFY(lockCount.testAndSetRelaxed(1, 0));
normalMutex.unlock();
testsTurn.release();
@@ -115,7 +169,7 @@ void tst_QMutex::tryLock()
threadsTurn.acquire();
timer.start();
QVERIFY(normalMutex.tryLock(0));
- QVERIFY(timer.elapsed() < waitTime);
+ QVERIFY(timer.elapsed() < waitTime + systemTimersResolution);
QVERIFY(lockCount.testAndSetRelaxed(0, 1));
QVERIFY(!normalMutex.tryLock(0));
QVERIFY(lockCount.testAndSetRelaxed(1, 0));
@@ -126,7 +180,7 @@ void tst_QMutex::tryLock()
threadsTurn.acquire();
timer.start();
QVERIFY(normalMutex.tryLock(3000));
- QVERIFY(timer.elapsed() < 3000);
+ QVERIFY(timer.elapsed() < 3000 + systemTimersResolution);
normalMutex.unlock();
testsTurn.release();
@@ -211,17 +265,17 @@ void tst_QMutex::tryLock()
testsTurn.release();
threadsTurn.acquire();
- QTime timer;
+ QElapsedTimer timer;
timer.start();
QVERIFY(!recursiveMutex.tryLock(waitTime));
- QVERIFY(timer.elapsed() >= waitTime);
+ QVERIFY(timer.elapsed() >= waitTime - systemTimersResolution);
QVERIFY(!recursiveMutex.tryLock(0));
testsTurn.release();
threadsTurn.acquire();
timer.start();
QVERIFY(recursiveMutex.tryLock(waitTime));
- QVERIFY(timer.elapsed() <= waitTime);
+ QVERIFY(timer.elapsed() <= waitTime + systemTimersResolution);
QVERIFY(lockCount.testAndSetRelaxed(0, 1));
QVERIFY(recursiveMutex.tryLock(waitTime));
QVERIFY(lockCount.testAndSetRelaxed(1, 2));
@@ -239,7 +293,7 @@ void tst_QMutex::tryLock()
threadsTurn.acquire();
timer.start();
QVERIFY(recursiveMutex.tryLock(0));
- QVERIFY(timer.elapsed() < waitTime);
+ QVERIFY(timer.elapsed() < waitTime + systemTimersResolution);
QVERIFY(lockCount.testAndSetRelaxed(0, 1));
QVERIFY(recursiveMutex.tryLock(0));
QVERIFY(lockCount.testAndSetRelaxed(1, 2));
@@ -439,7 +493,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 +545,7 @@ public:
void run()
{
- QTime t;
+ QElapsedTimer t;
t.start();
do {
if (mutex.tryLock())
@@ -619,7 +673,7 @@ void tst_QMutex::tryLockNegative()
class MoreStressTestThread : public QThread
{
- QTime t;
+ QElapsedTimer t;
public:
static QAtomicInt lockCount;
static QAtomicInt sentinel[threadCount];