From 86a237929e2b67ce333b635b760e78c628effb60 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Sat, 2 Jul 2011 15:13:12 +0200 Subject: QMutex is now just a pointer And added a POD QBasicMutex. (QBasicMutex* can safely be static_cast'ed to QMutex*) The d pointer is not anymore always a QMutexPrivate. If d == 0x0: the mutex is unlocked If d == 0x1: the mutex is locked, uncontended On linux: if d == 0x3: the mutex is locked contended, waiting on a futex If d is a pointer, it is a recursive mutex. On non-linux platforms: When a thread tries to lock a mutex for which d == 0x1, it will try to assing it a QMutexPrivated (allocated from a freelist) in order to wait for it. Change-Id: Ie1431cd9402a576fdd9a693cfd747166eebf5622 Reviewed-by: Bradley T. Hughes Reviewed-on: http://codereview.qt.nokia.com/2116 Reviewed-by: Qt Sanity Bot Reviewed-by: Olivier Goffart --- tests/auto/qmutex/tst_qmutex.cpp | 111 +++++++++++++++++---- .../corelib/thread/qmutex/tst_qmutex.cpp | 11 -- 2 files changed, 90 insertions(+), 32 deletions(-) (limited to 'tests') diff --git a/tests/auto/qmutex/tst_qmutex.cpp b/tests/auto/qmutex/tst_qmutex.cpp index 5fed6bb44e..7ad6a98a4d 100644 --- a/tests/auto/qmutex/tst_qmutex.cpp +++ b/tests/auto/qmutex/tst_qmutex.cpp @@ -65,6 +65,7 @@ private slots: void stressTest(); void tryLockRace(); void qtbug16115_trylock(); + void moreStress(); }; static const int iterations = 100; @@ -83,6 +84,8 @@ QMutex normalMutex, recursiveMutex(QMutex::Recursive); QSemaphore testsTurn; QSemaphore threadsTurn; +enum { waitTime = 100 }; + void tst_QMutex::tryLock() { // test non-recursive mutex @@ -109,18 +112,18 @@ void tst_QMutex::tryLock() threadsTurn.acquire(); QTime timer; timer.start(); - QVERIFY(!normalMutex.tryLock(1000)); - QVERIFY(timer.elapsed() >= 1000); + QVERIFY(!normalMutex.tryLock(waitTime)); + QVERIFY(timer.elapsed() >= waitTime); testsTurn.release(); threadsTurn.acquire(); timer.start(); - QVERIFY(normalMutex.tryLock(1000)); - QVERIFY(timer.elapsed() <= 1000); + QVERIFY(normalMutex.tryLock(waitTime)); + QVERIFY(timer.elapsed() <= waitTime); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); timer.start(); - QVERIFY(!normalMutex.tryLock(1000)); - QVERIFY(timer.elapsed() >= 1000); + QVERIFY(!normalMutex.tryLock(waitTime)); + QVERIFY(timer.elapsed() >= waitTime); QVERIFY(lockCount.testAndSetRelaxed(1, 0)); normalMutex.unlock(); testsTurn.release(); @@ -132,7 +135,7 @@ void tst_QMutex::tryLock() threadsTurn.acquire(); timer.start(); QVERIFY(normalMutex.tryLock(0)); - QVERIFY(timer.elapsed() < 1000); + QVERIFY(timer.elapsed() < waitTime); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); QVERIFY(!normalMutex.tryLock(0)); QVERIFY(lockCount.testAndSetRelaxed(1, 0)); @@ -158,13 +161,13 @@ void tst_QMutex::tryLock() normalMutex.unlock(); threadsTurn.release(); - // thread can't acquire lock, timeout = 1000 + // thread can't acquire lock, timeout = waitTime testsTurn.acquire(); normalMutex.lock(); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); threadsTurn.release(); - // thread can acquire lock, timeout = 1000 + // thread can acquire lock, timeout = waitTime testsTurn.acquire(); QVERIFY(lockCount.testAndSetRelaxed(1, 0)); normalMutex.unlock(); @@ -215,17 +218,17 @@ void tst_QMutex::tryLock() threadsTurn.acquire(); QTime timer; timer.start(); - QVERIFY(!recursiveMutex.tryLock(1000)); - QVERIFY(timer.elapsed() >= 1000); + QVERIFY(!recursiveMutex.tryLock(waitTime)); + QVERIFY(timer.elapsed() >= waitTime); QVERIFY(!recursiveMutex.tryLock(0)); testsTurn.release(); threadsTurn.acquire(); timer.start(); - QVERIFY(recursiveMutex.tryLock(1000)); - QVERIFY(timer.elapsed() <= 1000); + QVERIFY(recursiveMutex.tryLock(waitTime)); + QVERIFY(timer.elapsed() <= waitTime); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); - QVERIFY(recursiveMutex.tryLock(1000)); + QVERIFY(recursiveMutex.tryLock(waitTime)); QVERIFY(lockCount.testAndSetRelaxed(1, 2)); QVERIFY(lockCount.testAndSetRelaxed(2, 1)); recursiveMutex.unlock(); @@ -241,7 +244,7 @@ void tst_QMutex::tryLock() threadsTurn.acquire(); timer.start(); QVERIFY(recursiveMutex.tryLock(0)); - QVERIFY(timer.elapsed() < 1000); + QVERIFY(timer.elapsed() < waitTime); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); QVERIFY(recursiveMutex.tryLock(0)); QVERIFY(lockCount.testAndSetRelaxed(1, 2)); @@ -274,7 +277,7 @@ void tst_QMutex::tryLock() recursiveMutex.unlock(); threadsTurn.release(); - // thread can't acquire lock, timeout = 1000 + // thread can't acquire lock, timeout = waitTime testsTurn.acquire(); recursiveMutex.lock(); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); @@ -282,7 +285,7 @@ void tst_QMutex::tryLock() QVERIFY(lockCount.testAndSetRelaxed(1, 2)); threadsTurn.release(); - // thread can acquire lock, timeout = 1000 + // thread can acquire lock, timeout = waitTime testsTurn.acquire(); QVERIFY(lockCount.testAndSetRelaxed(2, 1)); recursiveMutex.unlock(); @@ -436,7 +439,8 @@ void tst_QMutex::lock_unlock_locked_tryLock() } } -enum { one_minute = 60 * 1000, threadCount = 10 }; +enum { one_minute = 6 * 1000, //not really one minute, but else it is too long. + threadCount = 10 }; class StressTestThread : public QThread { @@ -497,7 +501,7 @@ public: do { if (mutex.tryLock()) mutex.unlock(); - } while (t.elapsed() < 20000); + } while (t.elapsed() < one_minute/2); } }; QMutex TryLockRaceThread::mutex; @@ -534,7 +538,7 @@ void tst_QMutex::qtbug16115_trylock() TrylockThread(QMutex &mut) : mut(mut) {} QMutex &mut; void run() { - for (int i = 0; i < 1000000; ++i) { + for (int i = 0; i < 100000; ++i) { if (mut.tryLock(0)) { if ((++qtbug16115_trylock_counter) != 1) ++qtbug16115_failure_count; @@ -553,7 +557,7 @@ void tst_QMutex::qtbug16115_trylock() t2.start(); t3.start(); - for (int i = 0; i < 1000000; ++i) { + for (int i = 0; i < 100000; ++i) { mut.lock(); if ((++qtbug16115_trylock_counter) != 1) ++qtbug16115_failure_count; @@ -567,5 +571,70 @@ void tst_QMutex::qtbug16115_trylock() QCOMPARE(qtbug16115_failure_count, 0); } + +class MoreStressTestThread : public QThread +{ + QTime t; +public: + static QAtomicInt lockCount; + static QAtomicInt sentinel[threadCount]; + static QMutex mutex[threadCount]; + static QAtomicInt errorCount; + void start() + { + t.start(); + QThread::start(); + } + void run() + { + quint64 i = 0; + while (t.elapsed() < one_minute) { + i++; + uint nb = (i * 9 + lockCount * 13) % threadCount; + QMutexLocker locker(&mutex[nb]); + if (sentinel[nb]) errorCount.ref(); + if (sentinel[nb].fetchAndAddRelaxed(5)) errorCount.ref(); + if (!sentinel[nb].testAndSetRelaxed(5, 0)) errorCount.ref(); + if (sentinel[nb]) errorCount.ref(); + lockCount.ref(); + nb = (nb * 17 + i * 5 + lockCount * 3) % threadCount; + if (mutex[nb].tryLock()) { + if (sentinel[nb]) errorCount.ref(); + if (sentinel[nb].fetchAndAddRelaxed(16)) errorCount.ref(); + if (!sentinel[nb].testAndSetRelaxed(16, 0)) errorCount.ref(); + if (sentinel[nb]) errorCount.ref(); + lockCount.ref(); + mutex[nb].unlock(); + } + nb = (nb * 15 + i * 47 + lockCount * 31) % threadCount; + if (mutex[nb].tryLock(2)) { + if (sentinel[nb]) errorCount.ref(); + if (sentinel[nb].fetchAndAddRelaxed(53)) errorCount.ref(); + if (!sentinel[nb].testAndSetRelaxed(53, 0)) errorCount.ref(); + if (sentinel[nb]) errorCount.ref(); + lockCount.ref(); + mutex[nb].unlock(); + } + } + } +}; +QMutex MoreStressTestThread::mutex[threadCount]; +QAtomicInt MoreStressTestThread::lockCount; +QAtomicInt MoreStressTestThread::sentinel[threadCount]; +QAtomicInt MoreStressTestThread::errorCount = 0; + +void tst_QMutex::moreStress() +{ + MoreStressTestThread threads[threadCount]; + for (int i = 0; i < threadCount; ++i) + threads[i].start(); + QVERIFY(threads[0].wait(one_minute + 10000)); + for (int i = 1; i < threadCount; ++i) + QVERIFY(threads[i].wait(10000)); + qDebug("locked %d times", int(MoreStressTestThread::lockCount)); + QCOMPARE(int(MoreStressTestThread::errorCount), 0); +} + + QTEST_MAIN(tst_QMutex) #include "tst_qmutex.moc" diff --git a/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp b/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp index 05a15750c1..05e184d0c2 100644 --- a/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp +++ b/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp @@ -151,7 +151,6 @@ void tst_QMutex::noThread_data() QTest::addColumn("t"); QTest::newRow("noLock") << 1; - QTest::newRow("QMutexInline") << 2; QTest::newRow("QMutex") << 3; QTest::newRow("QMutexLocker") << 4; } @@ -172,16 +171,6 @@ void tst_QMutex::noThread() } } break; - case 2: - QBENCHMARK { - count = 0; - for (int i = 0; i < N; i++) { - mtx.lockInline(); - count++; - mtx.unlockInline(); - } - } - break; case 3: QBENCHMARK { count = 0; -- cgit v1.2.3