summaryrefslogtreecommitdiffstats
path: root/tests/auto/qreadwritelock
diff options
context:
space:
mode:
authorHolger Ihrig <holger.ihrig@nokia.com>2011-08-26 12:56:14 +0200
committerHolger Ihrig <holger.ihrig@nokia.com>2011-09-01 12:54:58 +0200
commit82e715b2770258fa2c536aeae1f46c7fccdcdecf (patch)
treea4b9135effe2109b164f622314a6ffac6198a8f8 /tests/auto/qreadwritelock
parentc9a5ccb268b5e2b2ce0743989c44f808b538ba9b (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/.gitignore1
-rw-r--r--tests/auto/qreadwritelock/qreadwritelock.pro4
-rw-r--r--tests/auto/qreadwritelock/tst_qreadwritelock.cpp1140
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"