diff options
author | Holger Ihrig <holger.ihrig@nokia.com> | 2011-08-26 12:56:14 +0200 |
---|---|---|
committer | Holger Ihrig <holger.ihrig@nokia.com> | 2011-09-01 12:54:58 +0200 |
commit | 82e715b2770258fa2c536aeae1f46c7fccdcdecf (patch) | |
tree | a4b9135effe2109b164f622314a6ffac6198a8f8 /tests/auto/qreadwritelock | |
parent | c9a5ccb268b5e2b2ce0743989c44f808b538ba9b (diff) |
Moving relevant tests to corelib/thread
Task-number: QTBUG-21066
Change-Id: Ia16fa8961f1a73f4da6709197b5dd9929c16583f
Reviewed-on: http://codereview.qt.nokia.com/3663
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Rohan McGovern <rohan.mcgovern@nokia.com>
Reviewed-by: Jason McDonald <jason.mcdonald@nokia.com>
Diffstat (limited to 'tests/auto/qreadwritelock')
-rw-r--r-- | tests/auto/qreadwritelock/.gitignore | 1 | ||||
-rw-r--r-- | tests/auto/qreadwritelock/qreadwritelock.pro | 4 | ||||
-rw-r--r-- | tests/auto/qreadwritelock/tst_qreadwritelock.cpp | 1140 |
3 files changed, 0 insertions, 1145 deletions
diff --git a/tests/auto/qreadwritelock/.gitignore b/tests/auto/qreadwritelock/.gitignore deleted file mode 100644 index 96fda685f5..0000000000 --- a/tests/auto/qreadwritelock/.gitignore +++ /dev/null @@ -1 +0,0 @@ -tst_qreadwritelock diff --git a/tests/auto/qreadwritelock/qreadwritelock.pro b/tests/auto/qreadwritelock/qreadwritelock.pro deleted file mode 100644 index 93f7c68dc3..0000000000 --- a/tests/auto/qreadwritelock/qreadwritelock.pro +++ /dev/null @@ -1,4 +0,0 @@ -load(qttest_p4) -SOURCES += tst_qreadwritelock.cpp -QT = core -CONFIG += parallel_test diff --git a/tests/auto/qreadwritelock/tst_qreadwritelock.cpp b/tests/auto/qreadwritelock/tst_qreadwritelock.cpp deleted file mode 100644 index 1b995e8d19..0000000000 --- a/tests/auto/qreadwritelock/tst_qreadwritelock.cpp +++ /dev/null @@ -1,1140 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include <QtTest/QtTest> -#include <qcoreapplication.h> - - -#include <qreadwritelock.h> -#include <qmutex.h> -#include <qthread.h> -#include <qwaitcondition.h> - -#ifdef Q_OS_UNIX -#include <unistd.h> -#endif -#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) -#include <windows.h> -#define sleep(X) Sleep(X) -#endif - -//on solaris, threads that loop one the release bool variable -//needs to sleep more than 1 usec. -#ifdef Q_OS_SOLARIS -# define RWTESTSLEEP usleep(10); -#else -# define RWTESTSLEEP usleep(1); -#endif - -#include <stdio.h> - -//TESTED_CLASS= -//TESTED_FILES= - -class tst_QReadWriteLock : public QObject -{ - Q_OBJECT -public: - tst_QReadWriteLock(); - virtual ~tst_QReadWriteLock(); - - -/* - Singlethreaded tests -*/ -private slots: -void constructDestruct(); -void readLockUnlock(); -void writeLockUnlock(); -void readLockUnlockLoop(); -void writeLockUnlockLoop(); -void readLockLoop(); -void writeLockLoop(); -void readWriteLockUnlockLoop(); -void tryReadLock(); -void tryWriteLock(); -/* - Multithreaded tests -*/ -private slots: - -void readLockBlockRelease(); -void writeLockBlockRelease(); -void multipleReadersBlockRelease(); -void multipleReadersLoop(); -void multipleWritersLoop(); -void multipleReadersWritersLoop(); -void countingTest(); -void limitedReaders(); -void deleteOnUnlock(); - -/* - Performance tests -*/ -private slots: -void uncontendedLocks(); - - // recursive locking tests - void recursiveReadLock(); - void recursiveWriteLock(); -}; - -tst_QReadWriteLock::tst_QReadWriteLock() -{ - -} - -tst_QReadWriteLock::~tst_QReadWriteLock() -{ - -} - -void tst_QReadWriteLock::constructDestruct() -{ - { - QReadWriteLock rwlock; - } -} - -void tst_QReadWriteLock::readLockUnlock() -{ - QReadWriteLock rwlock; - rwlock.lockForRead(); - rwlock.unlock(); -} - -void tst_QReadWriteLock::writeLockUnlock() -{ - QReadWriteLock rwlock; - rwlock.lockForWrite(); - rwlock.unlock(); -} - -void tst_QReadWriteLock::readLockUnlockLoop() -{ - QReadWriteLock rwlock; - int runs=10000; - int i; - for (i=0; i<runs; ++i) { - rwlock.lockForRead(); - rwlock.unlock(); - } -} - -void tst_QReadWriteLock::writeLockUnlockLoop() -{ - QReadWriteLock rwlock; - int runs=10000; - int i; - for (i=0; i<runs; ++i) { - rwlock.lockForWrite(); - rwlock.unlock(); - } -} - - -void tst_QReadWriteLock::readLockLoop() -{ - QReadWriteLock rwlock; - int runs=10000; - int i; - for (i=0; i<runs; ++i) { - rwlock.lockForRead(); - } - for (i=0; i<runs; ++i) { - rwlock.unlock(); - } -} - -void tst_QReadWriteLock::writeLockLoop() -{ - /* - If you include this, the test should print one line - and then block. - */ -#if 0 - QReadWriteLock rwlock; - int runs=10000; - int i; - for (i=0; i<runs; ++i) { - rwlock.lockForWrite(); - qDebug("I am going to block now."); - } -#endif -} - -void tst_QReadWriteLock::readWriteLockUnlockLoop() -{ - QReadWriteLock rwlock; - int runs=10000; - int i; - for (i=0; i<runs; ++i) { - rwlock.lockForRead(); - rwlock.unlock(); - rwlock.lockForWrite(); - rwlock.unlock(); - } - -} - -QAtomicInt lockCount(0); -QReadWriteLock readWriteLock; -QSemaphore testsTurn; -QSemaphore threadsTurn; - - -void tst_QReadWriteLock::tryReadLock() -{ - QReadWriteLock rwlock; - QVERIFY(rwlock.tryLockForRead()); - rwlock.unlock(); - QVERIFY(rwlock.tryLockForRead()); - rwlock.unlock(); - - rwlock.lockForRead(); - rwlock.lockForRead(); - QVERIFY(rwlock.tryLockForRead()); - rwlock.unlock(); - rwlock.unlock(); - rwlock.unlock(); - - rwlock.lockForWrite(); - QVERIFY(!rwlock.tryLockForRead()); - rwlock.unlock(); - - // functionality test - { - class Thread : public QThread - { - public: - void run() - { - testsTurn.release(); - - threadsTurn.acquire(); - QVERIFY(!readWriteLock.tryLockForRead()); - testsTurn.release(); - - threadsTurn.acquire(); - QVERIFY(readWriteLock.tryLockForRead()); - lockCount.ref(); - QVERIFY(readWriteLock.tryLockForRead()); - lockCount.ref(); - lockCount.deref(); - readWriteLock.unlock(); - lockCount.deref(); - readWriteLock.unlock(); - testsTurn.release(); - - threadsTurn.acquire(); - QTime timer; - timer.start(); - QVERIFY(!readWriteLock.tryLockForRead(1000)); - QVERIFY(timer.elapsed() >= 1000); - testsTurn.release(); - - threadsTurn.acquire(); - timer.start(); - QVERIFY(readWriteLock.tryLockForRead(1000)); - QVERIFY(timer.elapsed() <= 1000); - lockCount.ref(); - QVERIFY(readWriteLock.tryLockForRead(1000)); - lockCount.ref(); - lockCount.deref(); - readWriteLock.unlock(); - lockCount.deref(); - readWriteLock.unlock(); - testsTurn.release(); - - threadsTurn.acquire(); - } - }; - - Thread thread; - thread.start(); - - testsTurn.acquire(); - readWriteLock.lockForWrite(); - QVERIFY(lockCount.testAndSetRelaxed(0, 1)); - threadsTurn.release(); - - testsTurn.acquire(); - QVERIFY(lockCount.testAndSetRelaxed(1, 0)); - readWriteLock.unlock(); - threadsTurn.release(); - - testsTurn.acquire(); - readWriteLock.lockForWrite(); - QVERIFY(lockCount.testAndSetRelaxed(0, 1)); - threadsTurn.release(); - - testsTurn.acquire(); - QVERIFY(lockCount.testAndSetRelaxed(1, 0)); - readWriteLock.unlock(); - threadsTurn.release(); - - // stop thread - testsTurn.acquire(); - threadsTurn.release(); - thread.wait(); - } -} - -void tst_QReadWriteLock::tryWriteLock() -{ - { - QReadWriteLock rwlock; - QVERIFY(rwlock.tryLockForWrite()); - rwlock.unlock(); - QVERIFY(rwlock.tryLockForWrite()); - rwlock.unlock(); - - rwlock.lockForWrite(); - QVERIFY(!rwlock.tryLockForWrite()); - QVERIFY(!rwlock.tryLockForWrite()); - rwlock.unlock(); - - rwlock.lockForRead(); - QVERIFY(!rwlock.tryLockForWrite()); - rwlock.unlock(); - } - - { - QReadWriteLock rwlock(QReadWriteLock::Recursive); - QVERIFY(rwlock.tryLockForWrite()); - rwlock.unlock(); - QVERIFY(rwlock.tryLockForWrite()); - rwlock.unlock(); - - rwlock.lockForWrite(); - QVERIFY(rwlock.tryLockForWrite()); - QVERIFY(rwlock.tryLockForWrite()); - rwlock.unlock(); - rwlock.unlock(); - rwlock.unlock(); - - rwlock.lockForRead(); - QVERIFY(!rwlock.tryLockForWrite()); - rwlock.unlock(); - } - - // functionality test - { - class Thread : public QThread - { - public: - Thread() : failureCount(0) { } - void run() - { - testsTurn.release(); - - threadsTurn.acquire(); - if (readWriteLock.tryLockForWrite()) - failureCount++; - testsTurn.release(); - - threadsTurn.acquire(); - if (!readWriteLock.tryLockForWrite()) - failureCount++; - if (!lockCount.testAndSetRelaxed(0, 1)) - failureCount++; - if (!lockCount.testAndSetRelaxed(1, 0)) - failureCount++; - readWriteLock.unlock(); - testsTurn.release(); - - threadsTurn.acquire(); - if (readWriteLock.tryLockForWrite(1000)) - failureCount++; - testsTurn.release(); - - threadsTurn.acquire(); - if (!readWriteLock.tryLockForWrite(1000)) - failureCount++; - if (!lockCount.testAndSetRelaxed(0, 1)) - failureCount++; - if (!lockCount.testAndSetRelaxed(1, 0)) - failureCount++; - readWriteLock.unlock(); - testsTurn.release(); - - threadsTurn.acquire(); - } - - int failureCount; - }; - - Thread thread; - thread.start(); - - testsTurn.acquire(); - readWriteLock.lockForRead(); - lockCount.ref(); - threadsTurn.release(); - - testsTurn.acquire(); - lockCount.deref(); - readWriteLock.unlock(); - threadsTurn.release(); - - testsTurn.acquire(); - readWriteLock.lockForRead(); - lockCount.ref(); - threadsTurn.release(); - - testsTurn.acquire(); - lockCount.deref(); - readWriteLock.unlock(); - threadsTurn.release(); - - // stop thread - testsTurn.acquire(); - threadsTurn.release(); - thread.wait(); - - QCOMPARE(thread.failureCount, 0); - } -} - -bool threadDone; -volatile bool release; - -/* - write-lock - unlock - set threadone -*/ -class WriteLockThread : public QThread -{ -public: - QReadWriteLock &testRwlock; - inline WriteLockThread(QReadWriteLock &l) : testRwlock(l) { } - void run() - { - testRwlock.lockForWrite(); - testRwlock.unlock(); - threadDone=true; - } -}; - -/* - read-lock - unlock - set threadone -*/ -class ReadLockThread : public QThread -{ -public: - QReadWriteLock &testRwlock; - inline ReadLockThread(QReadWriteLock &l) : testRwlock(l) { } - void run() - { - testRwlock.lockForRead(); - testRwlock.unlock(); - threadDone=true; - } -}; -/* - write-lock - wait for release==true - unlock -*/ -class WriteLockReleasableThread : public QThread -{ -public: - QReadWriteLock &testRwlock; - inline WriteLockReleasableThread(QReadWriteLock &l) : testRwlock(l) { } - void run() - { - testRwlock.lockForWrite(); - while(release==false) { - RWTESTSLEEP - } - testRwlock.unlock(); - } -}; - -/* - read-lock - wait for release==true - unlock -*/ -class ReadLockReleasableThread : public QThread -{ -public: - QReadWriteLock &testRwlock; - inline ReadLockReleasableThread(QReadWriteLock &l) : testRwlock(l) { } - void run() - { - testRwlock.lockForRead(); - while(release==false) { - RWTESTSLEEP - } - testRwlock.unlock(); - } -}; - - -/* - for(runTime msecs) - read-lock - msleep(holdTime msecs) - release lock - msleep(waitTime msecs) -*/ -class ReadLockLoopThread : public QThread -{ -public: - QReadWriteLock &testRwlock; - int runTime; - int holdTime; - int waitTime; - bool print; - QTime t; - inline ReadLockLoopThread(QReadWriteLock &l, int runTime, int holdTime=0, int waitTime=0, bool print=false) - :testRwlock(l) - ,runTime(runTime) - ,holdTime(holdTime) - ,waitTime(waitTime) - ,print(print) - { } - void run() - { - t.start(); - while (t.elapsed()<runTime) { - testRwlock.lockForRead(); - if(print) printf("reading\n"); - if (holdTime) msleep(holdTime); - testRwlock.unlock(); - if (waitTime) msleep(waitTime); - } - } -}; - -/* - for(runTime msecs) - write-lock - msleep(holdTime msecs) - release lock - msleep(waitTime msecs) -*/ -class WriteLockLoopThread : public QThread -{ -public: - QReadWriteLock &testRwlock; - int runTime; - int holdTime; - int waitTime; - bool print; - QTime t; - inline WriteLockLoopThread(QReadWriteLock &l, int runTime, int holdTime=0, int waitTime=0, bool print=false) - :testRwlock(l) - ,runTime(runTime) - ,holdTime(holdTime) - ,waitTime(waitTime) - ,print(print) - { } - void run() - { - t.start(); - while (t.elapsed() < runTime) { - testRwlock.lockForWrite(); - if (print) printf("."); - if (holdTime) msleep(holdTime); - testRwlock.unlock(); - if (waitTime) msleep(waitTime); - } - } -}; - -volatile int count=0; - -/* - for(runTime msecs) - write-lock - count to maxval - set count to 0 - release lock - msleep waitTime -*/ -class WriteLockCountThread : public QThread -{ -public: - QReadWriteLock &testRwlock; - int runTime; - int waitTime; - int maxval; - QTime t; - inline WriteLockCountThread(QReadWriteLock &l, int runTime, int waitTime, int maxval) - :testRwlock(l) - ,runTime(runTime) - ,waitTime(waitTime) - ,maxval(maxval) - { } - void run() - { - t.start(); - while (t.elapsed() < runTime) { - testRwlock.lockForWrite(); - if(count) - qFatal("Non-zero count at start of write! (%d)",count ); -// printf("."); - int i; - for(i=0; i<maxval; ++i) { - volatile int lc=count; - ++lc; - count=lc; - } - count=0; - testRwlock.unlock(); - msleep(waitTime); - } - } -}; - -/* - for(runTime msecs) - read-lock - verify count==0 - release lock - msleep waitTime -*/ -class ReadLockCountThread : public QThread -{ -public: - QReadWriteLock &testRwlock; - int runTime; - int waitTime; - QTime t; - inline ReadLockCountThread(QReadWriteLock &l, int runTime, int waitTime) - :testRwlock(l) - ,runTime(runTime) - ,waitTime(waitTime) - { } - void run() - { - t.start(); - while (t.elapsed() < runTime) { - testRwlock.lockForRead(); - if(count) - qFatal("Non-zero count at Read! (%d)",count ); - testRwlock.unlock(); - msleep(waitTime); - } - } -}; - - -/* - A writer acquires a read-lock, a reader locks - the writer releases the lock, the reader gets the lock -*/ -void tst_QReadWriteLock::readLockBlockRelease() -{ - QReadWriteLock testLock; - testLock.lockForWrite(); - threadDone=false; - ReadLockThread rlt(testLock); - rlt.start(); - sleep(1); - testLock.unlock(); - rlt.wait(); - QVERIFY(threadDone); -} - -/* - writer1 acquires a read-lock, writer2 blocks, - writer1 releases the lock, writer2 gets the lock -*/ -void tst_QReadWriteLock::writeLockBlockRelease() -{ - QReadWriteLock testLock; - testLock.lockForWrite(); - threadDone=false; - WriteLockThread wlt(testLock); - wlt.start(); - sleep(1); - testLock.unlock(); - wlt.wait(); - QVERIFY(threadDone); -} -/* - Two readers acquire a read-lock, one writer attempts a write block, - the readers release their locks, the writer gets the lock. -*/ -void tst_QReadWriteLock::multipleReadersBlockRelease() -{ - - QReadWriteLock testLock; - release=false; - threadDone=false; - ReadLockReleasableThread rlt1(testLock); - ReadLockReleasableThread rlt2(testLock); - rlt1.start(); - rlt2.start(); - sleep(1); - WriteLockThread wlt(testLock); - wlt.start(); - sleep(1); - release=true; - wlt.wait(); - rlt1.wait(); - rlt2.wait(); - QVERIFY(threadDone); -} - -/* - Multiple readers locks and unlocks a lock. -*/ -void tst_QReadWriteLock::multipleReadersLoop() -{ - int time=500; - int hold=250; - int wait=0; -#if defined (Q_OS_HPUX) - const int numthreads=50; -#elif defined(Q_OS_VXWORKS) - const int numthreads=40; -#else - const int numthreads=75; -#endif - QReadWriteLock testLock; - ReadLockLoopThread *threads[numthreads]; - int i; - for (i=0; i<numthreads; ++i) - threads[i] = new ReadLockLoopThread(testLock, time, hold, wait); - for (i=0; i<numthreads; ++i) - threads[i]->start(); - for (i=0; i<numthreads; ++i) - threads[i]->wait(); - for (i=0; i<numthreads; ++i) - delete threads[i]; -} - -/* - Multiple writers locks and unlocks a lock. -*/ -void tst_QReadWriteLock::multipleWritersLoop() -{ - int time=500; - int wait=0; - int hold=0; - const int numthreads=50; - QReadWriteLock testLock; - WriteLockLoopThread *threads[numthreads]; - int i; - for (i=0; i<numthreads; ++i) - threads[i] = new WriteLockLoopThread(testLock, time, hold, wait); - for (i=0; i<numthreads; ++i) - threads[i]->start(); - for (i=0; i<numthreads; ++i) - threads[i]->wait(); - for (i=0; i<numthreads; ++i) - delete threads[i]; -} - -/* - Multiple readers and writers locks and unlocks a lock. -*/ -void tst_QReadWriteLock::multipleReadersWritersLoop() -{ - //int time=INT_MAX; - int time=10000; - int readerThreads=20; - int readerWait=0; - int readerHold=1; - - int writerThreads=2; - int writerWait=500; - int writerHold=50; - - QReadWriteLock testLock; - ReadLockLoopThread *readers[1024]; - WriteLockLoopThread *writers[1024]; - int i; - - for (i=0; i<readerThreads; ++i) - readers[i] = new ReadLockLoopThread(testLock, time, readerHold, readerWait, false); - for (i=0; i<writerThreads; ++i) - writers[i] = new WriteLockLoopThread(testLock, time, writerHold, writerWait, false); - - for (i=0; i<readerThreads; ++i) - readers[i]->start(QThread::NormalPriority); - for (i=0; i<writerThreads; ++i) - writers[i]->start(QThread::IdlePriority); - - for (i=0; i<readerThreads; ++i) - readers[i]->wait(); - for (i=0; i<writerThreads; ++i) - writers[i]->wait(); - - for (i=0; i<readerThreads; ++i) - delete readers[i]; - for (i=0; i<writerThreads; ++i) - delete writers[i]; -} - -/* - Writers increment a variable from 0 to maxval, then reset it to 0. - Readers verify that the variable remains at 0. -*/ -void tst_QReadWriteLock::countingTest() -{ - //int time=INT_MAX; - int time=10000; - int readerThreads=20; - int readerWait=1; - - int writerThreads=3; - int writerWait=150; - int maxval=10000; - - QReadWriteLock testLock; - ReadLockCountThread *readers[1024]; - WriteLockCountThread *writers[1024]; - int i; - - for (i=0; i<readerThreads; ++i) - readers[i] = new ReadLockCountThread(testLock, time, readerWait); - for (i=0; i<writerThreads; ++i) - writers[i] = new WriteLockCountThread(testLock, time, writerWait, maxval); - - for (i=0; i<readerThreads; ++i) - readers[i]->start(QThread::NormalPriority); - for (i=0; i<writerThreads; ++i) - writers[i]->start(QThread::LowestPriority); - - for (i=0; i<readerThreads; ++i) - readers[i]->wait(); - for (i=0; i<writerThreads; ++i) - writers[i]->wait(); - - for (i=0; i<readerThreads; ++i) - delete readers[i]; - for (i=0; i<writerThreads; ++i) - delete writers[i]; -} - -void tst_QReadWriteLock::limitedReaders() -{ - -}; - -/* - Test a race-condition that may happen if one thread is in unlock() while - another thread deletes the rw-lock. - - MainThread DeleteOnUnlockThread - - write-lock - unlock - | write-lock - | unlock - | delete lock - deref d inside unlock -*/ -class DeleteOnUnlockThread : public QThread -{ -public: - DeleteOnUnlockThread(QReadWriteLock **lock, QWaitCondition *startup, QMutex *waitMutex) - :m_lock(lock), m_startup(startup), m_waitMutex(waitMutex) {} - void run() - { - m_waitMutex->lock(); - m_startup->wakeAll(); - m_waitMutex->unlock(); - - // DeleteOnUnlockThread and the main thread will race from this point - (*m_lock)->lockForWrite(); - (*m_lock)->unlock(); - delete *m_lock; - } -private: - QReadWriteLock **m_lock; - QWaitCondition *m_startup; - QMutex *m_waitMutex; -}; - -void tst_QReadWriteLock::deleteOnUnlock() -{ - QReadWriteLock *lock = 0; - QWaitCondition startup; - QMutex waitMutex; - - DeleteOnUnlockThread thread2(&lock, &startup, &waitMutex); - - QTime t; - t.start(); - while(t.elapsed() < 4000) { - lock = new QReadWriteLock(); - waitMutex.lock(); - lock->lockForWrite(); - thread2.start(); - startup.wait(&waitMutex); - waitMutex.unlock(); - - // DeleteOnUnlockThread and the main thread will race from this point - lock->unlock(); - - thread2.wait(); - } -} - - -void tst_QReadWriteLock::uncontendedLocks() -{ - - uint read=0; - uint write=0; - uint count=0; - int millisecs=1000; - { - QTime t; - t.start(); - while(t.elapsed() <millisecs) - { - ++count; - } - } - { - QReadWriteLock rwlock; - QTime t; - t.start(); - while(t.elapsed() <millisecs) - { - rwlock.lockForRead(); - rwlock.unlock(); - ++read; - } - } - { - QReadWriteLock rwlock; - QTime t; - t.start(); - while(t.elapsed() <millisecs) - { - rwlock.lockForWrite(); - rwlock.unlock(); - ++write; - } - } - - qDebug("during %d millisecs:", millisecs); - qDebug("counted to %u", count); - qDebug("%u uncontended read locks/unlocks", read); - qDebug("%u uncontended write locks/unlocks", write); -} - -enum { RecursiveLockCount = 10 }; - -void tst_QReadWriteLock::recursiveReadLock() -{ - // thread to attempt locking for writing while the test recursively locks for reading - class RecursiveReadLockThread : public QThread - { - public: - QReadWriteLock *lock; - bool tryLockForWriteResult; - - void run() - { - testsTurn.release(); - - // test is recursively locking for writing - for (int i = 0; i < RecursiveLockCount; ++i) { - threadsTurn.acquire(); - tryLockForWriteResult = lock->tryLockForWrite(); - testsTurn.release(); - } - - // test is releasing recursive write lock - for (int i = 0; i < RecursiveLockCount - 1; ++i) { - threadsTurn.acquire(); - tryLockForWriteResult = lock->tryLockForWrite(); - testsTurn.release(); - } - - // after final unlock in test, we should get the lock - threadsTurn.acquire(); - tryLockForWriteResult = lock->tryLockForWrite(); - testsTurn.release(); - - // cleanup - threadsTurn.acquire(); - lock->unlock(); - testsTurn.release(); - - // test will lockForRead(), then we will lockForWrite() - // (and block), purpose is to ensure that the test can - // recursive lockForRead() even with a waiting writer - threadsTurn.acquire(); - // testsTurn.release(); // ### do not release here, the test uses tryAcquire() - lock->lockForWrite(); - lock->unlock(); - } - }; - - // init - QReadWriteLock lock(QReadWriteLock::Recursive); - RecursiveReadLockThread thread; - thread.lock = &lock; - thread.start(); - - testsTurn.acquire(); - - // verify that we can get multiple read locks in the same thread - for (int i = 0; i < RecursiveLockCount; ++i) { - QVERIFY(lock.tryLockForRead()); - threadsTurn.release(); - - testsTurn.acquire(); - QVERIFY(!thread.tryLockForWriteResult); - } - - // have to unlock the same number of times that we locked - for (int i = 0;i < RecursiveLockCount - 1; ++i) { - lock.unlock(); - threadsTurn.release(); - - testsTurn.acquire(); - QVERIFY(!thread.tryLockForWriteResult); - } - - // after the final unlock, we should be able to get the write lock - lock.unlock(); - threadsTurn.release(); - - testsTurn.acquire(); - QVERIFY(thread.tryLockForWriteResult); - threadsTurn.release(); - - // check that recursive read locking works even when we have a waiting writer - testsTurn.acquire(); - QVERIFY(lock.tryLockForRead()); - threadsTurn.release(); - - testsTurn.tryAcquire(1, 1000); - QVERIFY(lock.tryLockForRead()); - lock.unlock(); - lock.unlock(); - - // cleanup - QVERIFY(thread.wait()); -} - -void tst_QReadWriteLock::recursiveWriteLock() -{ - // thread to attempt locking for reading while the test recursively locks for writing - class RecursiveWriteLockThread : public QThread - { - public: - QReadWriteLock *lock; - bool tryLockForReadResult; - - void run() - { - testsTurn.release(); - - // test is recursively locking for writing - for (int i = 0; i < RecursiveLockCount; ++i) { - threadsTurn.acquire(); - tryLockForReadResult = lock->tryLockForRead(); - testsTurn.release(); - } - - // test is releasing recursive write lock - for (int i = 0; i < RecursiveLockCount - 1; ++i) { - threadsTurn.acquire(); - tryLockForReadResult = lock->tryLockForRead(); - testsTurn.release(); - } - - // after final unlock in test, we should get the lock - threadsTurn.acquire(); - tryLockForReadResult = lock->tryLockForRead(); - testsTurn.release(); - - // cleanup - lock->unlock(); - } - }; - - // init - QReadWriteLock lock(QReadWriteLock::Recursive); - RecursiveWriteLockThread thread; - thread.lock = &lock; - thread.start(); - - testsTurn.acquire(); - - // verify that we can get multiple read locks in the same thread - for (int i = 0; i < RecursiveLockCount; ++i) { - QVERIFY(lock.tryLockForWrite()); - threadsTurn.release(); - - testsTurn.acquire(); - QVERIFY(!thread.tryLockForReadResult); - } - - // have to unlock the same number of times that we locked - for (int i = 0;i < RecursiveLockCount - 1; ++i) { - lock.unlock(); - threadsTurn.release(); - - testsTurn.acquire(); - QVERIFY(!thread.tryLockForReadResult); - } - - // after the final unlock, thread should be able to get the read lock - lock.unlock(); - threadsTurn.release(); - - testsTurn.acquire(); - QVERIFY(thread.tryLockForReadResult); - - // cleanup - QVERIFY(thread.wait()); -} - -QTEST_MAIN(tst_QReadWriteLock) - -#include "tst_qreadwritelock.moc" |