tests/auto/qwaitcondition/tst_qwaitcondition.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/auto/qwaitcondition/tst_qwaitcondition.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,845 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+#include <qcoreapplication.h>
+#include <qmutex.h>
+#include <qthread.h>
+#include <qwaitcondition.h>
+
+#if defined(Q_OS_SYMBIAN)
+// Symbian Open C has a bug that causes very short waits to fail sometimes
+#define COND_WAIT_TIME 50
+#else
+#define COND_WAIT_TIME 1
+#endif
+
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+class tst_QWaitCondition : public QObject
+{
+    Q_OBJECT
+
+public:
+    tst_QWaitCondition();
+
+private slots:
+    void wait_QMutex();
+    void wait_QReadWriteLock();
+    void wakeOne();
+    void wakeAll();
+    void wait_RaceCondition();
+};
+
+static const int iterations = 10;
+
+// Note: some tests rely on ThreadCount being multiple of 2
+#ifdef Q_OS_SOLARIS
+static const int ThreadCount = 4;
+#else
+static const int ThreadCount = 10;
+#endif
+
+tst_QWaitCondition::tst_QWaitCondition()
+
+{
+}
+
+class wait_QMutex_Thread_1 : public QThread
+{
+public:
+    QMutex mutex;
+    QWaitCondition cond;
+
+    inline wait_QMutex_Thread_1()
+    { }
+
+    void run()
+    {
+    mutex.lock();
+    cond.wakeOne();
+    cond.wait(&mutex);
+    mutex.unlock();
+    }
+};
+
+class wait_QMutex_Thread_2 : public QThread
+{
+public:
+    QWaitCondition started;
+
+    QMutex *mutex;
+    QWaitCondition *cond;
+
+    inline wait_QMutex_Thread_2()
+    : mutex(0), cond(0)
+    { }
+
+    void run()
+    {
+    mutex->lock();
+    started.wakeOne();
+    cond->wait(mutex);
+    mutex->unlock();
+    }
+};
+
+class wait_QReadWriteLock_Thread_1 : public QThread
+{
+public:
+    QReadWriteLock readWriteLock;
+    QWaitCondition cond;
+
+    inline wait_QReadWriteLock_Thread_1()
+    { }
+
+    void run()
+    {
+    readWriteLock.lockForWrite();
+    cond.wakeOne();
+    cond.wait(&readWriteLock);
+    readWriteLock.unlock();
+    }
+};
+
+class wait_QReadWriteLock_Thread_2 : public QThread
+{
+public:
+    QWaitCondition started;
+
+    QReadWriteLock *readWriteLock;
+    QWaitCondition *cond;
+
+    inline wait_QReadWriteLock_Thread_2()
+    : readWriteLock(0), cond(0)
+    { }
+
+    void run()
+    {
+    readWriteLock->lockForRead();
+    started.wakeOne();
+    cond->wait(readWriteLock);
+    readWriteLock->unlock();
+    }
+};
+
+void tst_QWaitCondition::wait_QMutex()
+{
+    int x;
+    for (int i = 0; i < iterations; ++i) {
+    {
+        QMutex mutex;
+        QWaitCondition cond;
+
+        mutex.lock();
+
+        cond.wakeOne();
+        QVERIFY(!cond.wait(&mutex, 1));
+
+        cond.wakeAll();
+        QVERIFY(!cond.wait(&mutex, 1));
+
+        mutex.unlock();
+    }
+
+    {
+        // test multiple threads waiting on separate wait conditions
+        wait_QMutex_Thread_1 thread[ThreadCount];
+
+        for (x = 0; x < ThreadCount; ++x) {
+        thread[x].mutex.lock();
+        thread[x].start();
+        // wait for thread to start
+        QVERIFY(thread[x].cond.wait(&thread[x].mutex, 1000));
+        thread[x].mutex.unlock();
+        }
+
+        for (x = 0; x < ThreadCount; ++x) {
+        QVERIFY(thread[x].isRunning());
+        QVERIFY(!thread[x].isFinished());
+        }
+
+        for (x = 0; x < ThreadCount; ++x) {
+        thread[x].mutex.lock();
+        thread[x].cond.wakeOne();
+        thread[x].mutex.unlock();
+        }
+
+        for (x = 0; x < ThreadCount; ++x) {
+        QVERIFY(thread[x].wait(1000));
+        }
+    }
+
+    {
+        // test multiple threads waiting on a wait condition
+        QMutex mutex;
+        QWaitCondition cond1, cond2;
+        wait_QMutex_Thread_2 thread[ThreadCount];
+
+        mutex.lock();
+        for (x = 0; x < ThreadCount; ++x) {
+        thread[x].mutex = &mutex;
+        thread[x].cond = (x < ThreadCount / 2) ? &cond1 : &cond2;
+        thread[x].start();
+        // wait for thread to start
+        QVERIFY(thread[x].started.wait(&mutex, 1000));
+        }
+        mutex.unlock();
+
+        for (x = 0; x < ThreadCount; ++x) {
+        QVERIFY(thread[x].isRunning());
+        QVERIFY(!thread[x].isFinished());
+        }
+
+        mutex.lock();
+        cond1.wakeAll();
+        cond2.wakeAll();
+        mutex.unlock();
+
+        for (x = 0; x < ThreadCount; ++x) {
+        QVERIFY(thread[x].wait(1000));
+        }
+    }
+    }
+}
+
+void tst_QWaitCondition::wait_QReadWriteLock()
+{
+    {
+        QReadWriteLock readWriteLock(QReadWriteLock::Recursive);
+        QWaitCondition waitCondition;
+
+        // ensure that the lockForRead is correctly restored
+        readWriteLock.lockForRead();
+
+        QVERIFY(!waitCondition.wait(&readWriteLock, 1));
+
+        QVERIFY(!readWriteLock.tryLockForWrite());
+        QVERIFY(readWriteLock.tryLockForRead());
+        readWriteLock.unlock();
+        QVERIFY(!readWriteLock.tryLockForWrite());
+        readWriteLock.unlock();
+
+        QVERIFY(readWriteLock.tryLockForWrite());
+        readWriteLock.unlock();
+    }
+
+    {
+        QReadWriteLock readWriteLock(QReadWriteLock::Recursive);
+        QWaitCondition waitCondition;
+
+        // ensure that the lockForWrite is correctly restored
+        readWriteLock.lockForWrite();
+
+        QVERIFY(!waitCondition.wait(&readWriteLock, 1));
+
+        QVERIFY(!readWriteLock.tryLockForRead());
+        QVERIFY(readWriteLock.tryLockForWrite());
+        readWriteLock.unlock();
+        QVERIFY(!readWriteLock.tryLockForRead());
+        readWriteLock.unlock();
+
+        QVERIFY(readWriteLock.tryLockForRead());
+        readWriteLock.unlock();
+    }
+
+
+    int x;
+    for (int i = 0; i < iterations; ++i) {
+    {
+        QReadWriteLock readWriteLock;
+        QWaitCondition waitCondition;
+
+        readWriteLock.lockForRead();
+
+        waitCondition.wakeOne();
+        QVERIFY(!waitCondition.wait(&readWriteLock, 1));
+
+        waitCondition.wakeAll();
+        QVERIFY(!waitCondition.wait(&readWriteLock, 1));
+
+        readWriteLock.unlock();
+    }
+
+    {
+        QReadWriteLock readWriteLock;
+        QWaitCondition waitCondition;
+
+        readWriteLock.lockForWrite();
+
+        waitCondition.wakeOne();
+        QVERIFY(!waitCondition.wait(&readWriteLock, 1));
+
+        waitCondition.wakeAll();
+        QVERIFY(!waitCondition.wait(&readWriteLock, 1));
+
+        readWriteLock.unlock();
+    }
+
+    {
+        // test multiple threads waiting on separate wait conditions
+        wait_QReadWriteLock_Thread_1 thread[ThreadCount];
+
+        for (x = 0; x < ThreadCount; ++x) {
+        thread[x].readWriteLock.lockForRead();
+        thread[x].start();
+        // wait for thread to start
+#if defined(Q_OS_SYMBIAN) && defined(Q_CC_WINSCW)
+        // Symbian emulator startup simultaneously with this thread causes additional delay
+        QVERIFY(thread[x].cond.wait(&thread[x].readWriteLock, 10000));
+#else
+        QVERIFY(thread[x].cond.wait(&thread[x].readWriteLock, 1000));
+#endif
+        thread[x].readWriteLock.unlock();
+        }
+
+        for (x = 0; x < ThreadCount; ++x) {
+        QVERIFY(thread[x].isRunning());
+        QVERIFY(!thread[x].isFinished());
+        }
+
+        for (x = 0; x < ThreadCount; ++x) {
+        thread[x].readWriteLock.lockForRead();
+        thread[x].cond.wakeOne();
+        thread[x].readWriteLock.unlock();
+        }
+
+        for (x = 0; x < ThreadCount; ++x) {
+        QVERIFY(thread[x].wait(1000));
+        }
+    }
+
+    {
+        // test multiple threads waiting on a wait condition
+        QReadWriteLock readWriteLock;
+        QWaitCondition cond1, cond2;
+        wait_QReadWriteLock_Thread_2 thread[ThreadCount];
+
+        readWriteLock.lockForWrite();
+        for (x = 0; x < ThreadCount; ++x) {
+        thread[x].readWriteLock = &readWriteLock;
+        thread[x].cond = (x < ThreadCount / 2) ? &cond1 : &cond2;
+        thread[x].start();
+        // wait for thread to start
+        QVERIFY(thread[x].started.wait(&readWriteLock, 1000));
+        }
+        readWriteLock.unlock();
+
+        for (x = 0; x < ThreadCount; ++x) {
+        QVERIFY(thread[x].isRunning());
+        QVERIFY(!thread[x].isFinished());
+        }
+
+        readWriteLock.lockForWrite();
+        cond1.wakeAll();
+        cond2.wakeAll();
+        readWriteLock.unlock();
+
+        for (x = 0; x < ThreadCount; ++x) {
+        QVERIFY(thread[x].wait(1000));
+        }
+    }
+    }
+
+}
+
+class wake_Thread : public QThread
+{
+public:
+    static int count;
+
+    QWaitCondition started;
+    QWaitCondition dummy;
+
+    QMutex *mutex;
+    QWaitCondition *cond;
+
+    inline wake_Thread()
+    : mutex(0), cond(0)
+    { }
+
+    static inline void sleep(ulong s)
+    { QThread::sleep(s); }
+
+    void run()
+    {
+    mutex->lock();
+    ++count;
+        dummy.wakeOne(); // this wakeup should be lost
+           started.wakeOne();
+        dummy.wakeAll(); // this one too
+    cond->wait(mutex);
+        --count;
+    mutex->unlock();
+    }
+};
+
+int wake_Thread::count = 0;
+
+class wake_Thread_2 : public QThread
+{
+public:
+    static int count;
+
+    QWaitCondition started;
+    QWaitCondition dummy;
+
+    QReadWriteLock *readWriteLock;
+    QWaitCondition *cond;
+
+    inline wake_Thread_2()
+    : readWriteLock(0), cond(0)
+    { }
+
+    static inline void sleep(ulong s)
+    { QThread::sleep(s); }
+
+    void run()
+    {
+    readWriteLock->lockForWrite();
+    ++count;
+        dummy.wakeOne(); // this wakeup should be lost
+        started.wakeOne();
+        dummy.wakeAll(); // this one too
+    cond->wait(readWriteLock);
+        --count;
+    readWriteLock->unlock();
+    }
+};
+
+int wake_Thread_2::count = 0;
+
+void tst_QWaitCondition::wakeOne()
+{
+    int x;
+    // wake up threads, one at a time
+    for (int i = 0; i < iterations; ++i) {
+    QMutex mutex;
+    QWaitCondition cond;
+
+    // QMutex
+    wake_Thread thread[ThreadCount];
+    bool thread_exited[ThreadCount];
+
+    mutex.lock();
+    for (x = 0; x < ThreadCount; ++x) {
+        thread[x].mutex = &mutex;
+        thread[x].cond = &cond;
+        thread_exited[x] = FALSE;
+        thread[x].start();
+        // wait for thread to start
+        QVERIFY(thread[x].started.wait(&mutex, 1000));
+        // make sure wakeups are not queued... if nothing is
+        // waiting at the time of the wakeup, nothing happens
+        QVERIFY(!thread[x].dummy.wait(&mutex, 1));
+    }
+    mutex.unlock();
+
+    QCOMPARE(wake_Thread::count, ThreadCount);
+
+    // wake up threads one at a time
+    for (x = 0; x < ThreadCount; ++x) {
+        mutex.lock();
+        cond.wakeOne();
+        QVERIFY(!cond.wait(&mutex, COND_WAIT_TIME));
+        QVERIFY(!thread[x].dummy.wait(&mutex, 1));
+        mutex.unlock();
+
+        int exited = 0;
+        for (int y = 0; y < ThreadCount; ++y) {
+            if (thread_exited[y])
+                        continue;
+            if (thread[y].wait(exited > 0 ? 3 : 1000)) {
+                thread_exited[y] = TRUE;
+                ++exited;
+            }
+        }
+
+        QCOMPARE(exited, 1);
+        QCOMPARE(wake_Thread::count, ThreadCount - (x + 1));
+    }
+
+    QCOMPARE(wake_Thread::count, 0);
+
+    // QReadWriteLock
+    QReadWriteLock readWriteLock;
+    wake_Thread_2 rwthread[ThreadCount];
+
+    readWriteLock.lockForWrite();
+    for (x = 0; x < ThreadCount; ++x) {
+        rwthread[x].readWriteLock = &readWriteLock;
+        rwthread[x].cond = &cond;
+        thread_exited[x] = FALSE;
+        rwthread[x].start();
+        // wait for thread to start
+        QVERIFY(rwthread[x].started.wait(&readWriteLock, 1000));
+        // make sure wakeups are not queued... if nothing is
+        // waiting at the time of the wakeup, nothing happens
+        QVERIFY(!rwthread[x].dummy.wait(&readWriteLock, 1));
+    }
+    readWriteLock.unlock();
+
+    QCOMPARE(wake_Thread_2::count, ThreadCount);
+
+    // wake up threads one at a time
+    for (x = 0; x < ThreadCount; ++x) {
+        readWriteLock.lockForWrite();
+        cond.wakeOne();
+        QVERIFY(!cond.wait(&readWriteLock, COND_WAIT_TIME));
+        QVERIFY(!rwthread[x].dummy.wait(&readWriteLock, 1));
+        readWriteLock.unlock();
+
+        int exited = 0;
+        for (int y = 0; y < ThreadCount; ++y) {
+            if (thread_exited[y])
+                        continue;
+            if (rwthread[y].wait(exited > 0 ? 3 : 1000)) {
+                thread_exited[y] = TRUE;
+                ++exited;
+            }
+        }
+
+        QCOMPARE(exited, 1);
+        QCOMPARE(wake_Thread_2::count, ThreadCount - (x + 1));
+    }
+
+    QCOMPARE(wake_Thread_2::count, 0);
+    }
+
+    // wake up threads, two at a time
+    for (int i = 0; i < iterations; ++i) {
+    QMutex mutex;
+    QWaitCondition cond;
+
+        // QMutex
+    wake_Thread thread[ThreadCount];
+    bool thread_exited[ThreadCount];
+
+    mutex.lock();
+    for (x = 0; x < ThreadCount; ++x) {
+        thread[x].mutex = &mutex;
+        thread[x].cond = &cond;
+        thread_exited[x] = FALSE;
+        thread[x].start();
+        // wait for thread to start
+        QVERIFY(thread[x].started.wait(&mutex, 1000));
+        // make sure wakeups are not queued... if nothing is
+        // waiting at the time of the wakeup, nothing happens
+        QVERIFY(!thread[x].dummy.wait(&mutex, 1));
+    }
+    mutex.unlock();
+
+    QCOMPARE(wake_Thread::count, ThreadCount);
+
+    // wake up threads one at a time
+    for (x = 0; x < ThreadCount; x += 2) {
+        mutex.lock();
+        cond.wakeOne();
+        cond.wakeOne();
+        QVERIFY(!cond.wait(&mutex, COND_WAIT_TIME));
+        QVERIFY(!thread[x].dummy.wait(&mutex, 1));
+        QVERIFY(!thread[x + 1].dummy.wait(&mutex, 1));
+        mutex.unlock();
+
+        int exited = 0;
+        for (int y = 0; y < ThreadCount; ++y) {
+            if (thread_exited[y])
+                        continue;
+            if (thread[y].wait(exited > 0 ? 3 : 1000)) {
+                thread_exited[y] = TRUE;
+                ++exited;
+            }
+        }
+
+        QCOMPARE(exited, 2);
+        QCOMPARE(wake_Thread::count, ThreadCount - (x + 2));
+    }
+
+    QCOMPARE(wake_Thread::count, 0);
+
+        // QReadWriteLock
+        QReadWriteLock readWriteLock;
+        wake_Thread_2 rwthread[ThreadCount];
+
+    readWriteLock.lockForWrite();
+    for (x = 0; x < ThreadCount; ++x) {
+        rwthread[x].readWriteLock = &readWriteLock;
+        rwthread[x].cond = &cond;
+        thread_exited[x] = FALSE;
+        rwthread[x].start();
+        // wait for thread to start
+        QVERIFY(rwthread[x].started.wait(&readWriteLock, 1000));
+        // make sure wakeups are not queued... if nothing is
+        // waiting at the time of the wakeup, nothing happens
+        QVERIFY(!rwthread[x].dummy.wait(&readWriteLock, 1));
+    }
+    readWriteLock.unlock();
+
+    QCOMPARE(wake_Thread_2::count, ThreadCount);
+
+    // wake up threads one at a time
+    for (x = 0; x < ThreadCount; x += 2) {
+        readWriteLock.lockForWrite();
+        cond.wakeOne();
+        cond.wakeOne();
+        QVERIFY(!cond.wait(&readWriteLock, COND_WAIT_TIME));
+        QVERIFY(!rwthread[x].dummy.wait(&readWriteLock, 1));
+        QVERIFY(!rwthread[x + 1].dummy.wait(&readWriteLock, 1));
+        readWriteLock.unlock();
+
+        int exited = 0;
+        for (int y = 0; y < ThreadCount; ++y) {
+            if (thread_exited[y])
+                        continue;
+            if (rwthread[y].wait(exited > 0 ? 3 : 1000)) {
+                thread_exited[y] = TRUE;
+                ++exited;
+            }
+        }
+
+        QCOMPARE(exited, 2);
+        QCOMPARE(wake_Thread_2::count, ThreadCount - (x + 2));
+    }
+
+    QCOMPARE(wake_Thread_2::count, 0);
+}
+}
+
+void tst_QWaitCondition::wakeAll()
+{
+    int x;
+    for (int i = 0; i < iterations; ++i) {
+    QMutex mutex;
+    QWaitCondition cond;
+
+    // QMutex
+    wake_Thread thread[ThreadCount];
+
+    mutex.lock();
+    for (x = 0; x < ThreadCount; ++x) {
+        thread[x].mutex = &mutex;
+        thread[x].cond = &cond;
+        thread[x].start();
+        // wait for thread to start
+        QVERIFY(thread[x].started.wait(&mutex, 1000));
+    }
+    mutex.unlock();
+
+    QCOMPARE(wake_Thread::count, ThreadCount);
+
+    // wake up all threads at once
+    mutex.lock();
+    cond.wakeAll();
+    QVERIFY(!cond.wait(&mutex, COND_WAIT_TIME));
+    mutex.unlock();
+
+    int exited = 0;
+    for (x = 0; x < ThreadCount; ++x) {
+        if (thread[x].wait(1000))
+        ++exited;
+    }
+
+    QCOMPARE(exited, ThreadCount);
+    QCOMPARE(wake_Thread::count, 0);
+
+    // QReadWriteLock
+    QReadWriteLock readWriteLock;
+    wake_Thread_2 rwthread[ThreadCount];
+
+    readWriteLock.lockForWrite();
+    for (x = 0; x < ThreadCount; ++x) {
+        rwthread[x].readWriteLock = &readWriteLock;
+        rwthread[x].cond = &cond;
+        rwthread[x].start();
+        // wait for thread to start
+        QVERIFY(rwthread[x].started.wait(&readWriteLock, 1000));
+    }
+    readWriteLock.unlock();
+
+    QCOMPARE(wake_Thread_2::count, ThreadCount);
+
+    // wake up all threads at once
+    readWriteLock.lockForWrite();
+    cond.wakeAll();
+    QVERIFY(!cond.wait(&readWriteLock, COND_WAIT_TIME));
+    readWriteLock.unlock();
+
+    exited = 0;
+    for (x = 0; x < ThreadCount; ++x) {
+        if (rwthread[x].wait(1000))
+        ++exited;
+    }
+
+    QCOMPARE(exited, ThreadCount);
+    QCOMPARE(wake_Thread_2::count, 0);
+    }
+}
+
+class wait_RaceConditionThread : public QThread
+{
+public:
+    wait_RaceConditionThread(QMutex *mutex, QWaitCondition *startup, QWaitCondition *waitCondition,
+                             ulong timeout = ULONG_MAX)
+        : timeout(timeout), returnValue(false), ready(false),
+          mutex(mutex), startup(startup), waitCondition(waitCondition) {}
+
+    unsigned long timeout;
+    bool returnValue;
+
+    bool ready;
+
+    QMutex *mutex;
+    QWaitCondition *startup;
+    QWaitCondition *waitCondition;
+
+    void run() {
+        mutex->lock();
+
+        ready = true;
+        startup->wakeOne();
+
+        returnValue = waitCondition->wait(mutex, timeout);
+
+        mutex->unlock();
+    }
+};
+
+class wait_RaceConditionThread_2 : public QThread
+{
+public:
+    wait_RaceConditionThread_2(QReadWriteLock *readWriteLock,
+                               QWaitCondition *startup,
+                               QWaitCondition *waitCondition,
+                               ulong timeout = ULONG_MAX)
+        : timeout(timeout), returnValue(false), ready(false),
+          readWriteLock(readWriteLock), startup(startup), waitCondition(waitCondition)
+    { }
+
+    unsigned long timeout;
+    bool returnValue;
+
+    bool ready;
+
+    QReadWriteLock *readWriteLock;
+    QWaitCondition *startup;
+    QWaitCondition *waitCondition;
+
+    void run() {
+        readWriteLock->lockForWrite();
+
+        ready = true;
+        startup->wakeOne();
+
+        returnValue = waitCondition->wait(readWriteLock, timeout);
+
+        readWriteLock->unlock();
+    }
+};
+
+void tst_QWaitCondition::wait_RaceCondition()
+{
+    {
+        QMutex mutex;
+        QWaitCondition startup;
+        QWaitCondition waitCondition;
+
+        wait_RaceConditionThread timeoutThread(&mutex, &startup, &waitCondition, 1000),
+            waitingThread1(&mutex, &startup, &waitCondition);
+
+        timeoutThread.start();
+        waitingThread1.start();
+        mutex.lock();
+
+        // wait for the threads to start up
+        while (!timeoutThread.ready
+               || !waitingThread1.ready) {
+            startup.wait(&mutex);
+        }
+
+        QTest::qWait(2000);
+
+        waitCondition.wakeOne();
+
+        mutex.unlock();
+
+        QVERIFY(timeoutThread.wait(5000));
+        QVERIFY(!timeoutThread.returnValue);
+        QVERIFY(waitingThread1.wait(5000));
+        QVERIFY(waitingThread1.returnValue);
+    }
+
+    {
+        QReadWriteLock readWriteLock;
+        QWaitCondition startup;
+        QWaitCondition waitCondition;
+
+        wait_RaceConditionThread_2 timeoutThread(&readWriteLock, &startup, &waitCondition, 1000),
+            waitingThread1(&readWriteLock, &startup, &waitCondition);
+
+        timeoutThread.start();
+        waitingThread1.start();
+        readWriteLock.lockForRead();
+
+        // wait for the threads to start up
+        while (!timeoutThread.ready
+               || !waitingThread1.ready) {
+            startup.wait(&readWriteLock);
+        }
+
+        QTest::qWait(2000);
+
+        waitCondition.wakeOne();
+
+        readWriteLock.unlock();
+
+        QVERIFY(timeoutThread.wait(5000));
+        QVERIFY(!timeoutThread.returnValue);
+        QVERIFY(waitingThread1.wait(5000));
+        QVERIFY(waitingThread1.returnValue);
+    }
+}
+
+QTEST_MAIN(tst_QWaitCondition)
+#include "tst_qwaitcondition.moc"