From 82e715b2770258fa2c536aeae1f46c7fccdcdecf Mon Sep 17 00:00:00 2001 From: Holger Ihrig Date: Fri, 26 Aug 2011 12:56:14 +0200 Subject: 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 Reviewed-by: Rohan McGovern Reviewed-by: Jason McDonald --- tests/auto/corelib.pro | 12 - tests/auto/corelib/corelib.pro | 3 +- tests/auto/corelib/thread/qatomicint/.gitignore | 1 + .../auto/corelib/thread/qatomicint/qatomicint.pro | 4 + .../corelib/thread/qatomicint/tst_qatomicint.cpp | 791 +++++++++++++ .../auto/corelib/thread/qatomicpointer/.gitignore | 1 + .../thread/qatomicpointer/qatomicpointer.pro | 4 + .../thread/qatomicpointer/tst_qatomicpointer.cpp | 674 +++++++++++ tests/auto/corelib/thread/qmutex/.gitignore | 1 + tests/auto/corelib/thread/qmutex/qmutex.pro | 5 + tests/auto/corelib/thread/qmutex/tst_qmutex.cpp | 640 ++++++++++ tests/auto/corelib/thread/qmutexlocker/.gitignore | 1 + .../corelib/thread/qmutexlocker/qmutexlocker.pro | 4 + .../thread/qmutexlocker/tst_qmutexlocker.cpp | 236 ++++ tests/auto/corelib/thread/qreadlocker/.gitignore | 1 + .../corelib/thread/qreadlocker/qreadlocker.pro | 4 + .../corelib/thread/qreadlocker/tst_qreadlocker.cpp | 231 ++++ .../auto/corelib/thread/qreadwritelock/.gitignore | 1 + .../thread/qreadwritelock/qreadwritelock.pro | 4 + .../thread/qreadwritelock/tst_qreadwritelock.cpp | 1140 ++++++++++++++++++ tests/auto/corelib/thread/qsemaphore/.gitignore | 1 + .../auto/corelib/thread/qsemaphore/qsemaphore.pro | 7 + .../corelib/thread/qsemaphore/tst_qsemaphore.cpp | 450 +++++++ tests/auto/corelib/thread/qthread/.gitignore | 1 + tests/auto/corelib/thread/qthread/qthread.pro | 5 + tests/auto/corelib/thread/qthread/tst_qthread.cpp | 1249 ++++++++++++++++++++ tests/auto/corelib/thread/qthreadonce/.gitignore | 1 + .../corelib/thread/qthreadonce/qthreadonce.cpp | 121 ++ .../auto/corelib/thread/qthreadonce/qthreadonce.h | 114 ++ .../corelib/thread/qthreadonce/qthreadonce.pro | 13 + .../corelib/thread/qthreadonce/tst_qthreadonce.cpp | 234 ++++ .../auto/corelib/thread/qthreadstorage/.gitignore | 1 + .../corelib/thread/qthreadstorage/crashOnExit.cpp | 64 + .../corelib/thread/qthreadstorage/crashOnExit.pro | 4 + .../thread/qthreadstorage/qthreadstorage.pro | 5 + .../thread/qthreadstorage/tst_qthreadstorage.cpp | 503 ++++++++ .../thread/qthreadstorage/tst_qthreadstorage.pro | 4 + .../auto/corelib/thread/qwaitcondition/.gitignore | 1 + .../thread/qwaitcondition/qwaitcondition.pro | 6 + .../thread/qwaitcondition/tst_qwaitcondition.cpp | 845 +++++++++++++ tests/auto/corelib/thread/qwritelocker/.gitignore | 1 + .../corelib/thread/qwritelocker/qwritelocker.pro | 4 + .../thread/qwritelocker/tst_qwritelocker.cpp | 231 ++++ tests/auto/corelib/thread/thread.pro | 14 + tests/auto/qatomicint/.gitignore | 1 - tests/auto/qatomicint/qatomicint.pro | 4 - tests/auto/qatomicint/tst_qatomicint.cpp | 791 ------------- tests/auto/qatomicpointer/.gitignore | 1 - tests/auto/qatomicpointer/qatomicpointer.pro | 4 - tests/auto/qatomicpointer/tst_qatomicpointer.cpp | 674 ----------- tests/auto/qmutex/.gitignore | 1 - tests/auto/qmutex/qmutex.pro | 5 - tests/auto/qmutex/tst_qmutex.cpp | 640 ---------- tests/auto/qmutexlocker/.gitignore | 1 - tests/auto/qmutexlocker/qmutexlocker.pro | 4 - tests/auto/qmutexlocker/tst_qmutexlocker.cpp | 236 ---- tests/auto/qreadlocker/.gitignore | 1 - tests/auto/qreadlocker/qreadlocker.pro | 4 - tests/auto/qreadlocker/tst_qreadlocker.cpp | 231 ---- tests/auto/qreadwritelock/.gitignore | 1 - tests/auto/qreadwritelock/qreadwritelock.pro | 4 - tests/auto/qreadwritelock/tst_qreadwritelock.cpp | 1140 ------------------ tests/auto/qsemaphore/.gitignore | 1 - tests/auto/qsemaphore/qsemaphore.pro | 7 - tests/auto/qsemaphore/tst_qsemaphore.cpp | 450 ------- tests/auto/qthread/.gitignore | 1 - tests/auto/qthread/qthread.pro | 5 - tests/auto/qthread/tst_qthread.cpp | 1249 -------------------- tests/auto/qthreadonce/.gitignore | 1 - tests/auto/qthreadonce/qthreadonce.cpp | 121 -- tests/auto/qthreadonce/qthreadonce.h | 114 -- tests/auto/qthreadonce/qthreadonce.pro | 13 - tests/auto/qthreadonce/tst_qthreadonce.cpp | 234 ---- tests/auto/qthreadstorage/.gitignore | 1 - tests/auto/qthreadstorage/crashOnExit.cpp | 64 - tests/auto/qthreadstorage/crashOnExit.pro | 4 - tests/auto/qthreadstorage/qthreadstorage.pro | 5 - tests/auto/qthreadstorage/tst_qthreadstorage.cpp | 503 -------- tests/auto/qthreadstorage/tst_qthreadstorage.pro | 4 - tests/auto/qwaitcondition/.gitignore | 1 - tests/auto/qwaitcondition/qwaitcondition.pro | 6 - tests/auto/qwaitcondition/tst_qwaitcondition.cpp | 845 ------------- tests/auto/qwritelocker/.gitignore | 1 - tests/auto/qwritelocker/qwritelocker.pro | 4 - tests/auto/qwritelocker/tst_qwritelocker.cpp | 231 ---- 85 files changed, 7624 insertions(+), 7621 deletions(-) create mode 100644 tests/auto/corelib/thread/qatomicint/.gitignore create mode 100644 tests/auto/corelib/thread/qatomicint/qatomicint.pro create mode 100644 tests/auto/corelib/thread/qatomicint/tst_qatomicint.cpp create mode 100644 tests/auto/corelib/thread/qatomicpointer/.gitignore create mode 100644 tests/auto/corelib/thread/qatomicpointer/qatomicpointer.pro create mode 100644 tests/auto/corelib/thread/qatomicpointer/tst_qatomicpointer.cpp create mode 100644 tests/auto/corelib/thread/qmutex/.gitignore create mode 100644 tests/auto/corelib/thread/qmutex/qmutex.pro create mode 100644 tests/auto/corelib/thread/qmutex/tst_qmutex.cpp create mode 100644 tests/auto/corelib/thread/qmutexlocker/.gitignore create mode 100644 tests/auto/corelib/thread/qmutexlocker/qmutexlocker.pro create mode 100644 tests/auto/corelib/thread/qmutexlocker/tst_qmutexlocker.cpp create mode 100644 tests/auto/corelib/thread/qreadlocker/.gitignore create mode 100644 tests/auto/corelib/thread/qreadlocker/qreadlocker.pro create mode 100644 tests/auto/corelib/thread/qreadlocker/tst_qreadlocker.cpp create mode 100644 tests/auto/corelib/thread/qreadwritelock/.gitignore create mode 100644 tests/auto/corelib/thread/qreadwritelock/qreadwritelock.pro create mode 100644 tests/auto/corelib/thread/qreadwritelock/tst_qreadwritelock.cpp create mode 100644 tests/auto/corelib/thread/qsemaphore/.gitignore create mode 100644 tests/auto/corelib/thread/qsemaphore/qsemaphore.pro create mode 100644 tests/auto/corelib/thread/qsemaphore/tst_qsemaphore.cpp create mode 100644 tests/auto/corelib/thread/qthread/.gitignore create mode 100644 tests/auto/corelib/thread/qthread/qthread.pro create mode 100644 tests/auto/corelib/thread/qthread/tst_qthread.cpp create mode 100644 tests/auto/corelib/thread/qthreadonce/.gitignore create mode 100644 tests/auto/corelib/thread/qthreadonce/qthreadonce.cpp create mode 100644 tests/auto/corelib/thread/qthreadonce/qthreadonce.h create mode 100644 tests/auto/corelib/thread/qthreadonce/qthreadonce.pro create mode 100644 tests/auto/corelib/thread/qthreadonce/tst_qthreadonce.cpp create mode 100644 tests/auto/corelib/thread/qthreadstorage/.gitignore create mode 100644 tests/auto/corelib/thread/qthreadstorage/crashOnExit.cpp create mode 100644 tests/auto/corelib/thread/qthreadstorage/crashOnExit.pro create mode 100644 tests/auto/corelib/thread/qthreadstorage/qthreadstorage.pro create mode 100644 tests/auto/corelib/thread/qthreadstorage/tst_qthreadstorage.cpp create mode 100644 tests/auto/corelib/thread/qthreadstorage/tst_qthreadstorage.pro create mode 100644 tests/auto/corelib/thread/qwaitcondition/.gitignore create mode 100644 tests/auto/corelib/thread/qwaitcondition/qwaitcondition.pro create mode 100644 tests/auto/corelib/thread/qwaitcondition/tst_qwaitcondition.cpp create mode 100644 tests/auto/corelib/thread/qwritelocker/.gitignore create mode 100644 tests/auto/corelib/thread/qwritelocker/qwritelocker.pro create mode 100644 tests/auto/corelib/thread/qwritelocker/tst_qwritelocker.cpp create mode 100644 tests/auto/corelib/thread/thread.pro delete mode 100644 tests/auto/qatomicint/.gitignore delete mode 100644 tests/auto/qatomicint/qatomicint.pro delete mode 100644 tests/auto/qatomicint/tst_qatomicint.cpp delete mode 100644 tests/auto/qatomicpointer/.gitignore delete mode 100644 tests/auto/qatomicpointer/qatomicpointer.pro delete mode 100644 tests/auto/qatomicpointer/tst_qatomicpointer.cpp delete mode 100644 tests/auto/qmutex/.gitignore delete mode 100644 tests/auto/qmutex/qmutex.pro delete mode 100644 tests/auto/qmutex/tst_qmutex.cpp delete mode 100644 tests/auto/qmutexlocker/.gitignore delete mode 100644 tests/auto/qmutexlocker/qmutexlocker.pro delete mode 100644 tests/auto/qmutexlocker/tst_qmutexlocker.cpp delete mode 100644 tests/auto/qreadlocker/.gitignore delete mode 100644 tests/auto/qreadlocker/qreadlocker.pro delete mode 100644 tests/auto/qreadlocker/tst_qreadlocker.cpp delete mode 100644 tests/auto/qreadwritelock/.gitignore delete mode 100644 tests/auto/qreadwritelock/qreadwritelock.pro delete mode 100644 tests/auto/qreadwritelock/tst_qreadwritelock.cpp delete mode 100644 tests/auto/qsemaphore/.gitignore delete mode 100644 tests/auto/qsemaphore/qsemaphore.pro delete mode 100644 tests/auto/qsemaphore/tst_qsemaphore.cpp delete mode 100644 tests/auto/qthread/.gitignore delete mode 100644 tests/auto/qthread/qthread.pro delete mode 100644 tests/auto/qthread/tst_qthread.cpp delete mode 100644 tests/auto/qthreadonce/.gitignore delete mode 100644 tests/auto/qthreadonce/qthreadonce.cpp delete mode 100644 tests/auto/qthreadonce/qthreadonce.h delete mode 100644 tests/auto/qthreadonce/qthreadonce.pro delete mode 100644 tests/auto/qthreadonce/tst_qthreadonce.cpp delete mode 100644 tests/auto/qthreadstorage/.gitignore delete mode 100644 tests/auto/qthreadstorage/crashOnExit.cpp delete mode 100644 tests/auto/qthreadstorage/crashOnExit.pro delete mode 100644 tests/auto/qthreadstorage/qthreadstorage.pro delete mode 100644 tests/auto/qthreadstorage/tst_qthreadstorage.cpp delete mode 100644 tests/auto/qthreadstorage/tst_qthreadstorage.pro delete mode 100644 tests/auto/qwaitcondition/.gitignore delete mode 100644 tests/auto/qwaitcondition/qwaitcondition.pro delete mode 100644 tests/auto/qwaitcondition/tst_qwaitcondition.cpp delete mode 100644 tests/auto/qwritelocker/.gitignore delete mode 100644 tests/auto/qwritelocker/qwritelocker.pro delete mode 100644 tests/auto/qwritelocker/tst_qwritelocker.cpp diff --git a/tests/auto/corelib.pro b/tests/auto/corelib.pro index f3b78c6e85..1467db7287 100644 --- a/tests/auto/corelib.pro +++ b/tests/auto/corelib.pro @@ -3,8 +3,6 @@ SUBDIRS=\ corelib \ collections \ exceptionsafety \ - qatomicint \ - qatomicpointer \ qbitarray \ qbytearray \ qbytearraymatcher \ @@ -22,19 +20,14 @@ SUBDIRS=\ qline \ qmap \ qmargins \ - qmutex \ - qmutexlocker \ qobjectrace \ qpoint \ qqueue \ - qreadlocker \ - qreadwritelock \ qrect \ qregexp \ qringbuffer \ qscopedpointer \ qscopedvaluerollback \ - qsemaphore \ qset \ qsharedpointer \ qsignalspy \ @@ -50,16 +43,11 @@ SUBDIRS=\ qstringmatcher \ qstringref \ qtextboundaryfinder \ - qthread \ - qthreadonce \ - qthreadstorage \ qtime \ qtimeline \ qtmd5 \ qtokenautomaton \ qvarlengtharray \ qvector \ - qwaitcondition \ - qwritelocker \ selftests \ utf8 diff --git a/tests/auto/corelib/corelib.pro b/tests/auto/corelib/corelib.pro index 03a7035af0..62532b968f 100644 --- a/tests/auto/corelib/corelib.pro +++ b/tests/auto/corelib/corelib.pro @@ -7,4 +7,5 @@ SUBDIRS=\ io \ kernel \ plugin \ - statemachine + statemachine \ + thread diff --git a/tests/auto/corelib/thread/qatomicint/.gitignore b/tests/auto/corelib/thread/qatomicint/.gitignore new file mode 100644 index 0000000000..52998efd02 --- /dev/null +++ b/tests/auto/corelib/thread/qatomicint/.gitignore @@ -0,0 +1 @@ +tst_qatomicint diff --git a/tests/auto/corelib/thread/qatomicint/qatomicint.pro b/tests/auto/corelib/thread/qatomicint/qatomicint.pro new file mode 100644 index 0000000000..7850d93dc7 --- /dev/null +++ b/tests/auto/corelib/thread/qatomicint/qatomicint.pro @@ -0,0 +1,4 @@ +load(qttest_p4) +SOURCES += tst_qatomicint.cpp +QT = core +CONFIG += parallel_test diff --git a/tests/auto/corelib/thread/qatomicint/tst_qatomicint.cpp b/tests/auto/corelib/thread/qatomicint/tst_qatomicint.cpp new file mode 100644 index 0000000000..27a2cc2e9c --- /dev/null +++ b/tests/auto/corelib/thread/qatomicint/tst_qatomicint.cpp @@ -0,0 +1,791 @@ +/**************************************************************************** +** +** 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 + +#include +#include + +#include + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QAtomicInt : public QObject +{ + Q_OBJECT + +public: + tst_QAtomicInt(); + ~tst_QAtomicInt(); + +private slots: + void warningFree(); + + // QAtomicInt members + void constructor_data(); + void constructor(); + void copy_constructor_data(); + void copy_constructor(); + void equality_operator_data(); + void equality_operator(); + void inequality_operator_data(); + void inequality_operator(); + void not_operator_data(); + void not_operator(); + void cast_operator_data(); + void cast_operator(); + void assignment_operator_data(); + void assignment_operator(); + + void isReferenceCountingNative(); + void isReferenceCountingWaitFree(); + void ref_data(); + void ref(); + void deref_data(); + void deref(); + + void isTestAndSetNative(); + void isTestAndSetWaitFree(); + void testAndSet_data(); + void testAndSet(); + + void isFetchAndStoreNative(); + void isFetchAndStoreWaitFree(); + void fetchAndStore_data(); + void fetchAndStore(); + + void isFetchAndAddNative(); + void isFetchAndAddWaitFree(); + void fetchAndAdd_data(); + void fetchAndAdd(); + + // stress tests + void testAndSet_loop(); + void fetchAndAdd_loop(); + void fetchAndAdd_threadedLoop(); + +private: + static void warningFreeHelper(); +}; + +tst_QAtomicInt::tst_QAtomicInt() +{ } + +tst_QAtomicInt::~tst_QAtomicInt() +{ } + +void tst_QAtomicInt::warningFreeHelper() +{ + qFatal("This code is bogus, and shouldn't be run. We're looking for compiler warnings only."); + + QBasicAtomicInt i = Q_BASIC_ATOMIC_INITIALIZER(0); + + int expectedValue = 0; + int newValue = 0; + int valueToAdd = 0; + + i.ref(); + i.deref(); + + i.testAndSetRelaxed(expectedValue, newValue); + i.testAndSetAcquire(expectedValue, newValue); + i.testAndSetRelease(expectedValue, newValue); + i.testAndSetOrdered(expectedValue, newValue); + + i.fetchAndStoreRelaxed(newValue); + i.fetchAndStoreAcquire(newValue); + i.fetchAndStoreRelease(newValue); + i.fetchAndStoreOrdered(newValue); + + i.fetchAndAddRelaxed(valueToAdd); + i.fetchAndAddAcquire(valueToAdd); + i.fetchAndAddRelease(valueToAdd); + i.fetchAndAddOrdered(valueToAdd); +} + +void tst_QAtomicInt::warningFree() +{ + // This is a compile time check for warnings. + // No need for actual work here. + + void (*foo)() = &warningFreeHelper; + (void)foo; +} + +void tst_QAtomicInt::constructor_data() +{ + QTest::addColumn("value"); + + QTest::newRow("0") << 31337; + QTest::newRow("1") << 0; + QTest::newRow("2") << 1; + QTest::newRow("3") << -1; + QTest::newRow("4") << 2; + QTest::newRow("5") << -2; + QTest::newRow("6") << 3; + QTest::newRow("7") << -3; + QTest::newRow("8") << INT_MAX; + QTest::newRow("9") << INT_MIN+1; +} + +void tst_QAtomicInt::constructor() +{ + QFETCH(int, value); + QAtomicInt atomic1(value); + QCOMPARE(int(atomic1), value); + QAtomicInt atomic2 = value; + QCOMPARE(int(atomic2), value); +} + +void tst_QAtomicInt::copy_constructor_data() +{ constructor_data(); } + +void tst_QAtomicInt::copy_constructor() +{ + QFETCH(int, value); + QAtomicInt atomic1(value); + QCOMPARE(int(atomic1), value); + + QAtomicInt atomic2(atomic1); + QCOMPARE(int(atomic2), value); + QAtomicInt atomic3 = atomic1; + QCOMPARE(int(atomic3), value); + QAtomicInt atomic4(atomic2); + QCOMPARE(int(atomic4), value); + QAtomicInt atomic5 = atomic2; + QCOMPARE(int(atomic5), value); +} + +void tst_QAtomicInt::equality_operator_data() +{ + QTest::addColumn("value1"); + QTest::addColumn("value2"); + QTest::addColumn("result"); + + QTest::newRow("success0") << 1 << 1 << 1; + QTest::newRow("success1") << -1 << -1 << 1; + QTest::newRow("failure0") << 0 << 1 << 0; + QTest::newRow("failure1") << 1 << 0 << 0; + QTest::newRow("failure2") << 0 << -1 << 0; + QTest::newRow("failure3") << -1 << 0 << 0; +} + +void tst_QAtomicInt::equality_operator() +{ + QFETCH(int, value1); + QFETCH(int, value2); + QAtomicInt x = value1; + QTEST(x == value2 ? 1 : 0, "result"); +} + +void tst_QAtomicInt::inequality_operator_data() +{ + QTest::addColumn("value1"); + QTest::addColumn("value2"); + QTest::addColumn("result"); + + QTest::newRow("failure0") << 1 << 1 << 0; + QTest::newRow("failure1") << -1 << -1 << 0; + QTest::newRow("success0") << 0 << 1 << 1; + QTest::newRow("success1") << 1 << 0 << 1; + QTest::newRow("success2") << 0 << -1 << 1; + QTest::newRow("success3") << -1 << 0 << 1; +} + +void tst_QAtomicInt::inequality_operator() +{ + QFETCH(int, value1); + QFETCH(int, value2); + QAtomicInt x = value1; + QTEST(x != value2 ? 1 : 0, "result"); +} + +void tst_QAtomicInt::not_operator_data() +{ constructor_data(); } + +void tst_QAtomicInt::not_operator() +{ + QFETCH(int, value); + QAtomicInt atomic = value; + QCOMPARE(!atomic, !value); +} + +void tst_QAtomicInt::cast_operator_data() +{ constructor_data(); } + +void tst_QAtomicInt::cast_operator() +{ + QFETCH(int, value); + QAtomicInt atomic = value; + int copy = atomic; + QCOMPARE(copy, value); +} + +void tst_QAtomicInt::assignment_operator_data() +{ + QTest::addColumn("value"); + QTest::addColumn("newval"); + + QTest::newRow("value0") << 0 << 1; + QTest::newRow("value1") << 1 << 0; + QTest::newRow("value2") << 0 << -1; + QTest::newRow("value3") << -1 << 0; + QTest::newRow("value4") << -1 << 1; + QTest::newRow("value5") << 1 << -1; +} + +void tst_QAtomicInt::assignment_operator() +{ + QFETCH(int, value); + QFETCH(int, newval); + + { + QAtomicInt atomic1 = value; + atomic1 = newval; + QCOMPARE(int(atomic1), newval); + atomic1 = value; + QCOMPARE(int(atomic1), value); + QAtomicInt atomic2 = newval; + atomic1 = atomic2; + QCOMPARE(atomic1, atomic2); + } +} + +void tst_QAtomicInt::isReferenceCountingNative() +{ +#if defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE) + // the runtime test should say the same thing + QVERIFY(QAtomicInt::isReferenceCountingNative()); + +# if (defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_SOMETIMES_NATIVE) \ + || defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NOT_NATIVE)) +# error "Define only one of Q_ATOMIC_INT_REFERENCE_COUNTING_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" +# endif +#elif defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_SOMETIMES_NATIVE) + // could be either, just want to make sure the function is implemented + QVERIFY(QAtomicInt::isReferenceCountingNative() || !QAtomicInt::isReferenceCountingNative()); + +# if (defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE) \ + || defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NOT_NATIVE)) +# error "Define only one of Q_ATOMIC_INT_REFERENCE_COUNTING_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" +# endif +#elif defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NOT_NATIVE) + // the runtime test should say the same thing + QVERIFY(!QAtomicInt::isReferenceCountingNative()); + +# if (defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE) \ + || defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_SOMETIMES_NATIVE)) +# error "Define only one of Q_ATOMIC_INT_REFERENCE_COUNTING_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" +# endif +#else +# error "Q_ATOMIC_INT_REFERENCE_COUNTING_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE is not defined" +#endif +} + +void tst_QAtomicInt::isReferenceCountingWaitFree() +{ +#if defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_WAIT_FREE) + // the runtime test should say the same thing + QVERIFY(QAtomicInt::isReferenceCountingWaitFree()); + + // enforce some invariants + QVERIFY(QAtomicInt::isReferenceCountingNative()); +# if defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NOT_NATIVE) +# error "Reference counting cannot be wait-free and unsupported at the same time!" +# endif +#else + // the runtime test should say the same thing + QVERIFY(!QAtomicInt::isReferenceCountingWaitFree()); +#endif +} + +void tst_QAtomicInt::ref_data() +{ + QTest::addColumn("value"); + QTest::addColumn("result"); + QTest::addColumn("expected"); + + QTest::newRow("data0") << 0 << 1 << 1; + QTest::newRow("data1") << -1 << 0 << 0; + QTest::newRow("data2") << 1 << 1 << 2; +} + +void tst_QAtomicInt::ref() +{ + QFETCH(int, value); + QAtomicInt x = value; + QTEST(x.ref() ? 1 : 0, "result"); + QTEST(int(x), "expected"); +} + +void tst_QAtomicInt::deref_data() +{ + QTest::addColumn("value"); + QTest::addColumn("result"); + QTest::addColumn("expected"); + + QTest::newRow("data0") << 0 << 1 << -1; + QTest::newRow("data1") << 1 << 0 << 0; + QTest::newRow("data2") << 2 << 1 << 1; +} + +void tst_QAtomicInt::deref() +{ + QFETCH(int, value); + QAtomicInt x = value; + QTEST(x.deref() ? 1 : 0, "result"); + QTEST(int(x), "expected"); +} + +void tst_QAtomicInt::isTestAndSetNative() +{ +#if defined(Q_ATOMIC_INT_TEST_AND_SET_IS_ALWAYS_NATIVE) + // the runtime test should say the same thing + QVERIFY(QAtomicInt::isTestAndSetNative()); + +# if (defined(Q_ATOMIC_INT_TEST_AND_SET_IS_SOMETIMES_NATIVE) \ + || defined(Q_ATOMIC_INT_TEST_AND_SET_IS_NOT_NATIVE)) +# error "Define only one of Q_ATOMIC_INT_TEST_AND_SET_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" +# endif +#elif defined(Q_ATOMIC_INT_TEST_AND_SET_IS_SOMETIMES_NATIVE) + // could be either, just want to make sure the function is implemented + QVERIFY(QAtomicInt::isTestAndSetNative() || !QAtomicInt::isTestAndSetNative()); + +# if (defined(Q_ATOMIC_INT_TEST_AND_SET_IS_ALWAYS_NATIVE) \ + || defined(Q_ATOMIC_INT_TEST_AND_SET_IS_NOT_NATIVE)) +# error "Define only one of Q_ATOMIC_INT_TEST_AND_SET_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" +# endif +#elif defined(Q_ATOMIC_INT_TEST_AND_SET_IS_NOT_NATIVE) + // the runtime test should say the same thing + QVERIFY(!QAtomicInt::isTestAndSetNative()); + +# if (defined(Q_ATOMIC_INT_TEST_AND_SET_IS_ALWAYS_NATIVE) \ + || defined(Q_ATOMIC_INT_TEST_AND_SET_IS_SOMETIMES_NATIVE)) +# error "Define only one of Q_ATOMIC_INT_TEST_AND_SET_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" +# endif +#else +# error "Q_ATOMIC_INT_TEST_AND_SET_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE is not defined" +#endif +} + +void tst_QAtomicInt::isTestAndSetWaitFree() +{ +#if defined(Q_ATOMIC_INT_TEST_AND_SET_IS_WAIT_FREE) + // the runtime test should say the same thing + QVERIFY(QAtomicInt::isTestAndSetWaitFree()); + + // enforce some invariants + QVERIFY(QAtomicInt::isTestAndSetNative()); +# if defined(Q_ATOMIC_INT_TEST_AND_SET_IS_NOT_NATIVE) +# error "Reference counting cannot be wait-free and unsupported at the same time!" +# endif +#else + // the runtime test should say the same thing + QVERIFY(!QAtomicInt::isTestAndSetWaitFree()); +#endif +} + +void tst_QAtomicInt::testAndSet_data() +{ + QTest::addColumn("value"); + QTest::addColumn("expected"); + QTest::addColumn("newval"); + QTest::addColumn("result"); + + // these should succeed + QTest::newRow("success0") << 0 << 0 << 0 << 1; + QTest::newRow("success1") << 0 << 0 << 1 << 1; + QTest::newRow("success2") << 0 << 0 << -1 << 1; + QTest::newRow("success3") << 1 << 1 << 0 << 1; + QTest::newRow("success4") << 1 << 1 << 1 << 1; + QTest::newRow("success5") << 1 << 1 << -1 << 1; + QTest::newRow("success6") << -1 << -1 << 0 << 1; + QTest::newRow("success7") << -1 << -1 << 1 << 1; + QTest::newRow("success8") << -1 << -1 << -1 << 1; + QTest::newRow("success9") << INT_MIN+1 << INT_MIN+1 << INT_MIN+1 << 1; + QTest::newRow("successA") << INT_MIN+1 << INT_MIN+1 << 1 << 1; + QTest::newRow("successB") << INT_MIN+1 << INT_MIN+1 << -1 << 1; + QTest::newRow("successC") << INT_MAX << INT_MAX << INT_MAX << 1; + QTest::newRow("successD") << INT_MAX << INT_MAX << 1 << 1; + QTest::newRow("successE") << INT_MAX << INT_MAX << -1 << 1; + + // these should fail + QTest::newRow("failure0") << 0 << 1 << ~0 << 0; + QTest::newRow("failure1") << 0 << -1 << ~0 << 0; + QTest::newRow("failure2") << 1 << 0 << ~0 << 0; + QTest::newRow("failure3") << -1 << 0 << ~0 << 0; + QTest::newRow("failure4") << 1 << -1 << ~0 << 0; + QTest::newRow("failure5") << -1 << 1 << ~0 << 0; + QTest::newRow("failure6") << INT_MIN+1 << INT_MAX << ~0 << 0; + QTest::newRow("failure7") << INT_MAX << INT_MIN+1 << ~0 << 0; +} + +void tst_QAtomicInt::testAndSet() +{ + QFETCH(int, value); + QFETCH(int, expected); + QFETCH(int, newval); + + { + QAtomicInt atomic = value; + QTEST(atomic.testAndSetRelaxed(expected, newval) ? 1 : 0, "result"); + } + + { + QAtomicInt atomic = value; + QTEST(atomic.testAndSetAcquire(expected, newval) ? 1 : 0, "result"); + } + + { + QAtomicInt atomic = value; + QTEST(atomic.testAndSetRelease(expected, newval) ? 1 : 0, "result"); + } + + { + QAtomicInt atomic = value; + QTEST(atomic.testAndSetOrdered(expected, newval) ? 1 : 0, "result"); + } +} + +void tst_QAtomicInt::isFetchAndStoreNative() +{ +#if defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE) + // the runtime test should say the same thing + QVERIFY(QAtomicInt::isFetchAndStoreNative()); + +# if (defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_SOMETIMES_NATIVE) \ + || defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_NOT_NATIVE)) +# error "Define only one of Q_ATOMIC_INT_FETCH_AND_STORE_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" +# endif +#elif defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_SOMETIMES_NATIVE) + // could be either, just want to make sure the function is implemented + QVERIFY(QAtomicInt::isFetchAndStoreNative() || !QAtomicInt::isFetchAndStoreNative()); + +# if (defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE) \ + || defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_NOT_NATIVE)) +# error "Define only one of Q_ATOMIC_INT_FETCH_AND_STORE_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" +# endif +#elif defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_NOT_NATIVE) + // the runtime test should say the same thing + QVERIFY(!QAtomicInt::isFetchAndStoreNative()); + +# if (defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE) \ + || defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_SOMETIMES_NATIVE)) +# error "Define only one of Q_ATOMIC_INT_FETCH_AND_STORE_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" +# endif +#else +# error "Q_ATOMIC_INT_FETCH_AND_STORE_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE is not defined" +#endif +} + +void tst_QAtomicInt::isFetchAndStoreWaitFree() +{ +#if defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_WAIT_FREE) + // the runtime test should say the same thing + QVERIFY(QAtomicInt::isFetchAndStoreWaitFree()); + + // enforce some invariants + QVERIFY(QAtomicInt::isFetchAndStoreNative()); +# if defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_NOT_NATIVE) +# error "Reference counting cannot be wait-free and unsupported at the same time!" +# endif +#else + // the runtime test should say the same thing + QVERIFY(!QAtomicInt::isFetchAndStoreWaitFree()); +#endif +} + +void tst_QAtomicInt::fetchAndStore_data() +{ + QTest::addColumn("value"); + QTest::addColumn("newval"); + + QTest::newRow("data0") << 0 << 1; + QTest::newRow("data1") << 1 << 2; + QTest::newRow("data2") << 3 << 8; +} + +void tst_QAtomicInt::fetchAndStore() +{ + QFETCH(int, value); + QFETCH(int, newval); + + { + QAtomicInt atomic = value; + QCOMPARE(atomic.fetchAndStoreRelaxed(newval), value); + QCOMPARE(int(atomic), newval); + } + + { + QAtomicInt atomic = value; + QCOMPARE(atomic.fetchAndStoreAcquire(newval), value); + QCOMPARE(int(atomic), newval); + } + + { + QAtomicInt atomic = value; + QCOMPARE(atomic.fetchAndStoreRelease(newval), value); + QCOMPARE(int(atomic), newval); + } + + { + QAtomicInt atomic = value; + QCOMPARE(atomic.fetchAndStoreOrdered(newval), value); + QCOMPARE(int(atomic), newval); + } +} + +void tst_QAtomicInt::isFetchAndAddNative() +{ +#if defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_ALWAYS_NATIVE) + // the runtime test should say the same thing + QVERIFY(QAtomicInt::isFetchAndAddNative()); + +# if (defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_SOMETIMES_NATIVE) \ + || defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_NOT_NATIVE)) +# error "Define only one of Q_ATOMIC_INT_FETCH_AND_ADD_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" +# endif +#elif defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_SOMETIMES_NATIVE) + // could be either, just want to make sure the function is implemented + QVERIFY(QAtomicInt::isFetchAndAddNative() || !QAtomicInt::isFetchAndAddNative()); + +# if (defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_ALWAYS_NATIVE) \ + || defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_NOT_NATIVE)) +# error "Define only one of Q_ATOMIC_INT_FETCH_AND_ADD_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" +# endif +#elif defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_NOT_NATIVE) + // the runtime test should say the same thing + QVERIFY(!QAtomicInt::isFetchAndAddNative()); + +# if (defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_ALWAYS_NATIVE) \ + || defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_SOMETIMES_NATIVE)) +# error "Define only one of Q_ATOMIC_INT_FETCH_AND_ADD_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" +# endif +#else +# error "Q_ATOMIC_INT_FETCH_AND_ADD_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE is not defined" +#endif +} + +void tst_QAtomicInt::isFetchAndAddWaitFree() +{ +#if defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_WAIT_FREE) + // the runtime test should say the same thing + QVERIFY(QAtomicInt::isFetchAndAddWaitFree()); + + // enforce some invariants + QVERIFY(QAtomicInt::isFetchAndAddNative()); +# if defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_NOT_NATIVE) +# error "Reference counting cannot be wait-free and unsupported at the same time!" +# endif +#else + // the runtime test should say the same thing + QVERIFY(!QAtomicInt::isFetchAndAddWaitFree()); +#endif +} + +void tst_QAtomicInt::fetchAndAdd_data() +{ + QTest::addColumn("value1"); + QTest::addColumn("value2"); + + QTest::newRow("0+1") << 0 << 1; + QTest::newRow("1+0") << 1 << 0; + QTest::newRow("1+2") << 1 << 2; + QTest::newRow("2+1") << 2 << 1; + QTest::newRow("10+21") << 10 << 21; + QTest::newRow("31+40") << 31 << 40; + QTest::newRow("51+62") << 51 << 62; + QTest::newRow("72+81") << 72 << 81; + QTest::newRow("810+721") << 810 << 721; + QTest::newRow("631+540") << 631 << 540; + QTest::newRow("451+362") << 451 << 362; + QTest::newRow("272+181") << 272 << 181; + QTest::newRow("1810+8721") << 1810 << 8721; + QTest::newRow("3631+6540") << 3631 << 6540; + QTest::newRow("5451+4362") << 5451 << 4362; + QTest::newRow("7272+2181") << 7272 << 2181; + + QTest::newRow("0+-1") << 0 << -1; + QTest::newRow("1+0") << 1 << 0; + QTest::newRow("1+-2") << 1 << -2; + QTest::newRow("2+-1") << 2 << -1; + QTest::newRow("10+-21") << 10 << -21; + QTest::newRow("31+-40") << 31 << -40; + QTest::newRow("51+-62") << 51 << -62; + QTest::newRow("72+-81") << 72 << -81; + QTest::newRow("810+-721") << 810 << -721; + QTest::newRow("631+-540") << 631 << -540; + QTest::newRow("451+-362") << 451 << -362; + QTest::newRow("272+-181") << 272 << -181; + QTest::newRow("1810+-8721") << 1810 << -8721; + QTest::newRow("3631+-6540") << 3631 << -6540; + QTest::newRow("5451+-4362") << 5451 << -4362; + QTest::newRow("7272+-2181") << 7272 << -2181; + + QTest::newRow("0+1") << 0 << 1; + QTest::newRow("-1+0") << -1 << 0; + QTest::newRow("-1+2") << -1 << 2; + QTest::newRow("-2+1") << -2 << 1; + QTest::newRow("-10+21") << -10 << 21; + QTest::newRow("-31+40") << -31 << 40; + QTest::newRow("-51+62") << -51 << 62; + QTest::newRow("-72+81") << -72 << 81; + QTest::newRow("-810+721") << -810 << 721; + QTest::newRow("-631+540") << -631 << 540; + QTest::newRow("-451+362") << -451 << 362; + QTest::newRow("-272+181") << -272 << 181; + QTest::newRow("-1810+8721") << -1810 << 8721; + QTest::newRow("-3631+6540") << -3631 << 6540; + QTest::newRow("-5451+4362") << -5451 << 4362; + QTest::newRow("-7272+2181") << -7272 << 2181; +} + +void tst_QAtomicInt::fetchAndAdd() +{ + QFETCH(int, value1); + QFETCH(int, value2); + int result; + + { + QAtomicInt atomic = value1; + result = atomic.fetchAndAddRelaxed(value2); + QCOMPARE(result, value1); + QCOMPARE(int(atomic), value1 + value2); + } + + { + QAtomicInt atomic = value1; + result = atomic.fetchAndAddAcquire(value2); + QCOMPARE(result, value1); + QCOMPARE(int(atomic), value1 + value2); + } + + { + QAtomicInt atomic = value1; + result = atomic.fetchAndAddRelease(value2); + QCOMPARE(result, value1); + QCOMPARE(int(atomic), value1 + value2); + } + + { + QAtomicInt atomic = value1; + result = atomic.fetchAndAddOrdered(value2); + QCOMPARE(result, value1); + QCOMPARE(int(atomic), value1 + value2); + } +} + +void tst_QAtomicInt::testAndSet_loop() +{ + QTime stopWatch; + stopWatch.start(); + + int iterations = 10000000; + + QAtomicInt val=0; + for (int i = 0; i < iterations; ++i) { + QVERIFY(val.testAndSetRelaxed(val, val+1)); + if ((i % 1000) == 999) { + if (stopWatch.elapsed() > 60 * 1000) { + // This test shouldn't run for more than two minutes. + qDebug("Interrupted test after %d iterations (%.2f iterations/sec)", + i, (i * 1000.0) / double(stopWatch.elapsed())); + break; + } + } + } +} + +void tst_QAtomicInt::fetchAndAdd_loop() +{ + int iterations = 10000000; +#if defined (Q_OS_HPUX) + iterations = 1000000; +#endif + + QAtomicInt val=0; + for (int i = 0; i < iterations; ++i) { + const int prev = val.fetchAndAddRelaxed(1); + QCOMPARE(prev, int(val) -1); + } +} + +class FetchAndAddThread : public QThread +{ +public: + void run() + { + + for (int i = 0; i < iterations; ++i) + val->fetchAndAddAcquire(1); + + for (int i = 0; i < iterations; ++i) + val->fetchAndAddAcquire(-1); + + } +QAtomicInt *val; +int iterations; +}; + + +void tst_QAtomicInt::fetchAndAdd_threadedLoop() +{ + QAtomicInt val; + FetchAndAddThread t1; + t1.val = &val; + t1.iterations = 1000000; + + FetchAndAddThread t2; + t2.val = &val; + t2.iterations = 2000000; + + t1.start(); + t2.start(); + t1.wait(); + t2.wait(); + + QCOMPARE(int(val), 0); +} + +QTEST_MAIN(tst_QAtomicInt) +#include "tst_qatomicint.moc" diff --git a/tests/auto/corelib/thread/qatomicpointer/.gitignore b/tests/auto/corelib/thread/qatomicpointer/.gitignore new file mode 100644 index 0000000000..2843c40749 --- /dev/null +++ b/tests/auto/corelib/thread/qatomicpointer/.gitignore @@ -0,0 +1 @@ +tst_qatomicpointer diff --git a/tests/auto/corelib/thread/qatomicpointer/qatomicpointer.pro b/tests/auto/corelib/thread/qatomicpointer/qatomicpointer.pro new file mode 100644 index 0000000000..89ff137d39 --- /dev/null +++ b/tests/auto/corelib/thread/qatomicpointer/qatomicpointer.pro @@ -0,0 +1,4 @@ +load(qttest_p4) +SOURCES += tst_qatomicpointer.cpp +QT = core +CONFIG += parallel_test diff --git a/tests/auto/corelib/thread/qatomicpointer/tst_qatomicpointer.cpp b/tests/auto/corelib/thread/qatomicpointer/tst_qatomicpointer.cpp new file mode 100644 index 0000000000..42e744aaa6 --- /dev/null +++ b/tests/auto/corelib/thread/qatomicpointer/tst_qatomicpointer.cpp @@ -0,0 +1,674 @@ +/**************************************************************************** +** +** 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 + +#include + +#include + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QAtomicPointer : public QObject +{ + Q_OBJECT + +public: + tst_QAtomicPointer(); + ~tst_QAtomicPointer(); + +private slots: + void warningFree(); + + void constructor(); + void copy_constructor(); + void equality_operator(); + void inequality_operator(); + void assignment_operator(); + void star_operator(); + void dereference_operator(); + + void isTestAndSetNative(); + void isTestAndSetWaitFree(); + void testAndSet(); + + void isFetchAndStoreNative(); + void isFetchAndStoreWaitFree(); + void fetchAndStore(); + + void isFetchAndAddNative(); + void isFetchAndAddWaitFree(); + void fetchAndAdd_data(); + void fetchAndAdd(); + +private: + static void warningFreeHelper(); +}; + +tst_QAtomicPointer::tst_QAtomicPointer() +{ } + +tst_QAtomicPointer::~tst_QAtomicPointer() +{ } + +struct WFHC +{ + void bar() {} +}; + +void tst_QAtomicPointer::warningFreeHelper() +{ + qFatal("This code is bogus, and shouldn't be run. We're looking for compiler warnings only."); + + QBasicAtomicPointer p = Q_BASIC_ATOMIC_INITIALIZER(0); + + p->bar(); + + WFHC *expectedValue = 0; + WFHC *newValue = 0; + qptrdiff valueToAdd = 0; + + p.testAndSetRelaxed(expectedValue, newValue); + p.testAndSetAcquire(expectedValue, newValue); + p.testAndSetRelease(expectedValue, newValue); + p.testAndSetOrdered(expectedValue, newValue); + + p.fetchAndStoreRelaxed(newValue); + p.fetchAndStoreAcquire(newValue); + p.fetchAndStoreRelease(newValue); + p.fetchAndStoreOrdered(newValue); + + p.fetchAndAddRelaxed(valueToAdd); + p.fetchAndAddAcquire(valueToAdd); + p.fetchAndAddRelease(valueToAdd); + p.fetchAndAddOrdered(valueToAdd); +} + +void tst_QAtomicPointer::warningFree() +{ + // This is a compile time check for warnings. + // No need for actual work here. + + void (*foo)() = &warningFreeHelper; + (void)foo; +} + +void tst_QAtomicPointer::constructor() +{ + void *one = this; + QAtomicPointer atomic1 = one; + QVERIFY(atomic1 == one); + + void *two = &one; + QAtomicPointer atomic2 = two; + QVERIFY(atomic2 == two); + + void *three = &two; + QAtomicPointer atomic3 = three; + QVERIFY(atomic3 == three); +} + +void tst_QAtomicPointer::copy_constructor() +{ + void *one = this; + QAtomicPointer atomic1 = one; + QAtomicPointer atomic1_copy = atomic1; + QVERIFY(atomic1_copy == one); + QCOMPARE(atomic1_copy, atomic1); + + void *two = &one; + QAtomicPointer atomic2 = two; + QAtomicPointer atomic2_copy = atomic2; + QVERIFY(atomic2_copy == two); + QCOMPARE(atomic2_copy, atomic2); + + void *three = &two; + QAtomicPointer atomic3 = three; + QAtomicPointer atomic3_copy = atomic3; + QVERIFY(atomic3_copy == three); + QCOMPARE(atomic3_copy, atomic3); +} + +void tst_QAtomicPointer::equality_operator() +{ + void *one = this; + void *two = &one; + void *three = &two; + + QAtomicPointer atomic1 = one; + QAtomicPointer atomic2 = two; + QAtomicPointer atomic3 = three; + + QVERIFY(atomic1 == one); + QVERIFY(!(atomic1 == two)); + QVERIFY(!(atomic1 == three)); + + QVERIFY(!(atomic2 == one)); + QVERIFY(atomic2 == two); + QVERIFY(!(atomic2 == three)); + + QVERIFY(!(atomic3 == one)); + QVERIFY(!(atomic3 == two)); + QVERIFY(atomic3 == three); +} + +void tst_QAtomicPointer::inequality_operator() +{ + void *one = this; + void *two = &one; + void *three = &two; + + QAtomicPointer atomic1 = one; + QAtomicPointer atomic2 = two; + QAtomicPointer atomic3 = three; + + QVERIFY(!(atomic1 != one)); + QVERIFY(atomic1 != two); + QVERIFY(atomic1 != three); + + QVERIFY(atomic2 != one); + QVERIFY(!(atomic2 != two)); + QVERIFY(atomic2 != three); + + QVERIFY(atomic3 != one); + QVERIFY(atomic3 != two); + QVERIFY(!(atomic3 != three)); +} + +void tst_QAtomicPointer::assignment_operator() +{ + void *one = this; + void *two = &one; + void *three = &two; + + QAtomicPointer atomic1 = one; + QAtomicPointer atomic2 = two; + QAtomicPointer atomic3 = three; + + QVERIFY(atomic1 == one); + QVERIFY(atomic2 == two); + QVERIFY(atomic3 == three); + + atomic1 = two; + atomic2 = three; + atomic3 = one; + + QVERIFY(atomic1 == two); + QVERIFY(atomic2 == three); + QVERIFY(atomic3 == one); +} + +struct Type +{ + inline const Type *self() const + { return this; } +}; + +void tst_QAtomicPointer::star_operator() +{ + Type t; + QAtomicPointer p = &t; + QCOMPARE((*p).self(), t.self()); +} + +void tst_QAtomicPointer::dereference_operator() +{ + Type t; + QAtomicPointer p = &t; + QCOMPARE(p->self(), t.self()); +} + +void tst_QAtomicPointer::isTestAndSetNative() +{ +#if defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE) + // the runtime test should say the same thing + QVERIFY(QAtomicPointer::isTestAndSetNative()); + +# if (defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_SOMETIMES_NATIVE) \ + || defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_NOT_NATIVE)) +# error "Define only one of Q_ATOMIC_POINTER_TEST_AND_SET_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" +# endif +#elif defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_SOMETIMES_NATIVE) + // could be either, just want to make sure the function is implemented + QVERIFY(QAtomicPointer::isTestAndSetNative() + || !QAtomicPointer::isTestAndSetNative()); + +# if (defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE) \ + || defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_NOT_NATIVE)) +# error "Define only one of Q_ATOMIC_POINTER_TEST_AND_SET_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" +# endif +#elif defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_NOT_NATIVE) + // the runtime test should say the same thing + QVERIFY(!QAtomicPointer::isTestAndSetNative()); + +# if (defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE) \ + || defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_SOMETIMES_NATIVE)) +# error "Define only one of Q_ATOMIC_POINTER_TEST_AND_SET_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" +# endif +#else +# error "Q_ATOMIC_POINTER_TEST_AND_SET_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE is not defined" +#endif +} + +void tst_QAtomicPointer::isTestAndSetWaitFree() +{ +#if defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_WAIT_FREE) + // the runtime test should say the same thing + QVERIFY(QAtomicPointer::isTestAndSetWaitFree()); + + // enforce some invariants + QVERIFY(QAtomicPointer::isTestAndSetNative()); +# if defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_NOT_NATIVE) +# error "Reference counting cannot be wait-free and unsupported at the same time!" +# endif +#else + // the runtime test should say the same thing + QVERIFY(!QAtomicPointer::isTestAndSetWaitFree()); +#endif +} + +void tst_QAtomicPointer::testAndSet() +{ + void *one = this; + void *two = &one; + void *three = &two; + + { + QAtomicPointer atomic1 = one; + QAtomicPointer atomic2 = two; + QAtomicPointer atomic3 = three; + + QVERIFY(atomic1 == one); + QVERIFY(atomic2 == two); + QVERIFY(atomic3 == three); + + QVERIFY(atomic1.testAndSetRelaxed(one, two)); + QVERIFY(atomic2.testAndSetRelaxed(two, three)); + QVERIFY(atomic3.testAndSetRelaxed(three, one)); + + QVERIFY(atomic1 == two); + QVERIFY(atomic2 == three); + QVERIFY(atomic3 == one); + } + + { + QAtomicPointer atomic1 = one; + QAtomicPointer atomic2 = two; + QAtomicPointer atomic3 = three; + + QVERIFY(atomic1 == one); + QVERIFY(atomic2 == two); + QVERIFY(atomic3 == three); + + QVERIFY(atomic1.testAndSetAcquire(one, two)); + QVERIFY(atomic2.testAndSetAcquire(two, three)); + QVERIFY(atomic3.testAndSetAcquire(three, one)); + + QVERIFY(atomic1 == two); + QVERIFY(atomic2 == three); + QVERIFY(atomic3 == one); + } + + { + QAtomicPointer atomic1 = one; + QAtomicPointer atomic2 = two; + QAtomicPointer atomic3 = three; + + QVERIFY(atomic1 == one); + QVERIFY(atomic2 == two); + QVERIFY(atomic3 == three); + + QVERIFY(atomic1.testAndSetRelease(one, two)); + QVERIFY(atomic2.testAndSetRelease(two, three)); + QVERIFY(atomic3.testAndSetRelease(three, one)); + + QVERIFY(atomic1 == two); + QVERIFY(atomic2 == three); + QVERIFY(atomic3 == one); + } + + { + QAtomicPointer atomic1 = one; + QAtomicPointer atomic2 = two; + QAtomicPointer atomic3 = three; + + QVERIFY(atomic1 == one); + QVERIFY(atomic2 == two); + QVERIFY(atomic3 == three); + + QVERIFY(atomic1.testAndSetOrdered(one, two)); + QVERIFY(atomic2.testAndSetOrdered(two, three)); + QVERIFY(atomic3.testAndSetOrdered(three, one)); + + QVERIFY(atomic1 == two); + QVERIFY(atomic2 == three); + QVERIFY(atomic3 == one); + } +} + +void tst_QAtomicPointer::isFetchAndStoreNative() +{ +#if defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE) + // the runtime test should say the same thing + QVERIFY(QAtomicPointer::isFetchAndStoreNative()); + +# if (defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_SOMETIMES_NATIVE) \ + || defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_NOT_NATIVE)) +# error "Define only one of Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" +# endif +#elif defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_SOMETIMES_NATIVE) + // could be either, just want to make sure the function is implemented + QVERIFY(QAtomicPointer::isFetchAndStoreNative() + || !QAtomicPointer::isFetchAndStoreNative()); + +# if (defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE) \ + || defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_NOT_NATIVE)) +# error "Define only one of Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" +# endif +#elif defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_NOT_NATIVE) + // the runtime test should say the same thing + QVERIFY(!QAtomicPointer::isFetchAndStoreNative()); + +# if (defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE) \ + || defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_SOMETIMES_NATIVE)) +# error "Define only one of Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" +# endif +#else +# error "Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE is not defined" +#endif +} + +void tst_QAtomicPointer::isFetchAndStoreWaitFree() +{ +#if defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_WAIT_FREE) + // the runtime test should say the same thing + QVERIFY(QAtomicPointer::isFetchAndStoreWaitFree()); + + // enforce some invariants + QVERIFY(QAtomicPointer::isFetchAndStoreNative()); +# if defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_NOT_NATIVE) +# error "Reference counting cannot be wait-free and unsupported at the same time!" +# endif +#else + // the runtime test should say the same thing + QVERIFY(!QAtomicPointer::isFetchAndStoreWaitFree()); +#endif +} + +void tst_QAtomicPointer::fetchAndStore() +{ + void *one = this; + void *two = &one; + void *three = &two; + + { + QAtomicPointer atomic1 = one; + QAtomicPointer atomic2 = two; + QAtomicPointer atomic3 = three; + + QVERIFY(atomic1 == one); + QVERIFY(atomic2 == two); + QVERIFY(atomic3 == three); + + QCOMPARE(atomic1.fetchAndStoreRelaxed(two), one); + QCOMPARE(atomic2.fetchAndStoreRelaxed(three), two); + QCOMPARE(atomic3.fetchAndStoreRelaxed(one), three); + + QVERIFY(atomic1 == two); + QVERIFY(atomic2 == three); + QVERIFY(atomic3 == one); + } + + { + QAtomicPointer atomic1 = one; + QAtomicPointer atomic2 = two; + QAtomicPointer atomic3 = three; + + QVERIFY(atomic1 == one); + QVERIFY(atomic2 == two); + QVERIFY(atomic3 == three); + + QCOMPARE(atomic1.fetchAndStoreAcquire(two), one); + QCOMPARE(atomic2.fetchAndStoreAcquire(three), two); + QCOMPARE(atomic3.fetchAndStoreAcquire(one), three); + + QVERIFY(atomic1 == two); + QVERIFY(atomic2 == three); + QVERIFY(atomic3 == one); + } + + { + QAtomicPointer atomic1 = one; + QAtomicPointer atomic2 = two; + QAtomicPointer atomic3 = three; + + QVERIFY(atomic1 == one); + QVERIFY(atomic2 == two); + QVERIFY(atomic3 == three); + + QCOMPARE(atomic1.fetchAndStoreRelease(two), one); + QCOMPARE(atomic2.fetchAndStoreRelease(three), two); + QCOMPARE(atomic3.fetchAndStoreRelease(one), three); + + QVERIFY(atomic1 == two); + QVERIFY(atomic2 == three); + QVERIFY(atomic3 == one); + } + + { + QAtomicPointer atomic1 = one; + QAtomicPointer atomic2 = two; + QAtomicPointer atomic3 = three; + + QVERIFY(atomic1 == one); + QVERIFY(atomic2 == two); + QVERIFY(atomic3 == three); + + QCOMPARE(atomic1.fetchAndStoreOrdered(two), one); + QCOMPARE(atomic2.fetchAndStoreOrdered(three), two); + QCOMPARE(atomic3.fetchAndStoreOrdered(one), three); + + QVERIFY(atomic1 == two); + QVERIFY(atomic2 == three); + QVERIFY(atomic3 == one); + } +} + +void tst_QAtomicPointer::isFetchAndAddNative() +{ +#if defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE) + // the runtime test should say the same thing + QVERIFY(QAtomicPointer::isFetchAndAddNative()); + +# if (defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_SOMETIMES_NATIVE) \ + || defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_NOT_NATIVE)) +# error "Define only one of Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" +# endif +#elif defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_SOMETIMES_NATIVE) + // could be either, just want to make sure the function is implemented + QVERIFY(QAtomicPointer::isFetchAndAddNative() + || !QAtomicPointer::isFetchAndAddNative()); + +# if (defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE) \ + || defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_NOT_NATIVE)) +# error "Define only one of Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" +# endif +#elif defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_NOT_NATIVE) + // the runtime test should say the same thing + QVERIFY(!QAtomicPointer::isFetchAndAddNative()); + +# if (defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE) \ + || defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_SOMETIMES_NATIVE)) +# error "Define only one of Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" +# endif +#else +# error "Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE is not defined" +#endif +} + +void tst_QAtomicPointer::isFetchAndAddWaitFree() +{ +#if defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_WAIT_FREE) + // the runtime test should say the same thing + QVERIFY(QAtomicPointer::isFetchAndAddWaitFree()); + + // enforce some invariants + QVERIFY(QAtomicPointer::isFetchAndAddNative()); +# if defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_NOT_NATIVE) +# error "Reference counting cannot be wait-free and unsupported at the same time!" +# endif +#else + // the runtime test should say the same thing + QVERIFY(!QAtomicPointer::isFetchAndAddWaitFree()); +#endif +} + +void tst_QAtomicPointer::fetchAndAdd_data() +{ + QTest::addColumn("valueToAdd"); + + QTest::newRow("0") << 0; + QTest::newRow("1") << 1; + QTest::newRow("2") << 2; + QTest::newRow("10") << 10; + QTest::newRow("31") << 31; + QTest::newRow("51") << 51; + QTest::newRow("72") << 72; + QTest::newRow("810") << 810; + QTest::newRow("631") << 631; + QTest::newRow("451") << 451; + QTest::newRow("272") << 272; + QTest::newRow("1810") << 1810; + QTest::newRow("3631") << 3631; + QTest::newRow("5451") << 5451; + QTest::newRow("7272") << 7272; + QTest::newRow("-1") << -1; + QTest::newRow("-2") << -2; + QTest::newRow("-10") << -10; + QTest::newRow("-31") << -31; + QTest::newRow("-51") << -51; + QTest::newRow("-72") << -72; + QTest::newRow("-810") << -810; + QTest::newRow("-631") << -631; + QTest::newRow("-451") << -451; + QTest::newRow("-272") << -272; + QTest::newRow("-1810") << -1810; + QTest::newRow("-3631") << -3631; + QTest::newRow("-5451") << -5451; + QTest::newRow("-7272") << -7272; +} + +void tst_QAtomicPointer::fetchAndAdd() +{ + QFETCH(int, valueToAdd); + + char c; + char *pc = &c; + short s; + short *ps = &s; + int i; + int *pi = &i; + + { + QAtomicPointer pointer1 = pc; + QCOMPARE(quintptr(pointer1.fetchAndAddRelaxed(valueToAdd)), quintptr(pc)); + QCOMPARE(quintptr(pointer1.fetchAndAddRelaxed(-valueToAdd)), quintptr(pc + valueToAdd)); + QCOMPARE(quintptr(static_cast(pointer1)), quintptr(pc)); + QAtomicPointer pointer2 = ps; + QCOMPARE(quintptr(pointer2.fetchAndAddRelaxed(valueToAdd)), quintptr(ps)); + QCOMPARE(quintptr(pointer2.fetchAndAddRelaxed(-valueToAdd)), quintptr(ps + valueToAdd)); + QCOMPARE(quintptr(static_cast(pointer2)), quintptr(ps)); + QAtomicPointer pointer3 = pi; + QCOMPARE(quintptr(pointer3.fetchAndAddRelaxed(valueToAdd)), quintptr(pi)); + QCOMPARE(quintptr(pointer3.fetchAndAddRelaxed(-valueToAdd)), quintptr(pi + valueToAdd)); + QCOMPARE(quintptr(static_cast(pointer3)), quintptr(pi)); + } + + { + QAtomicPointer pointer1 = pc; + QCOMPARE(quintptr(pointer1.fetchAndAddAcquire(valueToAdd)), quintptr(pc)); + QCOMPARE(quintptr(pointer1.fetchAndAddAcquire(-valueToAdd)), quintptr(pc + valueToAdd)); + QCOMPARE(quintptr(static_cast(pointer1)), quintptr(pc)); + QAtomicPointer pointer2 = ps; + QCOMPARE(quintptr(pointer2.fetchAndAddAcquire(valueToAdd)), quintptr(ps)); + QCOMPARE(quintptr(pointer2.fetchAndAddAcquire(-valueToAdd)), quintptr(ps + valueToAdd)); + QCOMPARE(quintptr(static_cast(pointer2)), quintptr(ps)); + QAtomicPointer pointer3 = pi; + QCOMPARE(quintptr(pointer3.fetchAndAddAcquire(valueToAdd)), quintptr(pi)); + QCOMPARE(quintptr(pointer3.fetchAndAddAcquire(-valueToAdd)), quintptr(pi + valueToAdd)); + QCOMPARE(quintptr(static_cast(pointer3)), quintptr(pi)); + } + + { + QAtomicPointer pointer1 = pc; + QCOMPARE(quintptr(pointer1.fetchAndAddRelease(valueToAdd)), quintptr(pc)); + QCOMPARE(quintptr(pointer1.fetchAndAddRelease(-valueToAdd)), quintptr(pc + valueToAdd)); + QCOMPARE(quintptr(static_cast(pointer1)), quintptr(pc)); + QAtomicPointer pointer2 = ps; + QCOMPARE(quintptr(pointer2.fetchAndAddRelease(valueToAdd)), quintptr(ps)); + QCOMPARE(quintptr(pointer2.fetchAndAddRelease(-valueToAdd)), quintptr(ps + valueToAdd)); + QCOMPARE(quintptr(static_cast(pointer2)), quintptr(ps)); + QAtomicPointer pointer3 = pi; + QCOMPARE(quintptr(pointer3.fetchAndAddRelease(valueToAdd)), quintptr(pi)); + QCOMPARE(quintptr(pointer3.fetchAndAddRelease(-valueToAdd)), quintptr(pi + valueToAdd)); + QCOMPARE(quintptr(static_cast(pointer3)), quintptr(pi)); + } + + { + QAtomicPointer pointer1 = pc; + QCOMPARE(quintptr(pointer1.fetchAndAddOrdered(valueToAdd)), quintptr(pc)); + QCOMPARE(quintptr(pointer1.fetchAndAddOrdered(-valueToAdd)), quintptr(pc + valueToAdd)); + QCOMPARE(quintptr(static_cast(pointer1)), quintptr(pc)); + QAtomicPointer pointer2 = ps; + QCOMPARE(quintptr(pointer2.fetchAndAddOrdered(valueToAdd)), quintptr(ps)); + QCOMPARE(quintptr(pointer2.fetchAndAddOrdered(-valueToAdd)), quintptr(ps + valueToAdd)); + QCOMPARE(quintptr(static_cast(pointer2)), quintptr(ps)); + QAtomicPointer pointer3 = pi; + QCOMPARE(quintptr(pointer3.fetchAndAddOrdered(valueToAdd)), quintptr(pi)); + QCOMPARE(quintptr(pointer3.fetchAndAddOrdered(-valueToAdd)), quintptr(pi + valueToAdd)); + QCOMPARE(quintptr(static_cast(pointer3)), quintptr(pi)); + } +} + +QTEST_APPLESS_MAIN(tst_QAtomicPointer) +#include "tst_qatomicpointer.moc" diff --git a/tests/auto/corelib/thread/qmutex/.gitignore b/tests/auto/corelib/thread/qmutex/.gitignore new file mode 100644 index 0000000000..2f6b74166f --- /dev/null +++ b/tests/auto/corelib/thread/qmutex/.gitignore @@ -0,0 +1 @@ +tst_qmutex diff --git a/tests/auto/corelib/thread/qmutex/qmutex.pro b/tests/auto/corelib/thread/qmutex/qmutex.pro new file mode 100644 index 0000000000..608b08e16e --- /dev/null +++ b/tests/auto/corelib/thread/qmutex/qmutex.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +SOURCES += tst_qmutex.cpp +QT = core +CONFIG += parallel_test +CONFIG += insignificant_test diff --git a/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp b/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp new file mode 100644 index 0000000000..7ad6a98a4d --- /dev/null +++ b/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp @@ -0,0 +1,640 @@ +/**************************************************************************** +** +** 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 + +#include +#include +#include +#include +#include +#include + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QMutex : public QObject +{ + Q_OBJECT + +public: + tst_QMutex(); + virtual ~tst_QMutex(); + +private slots: + void tryLock(); + void lock_unlock_locked_tryLock(); + void stressTest(); + void tryLockRace(); + void qtbug16115_trylock(); + void moreStress(); +}; + +static const int iterations = 100; + +tst_QMutex::tst_QMutex() + +{ +} + +tst_QMutex::~tst_QMutex() +{ +} + +QAtomicInt lockCount(0); +QMutex normalMutex, recursiveMutex(QMutex::Recursive); +QSemaphore testsTurn; +QSemaphore threadsTurn; + +enum { waitTime = 100 }; + +void tst_QMutex::tryLock() +{ + // test non-recursive mutex + { + class Thread : public QThread + { + public: + void run() + { + testsTurn.release(); + + threadsTurn.acquire(); + QVERIFY(!normalMutex.tryLock()); + testsTurn.release(); + + threadsTurn.acquire(); + QVERIFY(normalMutex.tryLock()); + QVERIFY(lockCount.testAndSetRelaxed(0, 1)); + QVERIFY(!normalMutex.tryLock()); + QVERIFY(lockCount.testAndSetRelaxed(1, 0)); + normalMutex.unlock(); + testsTurn.release(); + + threadsTurn.acquire(); + QTime timer; + timer.start(); + QVERIFY(!normalMutex.tryLock(waitTime)); + QVERIFY(timer.elapsed() >= waitTime); + testsTurn.release(); + + threadsTurn.acquire(); + timer.start(); + QVERIFY(normalMutex.tryLock(waitTime)); + QVERIFY(timer.elapsed() <= waitTime); + QVERIFY(lockCount.testAndSetRelaxed(0, 1)); + timer.start(); + QVERIFY(!normalMutex.tryLock(waitTime)); + QVERIFY(timer.elapsed() >= waitTime); + QVERIFY(lockCount.testAndSetRelaxed(1, 0)); + normalMutex.unlock(); + testsTurn.release(); + + threadsTurn.acquire(); + QVERIFY(!normalMutex.tryLock(0)); + testsTurn.release(); + + threadsTurn.acquire(); + timer.start(); + QVERIFY(normalMutex.tryLock(0)); + QVERIFY(timer.elapsed() < waitTime); + QVERIFY(lockCount.testAndSetRelaxed(0, 1)); + QVERIFY(!normalMutex.tryLock(0)); + QVERIFY(lockCount.testAndSetRelaxed(1, 0)); + normalMutex.unlock(); + testsTurn.release(); + + threadsTurn.acquire(); + } + }; + + Thread thread; + thread.start(); + + // thread can't acquire lock + testsTurn.acquire(); + normalMutex.lock(); + QVERIFY(lockCount.testAndSetRelaxed(0, 1)); + threadsTurn.release(); + + // thread can acquire lock + testsTurn.acquire(); + QVERIFY(lockCount.testAndSetRelaxed(1, 0)); + normalMutex.unlock(); + threadsTurn.release(); + + // thread can't acquire lock, timeout = waitTime + testsTurn.acquire(); + normalMutex.lock(); + QVERIFY(lockCount.testAndSetRelaxed(0, 1)); + threadsTurn.release(); + + // thread can acquire lock, timeout = waitTime + testsTurn.acquire(); + QVERIFY(lockCount.testAndSetRelaxed(1, 0)); + normalMutex.unlock(); + threadsTurn.release(); + + // thread can't acquire lock, timeout = 0 + testsTurn.acquire(); + normalMutex.lock(); + QVERIFY(lockCount.testAndSetRelaxed(0, 1)); + threadsTurn.release(); + + // thread can acquire lock, timeout = 0 + testsTurn.acquire(); + QVERIFY(lockCount.testAndSetRelaxed(1, 0)); + normalMutex.unlock(); + threadsTurn.release(); + + // wait for thread to finish + testsTurn.acquire(); + threadsTurn.release(); + thread.wait(); + } + + // test recursive mutex + { + class Thread : public QThread + { + public: + void run() + { + testsTurn.release(); + + threadsTurn.acquire(); + QVERIFY(!recursiveMutex.tryLock()); + testsTurn.release(); + + threadsTurn.acquire(); + QVERIFY(recursiveMutex.tryLock()); + QVERIFY(lockCount.testAndSetRelaxed(0, 1)); + QVERIFY(recursiveMutex.tryLock()); + QVERIFY(lockCount.testAndSetRelaxed(1, 2)); + QVERIFY(lockCount.testAndSetRelaxed(2, 1)); + recursiveMutex.unlock(); + QVERIFY(lockCount.testAndSetRelaxed(1, 0)); + recursiveMutex.unlock(); + testsTurn.release(); + + threadsTurn.acquire(); + QTime timer; + timer.start(); + QVERIFY(!recursiveMutex.tryLock(waitTime)); + QVERIFY(timer.elapsed() >= waitTime); + QVERIFY(!recursiveMutex.tryLock(0)); + testsTurn.release(); + + threadsTurn.acquire(); + timer.start(); + QVERIFY(recursiveMutex.tryLock(waitTime)); + QVERIFY(timer.elapsed() <= waitTime); + QVERIFY(lockCount.testAndSetRelaxed(0, 1)); + QVERIFY(recursiveMutex.tryLock(waitTime)); + QVERIFY(lockCount.testAndSetRelaxed(1, 2)); + QVERIFY(lockCount.testAndSetRelaxed(2, 1)); + recursiveMutex.unlock(); + QVERIFY(lockCount.testAndSetRelaxed(1, 0)); + recursiveMutex.unlock(); + testsTurn.release(); + + threadsTurn.acquire(); + QVERIFY(!recursiveMutex.tryLock(0)); + QVERIFY(!recursiveMutex.tryLock(0)); + testsTurn.release(); + + threadsTurn.acquire(); + timer.start(); + QVERIFY(recursiveMutex.tryLock(0)); + QVERIFY(timer.elapsed() < waitTime); + QVERIFY(lockCount.testAndSetRelaxed(0, 1)); + QVERIFY(recursiveMutex.tryLock(0)); + QVERIFY(lockCount.testAndSetRelaxed(1, 2)); + QVERIFY(lockCount.testAndSetRelaxed(2, 1)); + recursiveMutex.unlock(); + QVERIFY(lockCount.testAndSetRelaxed(1, 0)); + recursiveMutex.unlock(); + testsTurn.release(); + + threadsTurn.acquire(); + } + }; + + Thread thread; + thread.start(); + + // thread can't acquire lock + testsTurn.acquire(); + recursiveMutex.lock(); + QVERIFY(lockCount.testAndSetRelaxed(0, 1)); + recursiveMutex.lock(); + QVERIFY(lockCount.testAndSetRelaxed(1, 2)); + threadsTurn.release(); + + // thread can acquire lock + testsTurn.acquire(); + QVERIFY(lockCount.testAndSetRelaxed(2, 1)); + recursiveMutex.unlock(); + QVERIFY(lockCount.testAndSetRelaxed(1, 0)); + recursiveMutex.unlock(); + threadsTurn.release(); + + // thread can't acquire lock, timeout = waitTime + testsTurn.acquire(); + recursiveMutex.lock(); + QVERIFY(lockCount.testAndSetRelaxed(0, 1)); + recursiveMutex.lock(); + QVERIFY(lockCount.testAndSetRelaxed(1, 2)); + threadsTurn.release(); + + // thread can acquire lock, timeout = waitTime + testsTurn.acquire(); + QVERIFY(lockCount.testAndSetRelaxed(2, 1)); + recursiveMutex.unlock(); + QVERIFY(lockCount.testAndSetRelaxed(1, 0)); + recursiveMutex.unlock(); + threadsTurn.release(); + + // thread can't acquire lock, timeout = 0 + testsTurn.acquire(); + recursiveMutex.lock(); + QVERIFY(lockCount.testAndSetRelaxed(0, 1)); + recursiveMutex.lock(); + QVERIFY(lockCount.testAndSetRelaxed(1, 2)); + threadsTurn.release(); + + // thread can acquire lock, timeout = 0 + testsTurn.acquire(); + QVERIFY(lockCount.testAndSetRelaxed(2, 1)); + recursiveMutex.unlock(); + QVERIFY(lockCount.testAndSetRelaxed(1, 0)); + recursiveMutex.unlock(); + threadsTurn.release(); + + // stop thread + testsTurn.acquire(); + threadsTurn.release(); + thread.wait(); + } +} + +class mutex_Thread : public QThread +{ +public: + QMutex mutex; + QWaitCondition cond; + + QMutex &test_mutex; + + inline mutex_Thread(QMutex &m) : test_mutex(m) { } + + void run() + { + test_mutex.lock(); + + mutex.lock(); + for (int i = 0; i < iterations; ++i) { + cond.wakeOne(); + cond.wait(&mutex); + } + mutex.unlock(); + + test_mutex.unlock(); + } +}; + +class rmutex_Thread : public QThread +{ +public: + QMutex mutex; + QWaitCondition cond; + + QMutex &test_mutex; + + inline rmutex_Thread(QMutex &m) : test_mutex(m) { } + + void run() + { + test_mutex.lock(); + test_mutex.lock(); + test_mutex.lock(); + test_mutex.lock(); + + mutex.lock(); + for (int i = 0; i < iterations; ++i) { + cond.wakeOne(); + cond.wait(&mutex); + } + mutex.unlock(); + + test_mutex.unlock(); + test_mutex.unlock(); + test_mutex.unlock(); + test_mutex.unlock(); + } +}; + +void tst_QMutex::lock_unlock_locked_tryLock() +{ + // normal mutex + QMutex mutex; + mutex_Thread thread(mutex); + + QMutex rmutex(QMutex::Recursive); + rmutex_Thread rthread(rmutex); + + for (int i = 0; i < iterations; ++i) { + // normal mutex + QVERIFY(mutex.tryLock()); + mutex.unlock(); + + thread.mutex.lock(); + thread.start(); + + for (int j = 0; j < iterations; ++j) { + QVERIFY(thread.cond.wait(&thread.mutex, 10000)); + QVERIFY(!mutex.tryLock()); + + thread.cond.wakeOne(); + } + + thread.mutex.unlock(); + + QVERIFY(thread.wait(10000)); + QVERIFY(mutex.tryLock()); + + mutex.unlock(); + + // recursive mutex + QVERIFY(rmutex.tryLock()); + QVERIFY(rmutex.tryLock()); + QVERIFY(rmutex.tryLock()); + QVERIFY(rmutex.tryLock()); + + rmutex.unlock(); + rmutex.unlock(); + rmutex.unlock(); + rmutex.unlock(); + + rthread.mutex.lock(); + rthread.start(); + + for (int k = 0; k < iterations; ++k) { + QVERIFY(rthread.cond.wait(&rthread.mutex, 10000)); + QVERIFY(!rmutex.tryLock()); + + rthread.cond.wakeOne(); + } + + rthread.mutex.unlock(); + + QVERIFY(rthread.wait(10000)); + QVERIFY(rmutex.tryLock()); + QVERIFY(rmutex.tryLock()); + QVERIFY(rmutex.tryLock()); + QVERIFY(rmutex.tryLock()); + + rmutex.unlock(); + rmutex.unlock(); + rmutex.unlock(); + rmutex.unlock(); + } +} + +enum { one_minute = 6 * 1000, //not really one minute, but else it is too long. + threadCount = 10 }; + +class StressTestThread : public QThread +{ + QTime t; +public: + static QBasicAtomicInt lockCount; + static QBasicAtomicInt sentinel; + static QMutex mutex; + static int errorCount; + void start() + { + t.start(); + QThread::start(); + } + void run() + { + while (t.elapsed() < one_minute) { + mutex.lock(); + if (sentinel.ref()) ++errorCount; + if (!sentinel.deref()) ++errorCount; + lockCount.ref(); + mutex.unlock(); + if (mutex.tryLock()) { + if (sentinel.ref()) ++errorCount; + if (!sentinel.deref()) ++errorCount; + lockCount.ref(); + mutex.unlock(); + } + } + } +}; +QMutex StressTestThread::mutex; +QBasicAtomicInt StressTestThread::lockCount = Q_BASIC_ATOMIC_INITIALIZER(0); +QBasicAtomicInt StressTestThread::sentinel = Q_BASIC_ATOMIC_INITIALIZER(-1); +int StressTestThread::errorCount = 0; + +void tst_QMutex::stressTest() +{ + StressTestThread 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)); + QCOMPARE(StressTestThread::errorCount, 0); + qDebug("locked %d times", int(StressTestThread::lockCount)); +} + +class TryLockRaceThread : public QThread +{ +public: + static QMutex mutex; + + void run() + { + QTime t; + t.start(); + do { + if (mutex.tryLock()) + mutex.unlock(); + } while (t.elapsed() < one_minute/2); + } +}; +QMutex TryLockRaceThread::mutex; + +void tst_QMutex::tryLockRace() +{ + // mutex not in use, should be able to lock it + QVERIFY(TryLockRaceThread::mutex.tryLock()); + TryLockRaceThread::mutex.unlock(); + + // try to break tryLock + TryLockRaceThread thread[threadCount]; + for (int i = 0; i < threadCount; ++i) + thread[i].start(); + for (int i = 0; i < threadCount; ++i) + QVERIFY(thread[i].wait()); + + // mutex not in use, should be able to lock it + QVERIFY(TryLockRaceThread::mutex.tryLock()); + TryLockRaceThread::mutex.unlock(); +} + +// Variable that will be protected by the mutex. Volatile so that the +// the optimiser doesn't mess with it based on the increment-then-decrement +// usage pattern. +static volatile int qtbug16115_trylock_counter; +// Counter for how many times the protected variable has an incorrect value. +static int qtbug16115_failure_count = 0; + +void tst_QMutex::qtbug16115_trylock() +{ + //Used to deadlock on unix + struct TrylockThread : QThread { + TrylockThread(QMutex &mut) : mut(mut) {} + QMutex &mut; + void run() { + for (int i = 0; i < 100000; ++i) { + if (mut.tryLock(0)) { + if ((++qtbug16115_trylock_counter) != 1) + ++qtbug16115_failure_count; + if ((--qtbug16115_trylock_counter) != 0) + ++qtbug16115_failure_count; + mut.unlock(); + } + } + } + }; + QMutex mut; + TrylockThread t1(mut); + TrylockThread t2(mut); + TrylockThread t3(mut); + t1.start(); + t2.start(); + t3.start(); + + for (int i = 0; i < 100000; ++i) { + mut.lock(); + if ((++qtbug16115_trylock_counter) != 1) + ++qtbug16115_failure_count; + if ((--qtbug16115_trylock_counter) != 0) + ++qtbug16115_failure_count; + mut.unlock(); + } + t1.wait(); + t2.wait(); + t3.wait(); + 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/auto/corelib/thread/qmutexlocker/.gitignore b/tests/auto/corelib/thread/qmutexlocker/.gitignore new file mode 100644 index 0000000000..7c75c1c2f4 --- /dev/null +++ b/tests/auto/corelib/thread/qmutexlocker/.gitignore @@ -0,0 +1 @@ +tst_qmutexlocker diff --git a/tests/auto/corelib/thread/qmutexlocker/qmutexlocker.pro b/tests/auto/corelib/thread/qmutexlocker/qmutexlocker.pro new file mode 100644 index 0000000000..01c369101b --- /dev/null +++ b/tests/auto/corelib/thread/qmutexlocker/qmutexlocker.pro @@ -0,0 +1,4 @@ +load(qttest_p4) +SOURCES += tst_qmutexlocker.cpp +QT = core +CONFIG += parallel_test diff --git a/tests/auto/corelib/thread/qmutexlocker/tst_qmutexlocker.cpp b/tests/auto/corelib/thread/qmutexlocker/tst_qmutexlocker.cpp new file mode 100644 index 0000000000..a663b60be7 --- /dev/null +++ b/tests/auto/corelib/thread/qmutexlocker/tst_qmutexlocker.cpp @@ -0,0 +1,236 @@ +/**************************************************************************** +** +** 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 + +#include +#include +#include +#include + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QMutexLockerThread : public QThread +{ +public: + QMutex mutex; + QSemaphore semaphore, testSemaphore; + + void waitForTest() + { + semaphore.release(); + testSemaphore.acquire(); + } + + tst_QMutexLockerThread() + : mutex(QMutex::Recursive) + { + } +}; + +class tst_QMutexLocker : public QObject +{ + Q_OBJECT + +public: + tst_QMutexLocker(); + ~tst_QMutexLocker(); + + tst_QMutexLockerThread *thread; + + void waitForThread() + { + thread->semaphore.acquire(); + } + void releaseThread() + { + thread->testSemaphore.release(); + } + +private slots: + void scopeTest(); + void unlockAndRelockTest(); + void lockerStateTest(); +}; + +tst_QMutexLocker::tst_QMutexLocker() +{ +} + +tst_QMutexLocker::~tst_QMutexLocker() +{ +} + +void tst_QMutexLocker::scopeTest() +{ + class ScopeTestThread : public tst_QMutexLockerThread + { + public: + void run() + { + waitForTest(); + + { + QMutexLocker locker(&mutex); + waitForTest(); + } + + waitForTest(); + } + }; + + thread = new ScopeTestThread; + thread->start(); + + waitForThread(); + // mutex should be unlocked before entering the scope that creates the QMutexLocker + QVERIFY(thread->mutex.tryLock()); + thread->mutex.unlock(); + releaseThread(); + + waitForThread(); + // mutex should be locked by the QMutexLocker + QVERIFY(!thread->mutex.tryLock()); + releaseThread(); + + waitForThread(); + // mutex should be unlocked when the QMutexLocker goes out of scope + QVERIFY(thread->mutex.tryLock()); + thread->mutex.unlock(); + releaseThread(); + + QVERIFY(thread->wait()); + + delete thread; + thread = 0; +} + + +void tst_QMutexLocker::unlockAndRelockTest() +{ + class UnlockAndRelockThread : public tst_QMutexLockerThread + { + public: + void run() + { + QMutexLocker locker(&mutex); + + waitForTest(); + + locker.unlock(); + + waitForTest(); + + locker.relock(); + + waitForTest(); + } + }; + + thread = new UnlockAndRelockThread; + thread->start(); + + waitForThread(); + // mutex should be locked by the QMutexLocker + QVERIFY(!thread->mutex.tryLock()); + releaseThread(); + + waitForThread(); + // mutex has been explicitly unlocked via QMutexLocker + QVERIFY(thread->mutex.tryLock()); + thread->mutex.unlock(); + releaseThread(); + + waitForThread(); + // mutex has been explicitly relocked via QMutexLocker + QVERIFY(!thread->mutex.tryLock()); + releaseThread(); + + QVERIFY(thread->wait()); + + delete thread; + thread = 0; +} + +void tst_QMutexLocker::lockerStateTest() +{ + class LockerStateThread : public tst_QMutexLockerThread + { + public: + void run() + { + { + QMutexLocker locker(&mutex); + locker.relock(); + locker.unlock(); + + waitForTest(); + } + + waitForTest(); + } + }; + + thread = new LockerStateThread; + thread->start(); + + waitForThread(); + // even though we relock() after creating the QMutexLocker, it shouldn't lock the mutex more than once + QVERIFY(thread->mutex.tryLock()); + thread->mutex.unlock(); + releaseThread(); + + waitForThread(); + // if we call QMutexLocker::unlock(), its destructor should do nothing + QVERIFY(thread->mutex.tryLock()); + thread->mutex.unlock(); + releaseThread(); + + QVERIFY(thread->wait()); + + delete thread; + thread = 0; +} + +QTEST_MAIN(tst_QMutexLocker) +#include "tst_qmutexlocker.moc" diff --git a/tests/auto/corelib/thread/qreadlocker/.gitignore b/tests/auto/corelib/thread/qreadlocker/.gitignore new file mode 100644 index 0000000000..2539362670 --- /dev/null +++ b/tests/auto/corelib/thread/qreadlocker/.gitignore @@ -0,0 +1 @@ +tst_qreadlocker diff --git a/tests/auto/corelib/thread/qreadlocker/qreadlocker.pro b/tests/auto/corelib/thread/qreadlocker/qreadlocker.pro new file mode 100644 index 0000000000..ee533070a7 --- /dev/null +++ b/tests/auto/corelib/thread/qreadlocker/qreadlocker.pro @@ -0,0 +1,4 @@ +load(qttest_p4) +SOURCES += tst_qreadlocker.cpp +QT = core +CONFIG += parallel_test diff --git a/tests/auto/corelib/thread/qreadlocker/tst_qreadlocker.cpp b/tests/auto/corelib/thread/qreadlocker/tst_qreadlocker.cpp new file mode 100644 index 0000000000..3ec9f1cb25 --- /dev/null +++ b/tests/auto/corelib/thread/qreadlocker/tst_qreadlocker.cpp @@ -0,0 +1,231 @@ +/**************************************************************************** +** +** 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 + +#include +#include +#include +#include + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QReadLockerThread : public QThread +{ +public: + QReadWriteLock lock; + QSemaphore semaphore, testSemaphore; + + void waitForTest() + { + semaphore.release(); + testSemaphore.acquire(); + } +}; + +class tst_QReadLocker : public QObject +{ + Q_OBJECT + +public: + tst_QReadLocker(); + ~tst_QReadLocker(); + + tst_QReadLockerThread *thread; + + void waitForThread() + { + thread->semaphore.acquire(); + } + void releaseThread() + { + thread->testSemaphore.release(); + } + +private slots: + void scopeTest(); + void unlockAndRelockTest(); + void lockerStateTest(); +}; + +tst_QReadLocker::tst_QReadLocker() +{ +} + +tst_QReadLocker::~tst_QReadLocker() +{ +} + +void tst_QReadLocker::scopeTest() +{ + class ScopeTestThread : public tst_QReadLockerThread + { + public: + void run() + { + waitForTest(); + + { + QReadLocker locker(&lock); + waitForTest(); + } + + waitForTest(); + } + }; + + thread = new ScopeTestThread; + thread->start(); + + waitForThread(); + // lock should be unlocked before entering the scope that creates the QReadLocker + QVERIFY(thread->lock.tryLockForWrite()); + thread->lock.unlock(); + releaseThread(); + + waitForThread(); + // lock should be locked by the QReadLocker + QVERIFY(!thread->lock.tryLockForWrite()); + releaseThread(); + + waitForThread(); + // lock should be unlocked when the QReadLocker goes out of scope + QVERIFY(thread->lock.tryLockForWrite()); + thread->lock.unlock(); + releaseThread(); + + QVERIFY(thread->wait()); + + delete thread; + thread = 0; +} + + +void tst_QReadLocker::unlockAndRelockTest() +{ + class UnlockAndRelockThread : public tst_QReadLockerThread + { + public: + void run() + { + QReadLocker locker(&lock); + + waitForTest(); + + locker.unlock(); + + waitForTest(); + + locker.relock(); + + waitForTest(); + } + }; + + thread = new UnlockAndRelockThread; + thread->start(); + + waitForThread(); + // lock should be locked by the QReadLocker + QVERIFY(!thread->lock.tryLockForWrite()); + releaseThread(); + + waitForThread(); + // lock has been explicitly unlocked via QReadLocker + QVERIFY(thread->lock.tryLockForWrite()); + thread->lock.unlock(); + releaseThread(); + + waitForThread(); + // lock has been explicitly relocked via QReadLocker + QVERIFY(!thread->lock.tryLockForWrite()); + releaseThread(); + + QVERIFY(thread->wait()); + + delete thread; + thread = 0; +} + +void tst_QReadLocker::lockerStateTest() +{ + class LockerStateThread : public tst_QReadLockerThread + { + public: + void run() + { + { + QReadLocker locker(&lock); + locker.relock(); + locker.unlock(); + + waitForTest(); + } + + waitForTest(); + } + }; + + thread = new LockerStateThread; + thread->start(); + + waitForThread(); + // even though we relock() after creating the QReadLocker, it shouldn't lock the lock more than once + QVERIFY(thread->lock.tryLockForWrite()); + thread->lock.unlock(); + releaseThread(); + + waitForThread(); + // if we call QReadLocker::unlock(), its destructor should do nothing + QVERIFY(thread->lock.tryLockForWrite()); + thread->lock.unlock(); + releaseThread(); + + QVERIFY(thread->wait()); + + delete thread; + thread = 0; +} + +QTEST_MAIN(tst_QReadLocker) +#include "tst_qreadlocker.moc" diff --git a/tests/auto/corelib/thread/qreadwritelock/.gitignore b/tests/auto/corelib/thread/qreadwritelock/.gitignore new file mode 100644 index 0000000000..96fda685f5 --- /dev/null +++ b/tests/auto/corelib/thread/qreadwritelock/.gitignore @@ -0,0 +1 @@ +tst_qreadwritelock diff --git a/tests/auto/corelib/thread/qreadwritelock/qreadwritelock.pro b/tests/auto/corelib/thread/qreadwritelock/qreadwritelock.pro new file mode 100644 index 0000000000..93f7c68dc3 --- /dev/null +++ b/tests/auto/corelib/thread/qreadwritelock/qreadwritelock.pro @@ -0,0 +1,4 @@ +load(qttest_p4) +SOURCES += tst_qreadwritelock.cpp +QT = core +CONFIG += parallel_test diff --git a/tests/auto/corelib/thread/qreadwritelock/tst_qreadwritelock.cpp b/tests/auto/corelib/thread/qreadwritelock/tst_qreadwritelock.cpp new file mode 100644 index 0000000000..1b995e8d19 --- /dev/null +++ b/tests/auto/corelib/thread/qreadwritelock/tst_qreadwritelock.cpp @@ -0,0 +1,1140 @@ +/**************************************************************************** +** +** 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 +#include + + +#include +#include +#include +#include + +#ifdef Q_OS_UNIX +#include +#endif +#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) +#include +#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 + +//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= 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()start(); + for (i=0; iwait(); + for (i=0; istart(); + for (i=0; iwait(); + for (i=0; istart(QThread::NormalPriority); + for (i=0; istart(QThread::IdlePriority); + + for (i=0; iwait(); + for (i=0; iwait(); + + for (i=0; istart(QThread::NormalPriority); + for (i=0; istart(QThread::LowestPriority); + + for (i=0; iwait(); + for (i=0; iwait(); + + for (i=0; ilock(); + 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() 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" diff --git a/tests/auto/corelib/thread/qsemaphore/.gitignore b/tests/auto/corelib/thread/qsemaphore/.gitignore new file mode 100644 index 0000000000..fe86486af4 --- /dev/null +++ b/tests/auto/corelib/thread/qsemaphore/.gitignore @@ -0,0 +1 @@ +tst_qsemaphore diff --git a/tests/auto/corelib/thread/qsemaphore/qsemaphore.pro b/tests/auto/corelib/thread/qsemaphore/qsemaphore.pro new file mode 100644 index 0000000000..a75bf443bc --- /dev/null +++ b/tests/auto/corelib/thread/qsemaphore/qsemaphore.pro @@ -0,0 +1,7 @@ +load(qttest_p4) +SOURCES += tst_qsemaphore.cpp +QT = core + + +CONFIG += parallel_test +mac*:CONFIG+=insignificant_test diff --git a/tests/auto/corelib/thread/qsemaphore/tst_qsemaphore.cpp b/tests/auto/corelib/thread/qsemaphore/tst_qsemaphore.cpp new file mode 100644 index 0000000000..a2c6bf16b7 --- /dev/null +++ b/tests/auto/corelib/thread/qsemaphore/tst_qsemaphore.cpp @@ -0,0 +1,450 @@ +/**************************************************************************** +** +** 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 + + +#include +#include +#include + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QSemaphore : public QObject +{ + Q_OBJECT + +public: + tst_QSemaphore(); + ~tst_QSemaphore(); + +private slots: + void acquire(); + void tryAcquire(); + void tryAcquireWithTimeout_data(); + void tryAcquireWithTimeout(); + void tryAcquireWithTimeoutStarvation(); + void release(); + void available(); + void producerConsumer(); +}; + +static QSemaphore *semaphore = 0; + +tst_QSemaphore::tst_QSemaphore() +{ } + +tst_QSemaphore::~tst_QSemaphore() +{ } + +class ThreadOne : public QThread +{ +public: + ThreadOne() {} + +protected: + void run() + { + int i = 0; + while ( i < 100 ) { + semaphore->acquire(); + i++; + semaphore->release(); + } + } +}; + +class ThreadN : public QThread +{ + int N; + +public: + ThreadN(int n) :N(n) { } + +protected: + void run() + { + int i = 0; + while ( i < 100 ) { + semaphore->acquire(N); + i++; + semaphore->release(N); + } + } +}; + +void tst_QSemaphore::acquire() +{ + { + // old incrementOne() test + QVERIFY(!semaphore); + semaphore = new QSemaphore; + // make some "thing" available + semaphore->release(); + + ThreadOne t1; + ThreadOne t2; + + t1.start(); + t2.start(); + + QVERIFY(t1.wait(4000)); + QVERIFY(t2.wait(4000)); + + delete semaphore; + semaphore = 0; + } + + // old incrementN() test + { + QVERIFY(!semaphore); + semaphore = new QSemaphore; + // make 4 "things" available + semaphore->release(4); + + ThreadN t1(2); + ThreadN t2(3); + + t1.start(); + t2.start(); + + QVERIFY(t1.wait(4000)); + QVERIFY(t2.wait(4000)); + + delete semaphore; + semaphore = 0; + } + + QSemaphore semaphore; + + QCOMPARE(semaphore.available(), 0); + semaphore.release(); + QCOMPARE(semaphore.available(), 1); + semaphore.release(); + QCOMPARE(semaphore.available(), 2); + semaphore.release(10); + QCOMPARE(semaphore.available(), 12); + semaphore.release(10); + QCOMPARE(semaphore.available(), 22); + + semaphore.acquire(); + QCOMPARE(semaphore.available(), 21); + semaphore.acquire(); + QCOMPARE(semaphore.available(), 20); + semaphore.acquire(10); + QCOMPARE(semaphore.available(), 10); + semaphore.acquire(10); + QCOMPARE(semaphore.available(), 0); +} + +void tst_QSemaphore::tryAcquire() +{ + QSemaphore semaphore; + + QCOMPARE(semaphore.available(), 0); + + semaphore.release(); + QCOMPARE(semaphore.available(), 1); + QVERIFY(!semaphore.tryAcquire(2)); + QCOMPARE(semaphore.available(), 1); + + semaphore.release(); + QCOMPARE(semaphore.available(), 2); + QVERIFY(!semaphore.tryAcquire(3)); + QCOMPARE(semaphore.available(), 2); + + semaphore.release(10); + QCOMPARE(semaphore.available(), 12); + QVERIFY(!semaphore.tryAcquire(100)); + QCOMPARE(semaphore.available(), 12); + + semaphore.release(10); + QCOMPARE(semaphore.available(), 22); + QVERIFY(!semaphore.tryAcquire(100)); + QCOMPARE(semaphore.available(), 22); + + QVERIFY(semaphore.tryAcquire()); + QCOMPARE(semaphore.available(), 21); + + QVERIFY(semaphore.tryAcquire()); + QCOMPARE(semaphore.available(), 20); + + QVERIFY(semaphore.tryAcquire(10)); + QCOMPARE(semaphore.available(), 10); + + QVERIFY(semaphore.tryAcquire(10)); + QCOMPARE(semaphore.available(), 0); + + // should not be able to acquire more + QVERIFY(!semaphore.tryAcquire()); + QCOMPARE(semaphore.available(), 0); + + QVERIFY(!semaphore.tryAcquire()); + QCOMPARE(semaphore.available(), 0); + + QVERIFY(!semaphore.tryAcquire(10)); + QCOMPARE(semaphore.available(), 0); + + QVERIFY(!semaphore.tryAcquire(10)); + QCOMPARE(semaphore.available(), 0); +} + +void tst_QSemaphore::tryAcquireWithTimeout_data() +{ + QTest::addColumn("timeout"); + + QTest::newRow("1s") << 1000; + QTest::newRow("10s") << 10000; +} + +void tst_QSemaphore::tryAcquireWithTimeout() +{ + QFETCH(int, timeout); + + QSemaphore semaphore; + QTime time; + +#define QVERIFYGE(a,b) {int e = a; if (a= " << #b << "=" << b; QVERIFY(e>=b);} +#define QVERIFYLE(a,b) {int e = a; if (btryAcquire(amountToConsume, timeout)) + break; + semaphore->release(amountToConsume); + } + } + }; + + QSemaphore semaphore; + semaphore.release(1); + + Thread consumer; + consumer.semaphore = &semaphore; + consumer.amountToConsume = 1; + consumer.timeout = 1000; + + // start the thread and wait for it to start consuming + consumer.start(); + consumer.startup.acquire(); + + // try to consume more than the thread we started is, and provide a longer + // timeout... we should timeout, not wait indefinitely + QVERIFY(!semaphore.tryAcquire(consumer.amountToConsume * 2, consumer.timeout * 2)); + + // the consumer should still be running + QVERIFY(consumer.isRunning() && !consumer.isFinished()); + + // acquire, and wait for smallConsumer to timeout + semaphore.acquire(); + QVERIFY(consumer.wait()); +} + +void tst_QSemaphore::release() +{ DEPENDS_ON("acquire"); } + +void tst_QSemaphore::available() +{ DEPENDS_ON("acquire"); } + +const char alphabet[] = "ACGTH"; +const int AlphabetSize = sizeof(alphabet) - 1; + +const int BufferSize = 4096; // GCD of BufferSize and alphabet size must be 1 +char buffer[BufferSize]; + +#ifndef Q_OS_WINCE +const int ProducerChunkSize = 3; +const int ConsumerChunkSize = 7; +const int Multiplier = 10; +#else +const int ProducerChunkSize = 2; +const int ConsumerChunkSize = 5; +const int Multiplier = 3; +#endif + +// note: the code depends on the fact that DataSize is a multiple of +// ProducerChunkSize, ConsumerChunkSize, and BufferSize +const int DataSize = ProducerChunkSize * ConsumerChunkSize * BufferSize * Multiplier; + +QSemaphore freeSpace(BufferSize); +QSemaphore usedSpace; + +class Producer : public QThread +{ +public: + void run(); +}; + +void Producer::run() +{ + for (int i = 0; i < DataSize; ++i) { + freeSpace.acquire(); + buffer[i % BufferSize] = alphabet[i % AlphabetSize]; + usedSpace.release(); + } + for (int i = 0; i < DataSize; ++i) { + if ((i % ProducerChunkSize) == 0) + freeSpace.acquire(ProducerChunkSize); + buffer[i % BufferSize] = alphabet[i % AlphabetSize]; + if ((i % ProducerChunkSize) == (ProducerChunkSize - 1)) + usedSpace.release(ProducerChunkSize); + } +} + +class Consumer : public QThread +{ +public: + void run(); +}; + +void Consumer::run() +{ + for (int i = 0; i < DataSize; ++i) { + usedSpace.acquire(); + QCOMPARE(buffer[i % BufferSize], alphabet[i % AlphabetSize]); + freeSpace.release(); + } + for (int i = 0; i < DataSize; ++i) { + if ((i % ConsumerChunkSize) == 0) + usedSpace.acquire(ConsumerChunkSize); + QCOMPARE(buffer[i % BufferSize], alphabet[i % AlphabetSize]); + if ((i % ConsumerChunkSize) == (ConsumerChunkSize - 1)) + freeSpace.release(ConsumerChunkSize); + } +} + +void tst_QSemaphore::producerConsumer() +{ + Producer producer; + Consumer consumer; + producer.start(); + consumer.start(); + producer.wait(); + consumer.wait(); +} + +QTEST_MAIN(tst_QSemaphore) +#include "tst_qsemaphore.moc" diff --git a/tests/auto/corelib/thread/qthread/.gitignore b/tests/auto/corelib/thread/qthread/.gitignore new file mode 100644 index 0000000000..4413a75588 --- /dev/null +++ b/tests/auto/corelib/thread/qthread/.gitignore @@ -0,0 +1 @@ +tst_qthread diff --git a/tests/auto/corelib/thread/qthread/qthread.pro b/tests/auto/corelib/thread/qthread/qthread.pro new file mode 100644 index 0000000000..d3b1028034 --- /dev/null +++ b/tests/auto/corelib/thread/qthread/qthread.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +SOURCES += tst_qthread.cpp +QT = core +symbian:LIBS += -llibpthread +CONFIG += parallel_test diff --git a/tests/auto/corelib/thread/qthread/tst_qthread.cpp b/tests/auto/corelib/thread/qthread/tst_qthread.cpp new file mode 100644 index 0000000000..3c46212c16 --- /dev/null +++ b/tests/auto/corelib/thread/qthread/tst_qthread.cpp @@ -0,0 +1,1249 @@ +/**************************************************************************** +** +** 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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef Q_OS_UNIX +#include +#endif +#if defined(Q_OS_WINCE) +#include +#elif defined(Q_OS_WIN) +#include +#include +#endif + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QThread : public QObject +{ + Q_OBJECT + +public: + tst_QThread(); + virtual ~tst_QThread(); + +private slots: + void currentThreadId(); + void currentThread(); + void idealThreadCount(); + void isFinished(); + void isRunning(); + void setPriority(); + void priority(); + void setStackSize(); + void stackSize(); + void exit(); + void start(); + void terminate(); + void quit(); + void wait(); + void started(); + void finished(); + void terminated(); + void run(); + void exec(); + void setTerminationEnabled(); + void sleep(); + void msleep(); + void usleep(); + + void nativeThreadAdoption(); + void adoptedThreadAffinity(); + void adoptedThreadSetPriority(); + void adoptedThreadExit(); + void adoptedThreadExec(); + void adoptedThreadFinished(); + void adoptedThreadExecFinished(); + void adoptMultipleThreads(); + void adoptMultipleThreadsOverlap(); + + void QTBUG13810_exitAndStart(); + void QTBUG15378_exitAndExec(); + + void connectThreadFinishedSignalToObjectDeleteLaterSlot(); + void wait2(); + void wait3_slowDestructor(); + void destroyFinishRace(); + void startFinishRace(); + void startAndQuitCustomEventLoop(); + + void stressTest(); +}; + +enum { one_minute = 60 * 1000, five_minutes = 5 * one_minute }; + +class SignalRecorder : public QObject +{ + Q_OBJECT +public: + QAtomicInt activationCount; + + inline SignalRecorder() + { activationCount = 0; } + + bool wasActivated() + { return activationCount > 0; } + +public slots: + void slot(); +}; + +void SignalRecorder::slot() +{ activationCount.ref(); } + +class Current_Thread : public QThread +{ +public: + Qt::HANDLE id; + QThread *thread; + + void run() + { + id = QThread::currentThreadId(); + thread = QThread::currentThread(); + } +}; + +class Simple_Thread : public QThread +{ +public: + QMutex mutex; + QWaitCondition cond; + + void run() + { + QMutexLocker locker(&mutex); + cond.wakeOne(); + } +}; + +class Exit_Object : public QObject +{ + Q_OBJECT +public: + QThread *thread; + int code; +public slots: + void slot() + { thread->exit(code); } +}; + +class Exit_Thread : public Simple_Thread +{ +public: + Exit_Object *object; + int code; + int result; + + void run() + { + Simple_Thread::run(); + if (object) { + object->thread = this; + object->code = code; + QTimer::singleShot(100, object, SLOT(slot())); + } + result = exec(); + } +}; + +class Terminate_Thread : public Simple_Thread +{ +public: + void run() + { + setTerminationEnabled(false); + { + QMutexLocker locker(&mutex); + cond.wakeOne(); + cond.wait(&mutex, five_minutes); + } + setTerminationEnabled(true); + qFatal("tst_QThread: test case hung"); + } +}; + +class Quit_Object : public QObject +{ + Q_OBJECT +public: + QThread *thread; +public slots: + void slot() + { thread->quit(); } +}; + +class Quit_Thread : public Simple_Thread +{ +public: + Quit_Object *object; + int result; + + void run() + { + Simple_Thread::run(); + if (object) { + object->thread = this; + QTimer::singleShot(100, object, SLOT(slot())); + } + result = exec(); + } +}; + +class Sleep_Thread : public Simple_Thread +{ +public: + enum SleepType { Second, Millisecond, Microsecond }; + + SleepType sleepType; + int interval; + + int elapsed; // result, in *MILLISECONDS* + + void run() + { + QMutexLocker locker(&mutex); + + elapsed = 0; + QTime time; + time.start(); + switch (sleepType) { + case Second: + sleep(interval); + break; + case Millisecond: + msleep(interval); + break; + case Microsecond: + usleep(interval); + break; + } + elapsed = time.elapsed(); + + cond.wakeOne(); + } +}; + +tst_QThread::tst_QThread() + +{ +} + +tst_QThread::~tst_QThread() +{ + +} + +void tst_QThread::currentThreadId() +{ + Current_Thread thread; + thread.id = 0; + thread.thread = 0; + thread.start(); + QVERIFY(thread.wait(five_minutes)); + QVERIFY(thread.id != 0); + QVERIFY(thread.id != QThread::currentThreadId()); +} + +void tst_QThread::currentThread() +{ + QVERIFY(QThread::currentThread() != 0); + QCOMPARE(QThread::currentThread(), thread()); + + Current_Thread thread; + thread.id = 0; + thread.thread = 0; + thread.start(); + QVERIFY(thread.wait(five_minutes)); + QCOMPARE(thread.thread, (QThread *)&thread); +} + +void tst_QThread::idealThreadCount() +{ + QVERIFY(QThread::idealThreadCount() > 0); + qDebug() << "Available cpu cores:" << QThread::idealThreadCount(); +} + +void tst_QThread::isFinished() +{ + Simple_Thread thread; + QVERIFY(!thread.isFinished()); + QMutexLocker locker(&thread.mutex); + thread.start(); + QVERIFY(!thread.isFinished()); + thread.cond.wait(locker.mutex()); + QVERIFY(thread.wait(five_minutes)); + QVERIFY(thread.isFinished()); +} + +void tst_QThread::isRunning() +{ + Simple_Thread thread; + QVERIFY(!thread.isRunning()); + QMutexLocker locker(&thread.mutex); + thread.start(); + QVERIFY(thread.isRunning()); + thread.cond.wait(locker.mutex()); + QVERIFY(thread.wait(five_minutes)); + QVERIFY(!thread.isRunning()); +} + +void tst_QThread::setPriority() +{ + Simple_Thread thread; + + // cannot change the priority, since the thread is not running + QCOMPARE(thread.priority(), QThread::InheritPriority); + QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running"); + thread.setPriority(QThread::IdlePriority); + QCOMPARE(thread.priority(), QThread::InheritPriority); + QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running"); + thread.setPriority(QThread::LowestPriority); + QCOMPARE(thread.priority(), QThread::InheritPriority); + QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running"); + thread.setPriority(QThread::LowPriority); + QCOMPARE(thread.priority(), QThread::InheritPriority); + QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running"); + thread.setPriority(QThread::NormalPriority); + QCOMPARE(thread.priority(), QThread::InheritPriority); + QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running"); + thread.setPriority(QThread::HighPriority); + QCOMPARE(thread.priority(), QThread::InheritPriority); + QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running"); + thread.setPriority(QThread::HighestPriority); + QCOMPARE(thread.priority(), QThread::InheritPriority); + QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running"); + thread.setPriority(QThread::TimeCriticalPriority); + QCOMPARE(thread.priority(), QThread::InheritPriority); + + QCOMPARE(thread.priority(), QThread::InheritPriority); + QMutexLocker locker(&thread.mutex); + thread.start(); + + // change the priority of a running thread + QCOMPARE(thread.priority(), QThread::InheritPriority); + thread.setPriority(QThread::IdlePriority); + QCOMPARE(thread.priority(), QThread::IdlePriority); + thread.setPriority(QThread::LowestPriority); + QCOMPARE(thread.priority(), QThread::LowestPriority); + thread.setPriority(QThread::LowPriority); + QCOMPARE(thread.priority(), QThread::LowPriority); + thread.setPriority(QThread::NormalPriority); + QCOMPARE(thread.priority(), QThread::NormalPriority); + thread.setPriority(QThread::HighPriority); + QCOMPARE(thread.priority(), QThread::HighPriority); + thread.setPriority(QThread::HighestPriority); + QCOMPARE(thread.priority(), QThread::HighestPriority); + thread.setPriority(QThread::TimeCriticalPriority); + QCOMPARE(thread.priority(), QThread::TimeCriticalPriority); + thread.cond.wait(locker.mutex()); + QVERIFY(thread.wait(five_minutes)); + + QCOMPARE(thread.priority(), QThread::InheritPriority); + QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running"); + thread.setPriority(QThread::IdlePriority); + QCOMPARE(thread.priority(), QThread::InheritPriority); + QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running"); + thread.setPriority(QThread::LowestPriority); + QCOMPARE(thread.priority(), QThread::InheritPriority); + QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running"); + thread.setPriority(QThread::LowPriority); + QCOMPARE(thread.priority(), QThread::InheritPriority); + QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running"); + thread.setPriority(QThread::NormalPriority); + QCOMPARE(thread.priority(), QThread::InheritPriority); + QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running"); + thread.setPriority(QThread::HighPriority); + QCOMPARE(thread.priority(), QThread::InheritPriority); + QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running"); + thread.setPriority(QThread::HighestPriority); + QCOMPARE(thread.priority(), QThread::InheritPriority); + QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running"); + thread.setPriority(QThread::TimeCriticalPriority); + QCOMPARE(thread.priority(), QThread::InheritPriority); +} + +void tst_QThread::priority() +{ DEPENDS_ON("setPriority"); } + +void tst_QThread::setStackSize() +{ + Simple_Thread thread; + QCOMPARE(thread.stackSize(), 0u); + thread.setStackSize(8192u); + QCOMPARE(thread.stackSize(), 8192u); + thread.setStackSize(0u); + QCOMPARE(thread.stackSize(), 0u); +} + +void tst_QThread::stackSize() +{ + DEPENDS_ON("setStackSize"); +} + +void tst_QThread::exit() +{ + Exit_Thread thread; + thread.object = new Exit_Object; + thread.object->moveToThread(&thread); + thread.code = 42; + thread.result = 0; + QVERIFY(!thread.isFinished()); + QVERIFY(!thread.isRunning()); + QMutexLocker locker(&thread.mutex); + thread.start(); + QVERIFY(thread.isRunning()); + QVERIFY(!thread.isFinished()); + thread.cond.wait(locker.mutex()); + QVERIFY(thread.wait(five_minutes)); + QVERIFY(thread.isFinished()); + QVERIFY(!thread.isRunning()); + QCOMPARE(thread.result, thread.code); + delete thread.object; + + Exit_Thread thread2; + thread2.object = 0; + thread2.code = 53; + thread2.result = 0; + QMutexLocker locker2(&thread2.mutex); + thread2.start(); + thread2.exit(thread2.code); + thread2.cond.wait(locker2.mutex()); + QVERIFY(thread2.wait(five_minutes)); + QCOMPARE(thread2.result, thread2.code); +} + +void tst_QThread::start() +{ + QThread::Priority priorities[] = { + QThread::IdlePriority, + QThread::LowestPriority, + QThread::LowPriority, + QThread::NormalPriority, + QThread::HighPriority, + QThread::HighestPriority, + QThread::TimeCriticalPriority, + QThread::InheritPriority + }; + const int prio_count = sizeof(priorities) / sizeof(QThread::Priority); + + for (int i = 0; i < prio_count; ++i) { + Simple_Thread thread; + QVERIFY(!thread.isFinished()); + QVERIFY(!thread.isRunning()); + QMutexLocker locker(&thread.mutex); + thread.start(priorities[i]); + QVERIFY(thread.isRunning()); + QVERIFY(!thread.isFinished()); + thread.cond.wait(locker.mutex()); + QVERIFY(thread.wait(five_minutes)); + QVERIFY(thread.isFinished()); + QVERIFY(!thread.isRunning()); + } +} + +void tst_QThread::terminate() +{ + Terminate_Thread thread; + { + QMutexLocker locker(&thread.mutex); + thread.start(); + QVERIFY(thread.cond.wait(locker.mutex(), five_minutes)); + thread.terminate(); + thread.cond.wakeOne(); + } + QVERIFY(thread.wait(five_minutes)); +} + +void tst_QThread::quit() +{ + Quit_Thread thread; + thread.object = new Quit_Object; + thread.object->moveToThread(&thread); + thread.result = -1; + QVERIFY(!thread.isFinished()); + QVERIFY(!thread.isRunning()); + QMutexLocker locker(&thread.mutex); + thread.start(); + QVERIFY(thread.isRunning()); + QVERIFY(!thread.isFinished()); + thread.cond.wait(locker.mutex()); + QVERIFY(thread.wait(five_minutes)); + QVERIFY(thread.isFinished()); + QVERIFY(!thread.isRunning()); + QCOMPARE(thread.result, 0); + delete thread.object; + + Quit_Thread thread2; + thread2.object = 0; + thread2.result = -1; + QMutexLocker locker2(&thread2.mutex); + thread2.start(); + thread2.quit(); + thread2.cond.wait(locker2.mutex()); + QVERIFY(thread2.wait(five_minutes)); + QCOMPARE(thread2.result, 0); +} + +void tst_QThread::wait() +{ + DEPENDS_ON("isRunning"); + DEPENDS_ON("isFinished"); +} + +void tst_QThread::started() +{ + SignalRecorder recorder; + Simple_Thread thread; + connect(&thread, SIGNAL(started()), &recorder, SLOT(slot()), Qt::DirectConnection); + thread.start(); + QVERIFY(thread.wait(five_minutes)); + QVERIFY(recorder.wasActivated()); +} + +void tst_QThread::finished() +{ + SignalRecorder recorder; + Simple_Thread thread; + connect(&thread, SIGNAL(finished()), &recorder, SLOT(slot()), Qt::DirectConnection); + thread.start(); + QVERIFY(thread.wait(five_minutes)); + QVERIFY(recorder.wasActivated()); +} + +void tst_QThread::terminated() +{ + SignalRecorder recorder; + Terminate_Thread thread; + connect(&thread, SIGNAL(terminated()), &recorder, SLOT(slot()), Qt::DirectConnection); + { + QMutexLocker locker(&thread.mutex); + thread.start(); + thread.cond.wait(locker.mutex()); + thread.terminate(); + thread.cond.wakeOne(); + } + QVERIFY(thread.wait(five_minutes)); + QVERIFY(recorder.wasActivated()); +} + +void tst_QThread::run() +{ DEPENDS_ON("wait()"); } + +void tst_QThread::exec() +{ + DEPENDS_ON("exit()"); + DEPENDS_ON("quit()"); + + class MultipleExecThread : public QThread + { + public: + int res1, res2; + + MultipleExecThread() : res1(-2), res2(-2) { } + + void run() + { + { + Exit_Object o; + o.thread = this; + o.code = 1; + QTimer::singleShot(100, &o, SLOT(slot())); + res1 = exec(); + } + { + Exit_Object o; + o.thread = this; + o.code = 2; + QTimer::singleShot(100, &o, SLOT(slot())); + res2 = exec(); + } + } + }; + + MultipleExecThread thread; + thread.start(); + QVERIFY(thread.wait()); + + QCOMPARE(thread.res1, 1); + QCOMPARE(thread.res2, 2); +} + +void tst_QThread::setTerminationEnabled() +{ DEPENDS_ON("terminate"); } + +void tst_QThread::sleep() +{ + Sleep_Thread thread; + thread.sleepType = Sleep_Thread::Second; + thread.interval = 2; + thread.start(); + QVERIFY(thread.wait(five_minutes)); + QVERIFY(thread.elapsed >= 2000); +} + +void tst_QThread::msleep() +{ + Sleep_Thread thread; + thread.sleepType = Sleep_Thread::Millisecond; + thread.interval = 120; + thread.start(); + QVERIFY(thread.wait(five_minutes)); +#if defined (Q_OS_WIN) + // Since the resolution of QTime is so coarse... + QVERIFY(thread.elapsed >= 100); +#else + QVERIFY(thread.elapsed >= 120); +#endif +} + +void tst_QThread::usleep() +{ + Sleep_Thread thread; + thread.sleepType = Sleep_Thread::Microsecond; + thread.interval = 120000; + thread.start(); + QVERIFY(thread.wait(five_minutes)); +#if defined (Q_OS_WIN) + // Since the resolution of QTime is so coarse... + QVERIFY(thread.elapsed >= 100); +#else + QVERIFY(thread.elapsed >= 120); +#endif +} + +typedef void (*FunctionPointer)(void *); +void noop(void*) { } + +#ifdef Q_OS_SYMBIAN +typedef RThread ThreadHandle; +#elif defined Q_OS_UNIX + typedef pthread_t ThreadHandle; +#elif defined Q_OS_WIN + typedef HANDLE ThreadHandle; +#endif + +#ifdef Q_OS_WIN +#define WIN_FIX_STDCALL __stdcall +#else +#define WIN_FIX_STDCALL +#endif + +class NativeThreadWrapper +{ +public: + NativeThreadWrapper() : qthread(0), waitForStop(false) {} + void start(FunctionPointer functionPointer = noop, void *data = 0); + void startAndWait(FunctionPointer functionPointer = noop, void *data = 0); + void join(); + void setWaitForStop() { waitForStop = true; } + void stop(); + + ThreadHandle nativeThreadHandle; + QThread *qthread; + QWaitCondition startCondition; + QMutex mutex; + bool waitForStop; + QWaitCondition stopCondition; +protected: + static void *runUnix(void *data); + static unsigned WIN_FIX_STDCALL runWin(void *data); + static int runSymbian(void *data); + + FunctionPointer functionPointer; + void *data; +}; + +void NativeThreadWrapper::start(FunctionPointer functionPointer, void *data) +{ + this->functionPointer = functionPointer; + this->data = data; +#ifdef Q_OS_SYMBIAN + qt_symbian_throwIfError(nativeThreadHandle.Create(KNullDesC(), NativeThreadWrapper::runSymbian, 1024, &User::Allocator(), this)); + nativeThreadHandle.Resume(); +#elif defined Q_OS_UNIX + const int state = pthread_create(&nativeThreadHandle, 0, NativeThreadWrapper::runUnix, this); + Q_UNUSED(state); +#elif defined(Q_OS_WINCE) + nativeThreadHandle = CreateThread(NULL, 0 , (LPTHREAD_START_ROUTINE)NativeThreadWrapper::runWin , this, 0, NULL); +#elif defined Q_OS_WIN + unsigned thrdid = 0; + nativeThreadHandle = (Qt::HANDLE) _beginthreadex(NULL, 0, NativeThreadWrapper::runWin, this, 0, &thrdid); +#endif +} + +void NativeThreadWrapper::startAndWait(FunctionPointer functionPointer, void *data) +{ + QMutexLocker locker(&mutex); + start(functionPointer, data); + startCondition.wait(locker.mutex()); +} + +void NativeThreadWrapper::join() +{ +#ifdef Q_OS_SYMBIAN + TRequestStatus stat; + nativeThreadHandle.Logon(stat); + User::WaitForRequest(stat); + nativeThreadHandle.Close(); +#elif defined Q_OS_UNIX + pthread_join(nativeThreadHandle, 0); +#elif defined Q_OS_WIN + WaitForSingleObject(nativeThreadHandle, INFINITE); + CloseHandle(nativeThreadHandle); +#endif +} + +void *NativeThreadWrapper::runUnix(void *that) +{ + NativeThreadWrapper *nativeThreadWrapper = reinterpret_cast(that); + + // Adopt thread, create QThread object. + nativeThreadWrapper->qthread = QThread::currentThread(); + + // Release main thread. + { + QMutexLocker lock(&nativeThreadWrapper->mutex); + nativeThreadWrapper->startCondition.wakeOne(); + } + + // Run function. + nativeThreadWrapper->functionPointer(nativeThreadWrapper->data); + + // Wait for stop. + { + QMutexLocker lock(&nativeThreadWrapper->mutex); + if (nativeThreadWrapper->waitForStop) + nativeThreadWrapper->stopCondition.wait(lock.mutex()); + } + + return 0; +} + +unsigned WIN_FIX_STDCALL NativeThreadWrapper::runWin(void *data) +{ + runUnix(data); + return 0; +} + +int NativeThreadWrapper::runSymbian(void *data) +{ + runUnix(data); + return 0; +} + +void NativeThreadWrapper::stop() +{ + QMutexLocker lock(&mutex); + waitForStop = false; + stopCondition.wakeOne(); +} + +bool threadAdoptedOk = false; +QThread *mainThread; +void testNativeThreadAdoption(void *) +{ + threadAdoptedOk = (QThread::currentThreadId() != 0 + && QThread::currentThread() != 0 + && QThread::currentThread() != mainThread); +} +void tst_QThread::nativeThreadAdoption() +{ + threadAdoptedOk = false; + mainThread = QThread::currentThread(); + NativeThreadWrapper nativeThread; + nativeThread.setWaitForStop(); + nativeThread.startAndWait(testNativeThreadAdoption); + QVERIFY(nativeThread.qthread); + + nativeThread.stop(); + nativeThread.join(); + + QVERIFY(threadAdoptedOk); +} + +void adoptedThreadAffinityFunction(void *arg) +{ + QThread **affinity = reinterpret_cast(arg); + QThread *current = QThread::currentThread(); + affinity[0] = current; + affinity[1] = current->thread(); +} + +void tst_QThread::adoptedThreadAffinity() +{ + QThread *affinity[2] = { 0, 0 }; + + NativeThreadWrapper thread; + thread.startAndWait(adoptedThreadAffinityFunction, affinity); + thread.join(); + + // adopted thread should have affinity to itself + QCOMPARE(affinity[0], affinity[1]); +} + +void tst_QThread::adoptedThreadSetPriority() +{ + + NativeThreadWrapper nativeThread; + nativeThread.setWaitForStop(); + nativeThread.startAndWait(); + + // change the priority of a running thread + QCOMPARE(nativeThread.qthread->priority(), QThread::InheritPriority); + nativeThread.qthread->setPriority(QThread::IdlePriority); + QCOMPARE(nativeThread.qthread->priority(), QThread::IdlePriority); + nativeThread.qthread->setPriority(QThread::LowestPriority); + QCOMPARE(nativeThread.qthread->priority(), QThread::LowestPriority); + nativeThread.qthread->setPriority(QThread::LowPriority); + QCOMPARE(nativeThread.qthread->priority(), QThread::LowPriority); + nativeThread.qthread->setPriority(QThread::NormalPriority); + QCOMPARE(nativeThread.qthread->priority(), QThread::NormalPriority); + nativeThread.qthread->setPriority(QThread::HighPriority); + QCOMPARE(nativeThread.qthread->priority(), QThread::HighPriority); + nativeThread.qthread->setPriority(QThread::HighestPriority); + QCOMPARE(nativeThread.qthread->priority(), QThread::HighestPriority); + nativeThread.qthread->setPriority(QThread::TimeCriticalPriority); + QCOMPARE(nativeThread.qthread->priority(), QThread::TimeCriticalPriority); + + nativeThread.stop(); + nativeThread.join(); +} + +void tst_QThread::adoptedThreadExit() +{ + NativeThreadWrapper nativeThread; + nativeThread.setWaitForStop(); + + nativeThread.startAndWait(); + QVERIFY(nativeThread.qthread); + QVERIFY(nativeThread.qthread->isRunning()); + QVERIFY(!nativeThread.qthread->isFinished()); + + nativeThread.stop(); + nativeThread.join(); +} + +void adoptedThreadExecFunction(void *) +{ + QThread * const adoptedThread = QThread::currentThread(); + QEventLoop eventLoop(adoptedThread); + + const int code = 1; + Exit_Object o; + o.thread = adoptedThread; + o.code = code; + QTimer::singleShot(100, &o, SLOT(slot())); + + const int result = eventLoop.exec(); + QCOMPARE(result, code); +} + +void tst_QThread::adoptedThreadExec() +{ + NativeThreadWrapper nativeThread; + nativeThread.start(adoptedThreadExecFunction); + nativeThread.join(); +} + +/* + Test that you get the finished signal when an adopted thread exits. +*/ +void tst_QThread::adoptedThreadFinished() +{ + NativeThreadWrapper nativeThread; + nativeThread.setWaitForStop(); + nativeThread.startAndWait(); + + QObject::connect(nativeThread.qthread, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + + nativeThread.stop(); + nativeThread.join(); + + QTestEventLoop::instance().enterLoop(5); + QVERIFY(!QTestEventLoop::instance().timeout()); +} + +void tst_QThread::adoptedThreadExecFinished() +{ + NativeThreadWrapper nativeThread; + nativeThread.setWaitForStop(); + nativeThread.startAndWait(adoptedThreadExecFunction); + + QObject::connect(nativeThread.qthread, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + + nativeThread.stop(); + nativeThread.join(); + + QTestEventLoop::instance().enterLoop(5); + QVERIFY(!QTestEventLoop::instance().timeout()); +} + +void tst_QThread::adoptMultipleThreads() +{ +#if defined(Q_OS_WIN) + // Windows CE is not capable of handling that many threads. On the emulator it is dead with 26 threads already. +# if defined(Q_OS_WINCE) + const int numThreads = 20; +# else + // need to test lots of threads, so that we exceed MAXIMUM_WAIT_OBJECTS in qt_adopted_thread_watcher() + const int numThreads = 200; +# endif +#else + const int numThreads = 5; +#endif + QVector nativeThreads; + + SignalRecorder recorder; + + for (int i = 0; i < numThreads; ++i) { + nativeThreads.append(new NativeThreadWrapper()); + nativeThreads.at(i)->setWaitForStop(); + nativeThreads.at(i)->startAndWait(); + QObject::connect(nativeThreads.at(i)->qthread, SIGNAL(finished()), &recorder, SLOT(slot())); + } + + QObject::connect(nativeThreads.at(numThreads - 1)->qthread, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + + for (int i = 0; i < numThreads; ++i) { + nativeThreads.at(i)->stop(); + nativeThreads.at(i)->join(); + delete nativeThreads.at(i); + } + + QTestEventLoop::instance().enterLoop(5); + QVERIFY(!QTestEventLoop::instance().timeout()); + QCOMPARE(int(recorder.activationCount), numThreads); +} + +void tst_QThread::adoptMultipleThreadsOverlap() +{ +#if defined(Q_OS_WIN) + // Windows CE is not capable of handling that many threads. On the emulator it is dead with 26 threads already. +# if defined(Q_OS_WINCE) + const int numThreads = 20; +# else + // need to test lots of threads, so that we exceed MAXIMUM_WAIT_OBJECTS in qt_adopted_thread_watcher() + const int numThreads = 200; +# endif +#elif defined(Q_OS_SYMBIAN) + // stress the monitoring thread's add function + const int numThreads = 100; +#else + const int numThreads = 5; +#endif + QVector nativeThreads; + + SignalRecorder recorder; + + for (int i = 0; i < numThreads; ++i) { + nativeThreads.append(new NativeThreadWrapper()); + nativeThreads.at(i)->setWaitForStop(); + nativeThreads.at(i)->mutex.lock(); + nativeThreads.at(i)->start(); + } + for (int i = 0; i < numThreads; ++i) { + nativeThreads.at(i)->startCondition.wait(&nativeThreads.at(i)->mutex); + QObject::connect(nativeThreads.at(i)->qthread, SIGNAL(finished()), &recorder, SLOT(slot())); + nativeThreads.at(i)->mutex.unlock(); + } + + QObject::connect(nativeThreads.at(numThreads - 1)->qthread, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + + for (int i = 0; i < numThreads; ++i) { + nativeThreads.at(i)->stop(); + nativeThreads.at(i)->join(); + delete nativeThreads.at(i); + } + + QTestEventLoop::instance().enterLoop(5); + QVERIFY(!QTestEventLoop::instance().timeout()); + QCOMPARE(int(recorder.activationCount), numThreads); +} +void tst_QThread::stressTest() +{ +#if defined(Q_OS_WINCE) + QSKIP("Disconnects on WinCE, skipping...", SkipAll); +#endif + QTime t; + t.start(); + while (t.elapsed() < one_minute) { + Current_Thread t; + t.start(); + t.wait(one_minute); + } +} + +class Syncronizer : public QObject +{ Q_OBJECT +public slots: + void setProp(int p) { + if(m_prop != p) { + m_prop = p; + emit propChanged(p); + } + } +signals: + void propChanged(int); +public: + Syncronizer() : m_prop(42) {} + int m_prop; +}; + +void tst_QThread::QTBUG13810_exitAndStart() +{ + QThread thread; + thread.exit(555); //should do nothing + + thread.start(); + + //test that the thread is running by executing queued connected signal there + Syncronizer sync1; + sync1.moveToThread(&thread); + Syncronizer sync2; + sync2.moveToThread(&thread); + connect(&sync2, SIGNAL(propChanged(int)), &sync1, SLOT(setProp(int)), Qt::QueuedConnection); + connect(&sync1, SIGNAL(propChanged(int)), &thread, SLOT(quit()), Qt::QueuedConnection); + QMetaObject::invokeMethod(&sync2, "setProp", Qt::QueuedConnection , Q_ARG(int, 89)); + QTest::qWait(50); + while(!thread.wait(10)) + QTest::qWait(10); + QCOMPARE(sync2.m_prop, 89); + QCOMPARE(sync1.m_prop, 89); +} + +void tst_QThread::QTBUG15378_exitAndExec() +{ + class Thread : public QThread { + public: + QSemaphore sem1; + QSemaphore sem2; + volatile int value; + void run() { + sem1.acquire(); + value = exec(); //First entrence + sem2.release(); + value = exec(); // Second loop + } + }; + Thread thread; + thread.value = 0; + thread.start(); + thread.exit(556); + thread.sem1.release(); //should exit the first loop + thread.sem2.acquire(); + int v = thread.value; + QCOMPARE(v, 556); + + //test that the thread is running by executing queued connected signal there + Syncronizer sync1; + sync1.moveToThread(&thread); + Syncronizer sync2; + sync2.moveToThread(&thread); + connect(&sync2, SIGNAL(propChanged(int)), &sync1, SLOT(setProp(int)), Qt::QueuedConnection); + connect(&sync1, SIGNAL(propChanged(int)), &thread, SLOT(quit()), Qt::QueuedConnection); + QMetaObject::invokeMethod(&sync2, "setProp", Qt::QueuedConnection , Q_ARG(int, 89)); + QTest::qWait(50); + while(!thread.wait(10)) + QTest::qWait(10); + QCOMPARE(sync2.m_prop, 89); + QCOMPARE(sync1.m_prop, 89); +} + +void tst_QThread::connectThreadFinishedSignalToObjectDeleteLaterSlot() +{ + QThread thread; + QObject *object = new QObject; + QWeakPointer p = object; + QVERIFY(!p.isNull()); + connect(&thread, SIGNAL(started()), &thread, SLOT(quit()), Qt::DirectConnection); + connect(&thread, SIGNAL(finished()), object, SLOT(deleteLater())); + object->moveToThread(&thread); + thread.start(); + QVERIFY(thread.wait(30000)); + QVERIFY(p.isNull()); +} + +class Waiting_Thread : public QThread +{ +public: + enum { WaitTime = 800 }; + QMutex mutex; + QWaitCondition cond1; + QWaitCondition cond2; + + void run() + { + QMutexLocker locker(&mutex); + cond1.wait(&mutex); + cond2.wait(&mutex, WaitTime); + } +}; + +void tst_QThread::wait2() +{ + QElapsedTimer timer; + Waiting_Thread thread; + thread.start(); + timer.start(); + QVERIFY(!thread.wait(Waiting_Thread::WaitTime)); + qint64 elapsed = timer.elapsed(); + + QVERIFY(elapsed >= Waiting_Thread::WaitTime); + //QVERIFY(elapsed < Waiting_Thread::WaitTime * 1.4); + + timer.start(); + thread.cond1.wakeOne(); + QVERIFY(thread.wait(/*Waiting_Thread::WaitTime * 1.4*/)); + elapsed = timer.elapsed(); + QVERIFY(elapsed >= Waiting_Thread::WaitTime); + //QVERIFY(elapsed < Waiting_Thread::WaitTime * 1.4); +} + + +class SlowSlotObject : public QObject { + Q_OBJECT +public: + QMutex mutex; + QWaitCondition cond; +public slots: + void slowSlot() { + QMutexLocker locker(&mutex); + cond.wait(&mutex); + } +}; + +void tst_QThread::wait3_slowDestructor() +{ + SlowSlotObject slow; + QThread thread; + QObject::connect(&thread, SIGNAL(finished()), &slow, SLOT(slowSlot()), Qt::DirectConnection); + + enum { WaitTime = 1800 }; + QElapsedTimer timer; + + thread.start(); + thread.quit(); + //the quit function will cause the thread to finish and enter the slowSlot that is blocking + + timer.start(); + QVERIFY(!thread.wait(Waiting_Thread::WaitTime)); + qint64 elapsed = timer.elapsed(); + + QVERIFY(elapsed >= Waiting_Thread::WaitTime); + //QVERIFY(elapsed < Waiting_Thread::WaitTime * 1.4); + + slow.cond.wakeOne(); + //now the thread should finish quickly + QVERIFY(thread.wait(one_minute)); +} + +void tst_QThread::destroyFinishRace() +{ + class Thread : public QThread { void run() {} }; + for (int i = 0; i < 15; i++) { + Thread *thr = new Thread; + connect(thr, SIGNAL(finished()), thr, SLOT(deleteLater())); + QWeakPointer weak(static_cast(thr)); + thr->start(); + while (weak) { + qApp->processEvents(); + qApp->processEvents(); + qApp->processEvents(); + qApp->processEvents(); + } + } +} + +void tst_QThread::startFinishRace() +{ + class Thread : public QThread { + public: + Thread() : i (50) {} + void run() { + i--; + if (!i) disconnect(this, SIGNAL(finished()), 0, 0); + } + int i; + }; + for (int i = 0; i < 15; i++) { + Thread thr; + connect(&thr, SIGNAL(finished()), &thr, SLOT(start())); + thr.start(); + while (!thr.isFinished() || thr.i != 0) { + qApp->processEvents(); + qApp->processEvents(); + qApp->processEvents(); + qApp->processEvents(); + } + QCOMPARE(thr.i, 0); + } +} + +void tst_QThread::startAndQuitCustomEventLoop() +{ + struct Thread : QThread { + void run() { QEventLoop().exec(); } + }; + + for (int i = 0; i < 5; i++) { + Thread t; + t.start(); + t.quit(); + t.wait(); + } +} + + +QTEST_MAIN(tst_QThread) +#include "tst_qthread.moc" diff --git a/tests/auto/corelib/thread/qthreadonce/.gitignore b/tests/auto/corelib/thread/qthreadonce/.gitignore new file mode 100644 index 0000000000..856177d615 --- /dev/null +++ b/tests/auto/corelib/thread/qthreadonce/.gitignore @@ -0,0 +1 @@ +tst_qthreadonce diff --git a/tests/auto/corelib/thread/qthreadonce/qthreadonce.cpp b/tests/auto/corelib/thread/qthreadonce/qthreadonce.cpp new file mode 100644 index 0000000000..b23e11b153 --- /dev/null +++ b/tests/auto/corelib/thread/qthreadonce/qthreadonce.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** 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 "qplatformdefs.h" +#include "qthreadonce.h" + +#ifndef QT_NO_THREAD +#include "qmutex.h" + +Q_GLOBAL_STATIC_WITH_ARGS(QMutex, onceInitializationMutex, (QMutex::Recursive)) + +enum QOnceExtra { + MustRunCode = 0x01, + MustUnlockMutex = 0x02 +}; + +/*! + \internal + Initialize the Q_ONCE structure. + + Q_ONCE consists of two variables: + - a static POD QOnceControl::ControlVariable (it's a QBasicAtomicInt) + - an automatic QOnceControl that controls the former + + The POD is initialized to 0. + + When QOnceControl's constructor starts, it'll lock the global + initialization mutex. It'll then check if it's the first to up + the control variable and will take note. + + The QOnceControl's destructor will unlock the global + initialization mutex. +*/ +QOnceControl::QOnceControl(QBasicAtomicInt *control) +{ + d = 0; + gv = control; + // check if code has already run once + if (*gv == 2) { + // uncontended case: it has already initialized + // no waiting + return; + } + + // acquire the path + onceInitializationMutex()->lock(); + extra = MustUnlockMutex; + + if (gv->testAndSetAcquire(0, 1)) { + // path acquired, we're the first + extra |= MustRunCode; + } +} + +QOnceControl::~QOnceControl() +{ + if (mustRunCode()) + // code wasn't run! + gv->testAndSetRelease(1, 0); + else + gv->testAndSetRelease(1, 2); + if (extra & MustUnlockMutex) + onceInitializationMutex()->unlock(); +} + +/*! + \internal + Returns true if the initialization code must be run. + + Obviously, the initialization code must be run only once... +*/ +bool QOnceControl::mustRunCode() +{ + return extra & MustRunCode; +} + +void QOnceControl::done() +{ + extra &= ~MustRunCode; +} + +#endif // QT_NO_THREAD diff --git a/tests/auto/corelib/thread/qthreadonce/qthreadonce.h b/tests/auto/corelib/thread/qthreadonce/qthreadonce.h new file mode 100644 index 0000000000..c33625cbde --- /dev/null +++ b/tests/auto/corelib/thread/qthreadonce/qthreadonce.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + + +#ifndef QTHREADONCE_H +#define QTHREADONCE_H + +#include +#include + +QT_BEGIN_HEADER + +QT_MODULE(Core) + +#ifndef QT_NO_THREAD + +class QOnceControl +{ +public: + QOnceControl(QBasicAtomicInt *); + ~QOnceControl(); + + bool mustRunCode(); + void done(); + +private: + QBasicAtomicInt *gv; + union { + qint32 extra; + void *d; + }; +}; + +#define Q_ONCE_GV_NAME2(prefix, line) prefix ## line +#define Q_ONCE_GV_NAME(prefix, line) Q_ONCE_GV_NAME2(prefix, line) +#define Q_ONCE_GV Q_ONCE_GV_NAME(_q_once_, __LINE__) + +#define Q_ONCE \ + static QBasicAtomicInt Q_ONCE_GV = Q_BASIC_ATOMIC_INITIALIZER(0); \ + if (0){} else \ + for (QOnceControl _control_(&Q_ONCE_GV); _control_.mustRunCode(); _control_.done()) + +template +class QSingleton +{ + // this is a POD-like class + struct Destructor + { + T *&pointer; + Destructor(T *&ptr) : pointer(ptr) {} + ~Destructor() { delete pointer; } + }; + +public: + T *_q_value; + QBasicAtomicInt _q_guard; + + inline T *value() + { + for (QOnceControl control(&_q_guard); control.mustRunCode(); control.done()) { + _q_value = new T(); + static Destructor cleanup(_q_value); + } + return _q_value; + } + + inline T& operator*() { return *value(); } + inline T* operator->() { return value(); } + inline operator T*() { return value(); } +}; + +#endif // QT_NO_THREAD + +QT_END_HEADER + +#endif diff --git a/tests/auto/corelib/thread/qthreadonce/qthreadonce.pro b/tests/auto/corelib/thread/qthreadonce/qthreadonce.pro new file mode 100644 index 0000000000..d7ef4d4c23 --- /dev/null +++ b/tests/auto/corelib/thread/qthreadonce/qthreadonce.pro @@ -0,0 +1,13 @@ +load(qttest_p4) +SOURCES += tst_qthreadonce.cpp +QT = core + +# Don't use gcc's threadsafe statics +# Note: some versions of gcc generate invalid code with this option... +# Some versions of gcc don't even have it, so disable it +#*-g++*:QMAKE_CXXFLAGS += -fno-threadsafe-statics + +# Temporary: +SOURCES += qthreadonce.cpp + +CONFIG += parallel_test diff --git a/tests/auto/corelib/thread/qthreadonce/tst_qthreadonce.cpp b/tests/auto/corelib/thread/qthreadonce/tst_qthreadonce.cpp new file mode 100644 index 0000000000..dea4e43fef --- /dev/null +++ b/tests/auto/corelib/thread/qthreadonce/tst_qthreadonce.cpp @@ -0,0 +1,234 @@ +/**************************************************************************** +** +** 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 + +#include +#include +#include +#include +#include "qthreadonce.h" + +//TESTED_CLASS= +//TESTED_FILES=corelib/thread/qthreadonce.h corelib/thread/qthreadonce.cpp + +class tst_QThreadOnce : public QObject +{ + Q_OBJECT + +private slots: + void sameThread(); + void sameThread_data(); + void multipleThreads(); + + void nesting(); + void reentering(); + void exception(); +}; + +class SingletonObject: public QObject +{ + Q_OBJECT +public: + static int runCount; + SingletonObject() { val = 42; ++runCount; } + ~SingletonObject() { } + + QBasicAtomicInt val; +}; + +class IncrementThread: public QThread +{ +public: + static QBasicAtomicInt runCount; + static QSingleton singleton; + QSemaphore &sem1, &sem2; + int &var; + + IncrementThread(QSemaphore *psem1, QSemaphore *psem2, int *pvar, QObject *parent) + : QThread(parent), sem1(*psem1), sem2(*psem2), var(*pvar) + { start(); } + + ~IncrementThread() { wait(); } + +protected: + void run() + { + sem2.release(); + sem1.acquire(); // synchronize + + Q_ONCE { + ++var; + } + runCount.ref(); + singleton->val.ref(); + } +}; +int SingletonObject::runCount = 0; +QBasicAtomicInt IncrementThread::runCount = Q_BASIC_ATOMIC_INITIALIZER(0); +QSingleton IncrementThread::singleton; + +void tst_QThreadOnce::sameThread_data() +{ + SingletonObject::runCount = 0; + QTest::addColumn("expectedValue"); + + QTest::newRow("first") << 42; + QTest::newRow("second") << 43; +} + +void tst_QThreadOnce::sameThread() +{ + static int controlVariable = 0; + Q_ONCE { + QCOMPARE(controlVariable, 0); + ++controlVariable; + } + QCOMPARE(controlVariable, 1); + + static QSingleton s; + QTEST((int)s->val, "expectedValue"); + s->val.ref(); + + QCOMPARE(SingletonObject::runCount, 1); +} + +void tst_QThreadOnce::multipleThreads() +{ +#if defined(Q_OS_WINCE) || defined(Q_OS_VXWORKS) || defined(Q_OS_SYMBIAN) + const int NumberOfThreads = 20; +#else + const int NumberOfThreads = 100; +#endif + int controlVariable = 0; + QSemaphore sem1, sem2(NumberOfThreads); + + QObject *parent = new QObject; + for (int i = 0; i < NumberOfThreads; ++i) + new IncrementThread(&sem1, &sem2, &controlVariable, parent); + + QCOMPARE(controlVariable, 0); // nothing must have set them yet + SingletonObject::runCount = 0; + IncrementThread::runCount = 0; + + // wait for all of them to be ready + sem2.acquire(NumberOfThreads); + // unleash the threads + sem1.release(NumberOfThreads); + + // wait for all of them to terminate: + delete parent; + + QCOMPARE(controlVariable, 1); + QCOMPARE((int)IncrementThread::runCount, NumberOfThreads); + QCOMPARE(SingletonObject::runCount, 1); +} + +void tst_QThreadOnce::nesting() +{ + int variable = 0; + Q_ONCE { + Q_ONCE { + ++variable; + } + } + + QVERIFY(variable == 1); +} + +static void reentrant(int control, int &counter) +{ + Q_ONCE { + if (counter) + reentrant(--control, counter); + ++counter; + } + static QSingleton s; + s->val.ref(); +} + +void tst_QThreadOnce::reentering() +{ + const int WantedRecursions = 5; + int count = 0; + SingletonObject::runCount = 0; + reentrant(WantedRecursions, count); + + // reentrancy is undefined behavior: + QVERIFY(count == 1 || count == WantedRecursions); + QCOMPARE(SingletonObject::runCount, 1); +} + +#if !defined(QT_NO_EXCEPTIONS) +static void exception_helper(int &val) +{ + Q_ONCE { + if (val++ == 0) throw 0; + } +} +#endif + +void tst_QThreadOnce::exception() +{ +#if defined(QT_NO_EXCEPTIONS) + QSKIP("Compiled without exceptions, skipping test", SkipAll); +#else + int count = 0; + + try { + exception_helper(count); + } catch (...) { + // nothing + } + QCOMPARE(count, 1); + + try { + exception_helper(count); + } catch (...) { + QVERIFY2(false, "Exception shouldn't have been thrown..."); + } + QCOMPARE(count, 2); +#endif +} + +QTEST_MAIN(tst_QThreadOnce) +#include "tst_qthreadonce.moc" diff --git a/tests/auto/corelib/thread/qthreadstorage/.gitignore b/tests/auto/corelib/thread/qthreadstorage/.gitignore new file mode 100644 index 0000000000..301968a8f6 --- /dev/null +++ b/tests/auto/corelib/thread/qthreadstorage/.gitignore @@ -0,0 +1 @@ +tst_qthreadstorage diff --git a/tests/auto/corelib/thread/qthreadstorage/crashOnExit.cpp b/tests/auto/corelib/thread/qthreadstorage/crashOnExit.cpp new file mode 100644 index 0000000000..92efcf3b3d --- /dev/null +++ b/tests/auto/corelib/thread/qthreadstorage/crashOnExit.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** 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 + +class Class +{ +public: + ~Class() + { + // trigger creation of a new QThreadStorage, after the previous QThreadStorage from main() was destructed + static QThreadStorage threadstorage; + threadstorage.setLocalData(new int); + threadstorage.setLocalData(new int); + } +}; + +int main() +{ + // instantiate the class that will use QThreadStorage from its destructor, it's destructor will be run last + static Class instance; + // instantiate QThreadStorage, it's destructor (and the global destructors for QThreadStorages internals) will run first + static QThreadStorage threadstorage; + threadstorage.setLocalData(new int); + threadstorage.setLocalData(new int); +} diff --git a/tests/auto/corelib/thread/qthreadstorage/crashOnExit.pro b/tests/auto/corelib/thread/qthreadstorage/crashOnExit.pro new file mode 100644 index 0000000000..918ef398ba --- /dev/null +++ b/tests/auto/corelib/thread/qthreadstorage/crashOnExit.pro @@ -0,0 +1,4 @@ +SOURCES += crashOnExit.cpp +QT = core +CONFIG-=app_bundle +CONFIG+=console diff --git a/tests/auto/corelib/thread/qthreadstorage/qthreadstorage.pro b/tests/auto/corelib/thread/qthreadstorage/qthreadstorage.pro new file mode 100644 index 0000000000..0dc8d086df --- /dev/null +++ b/tests/auto/corelib/thread/qthreadstorage/qthreadstorage.pro @@ -0,0 +1,5 @@ +TEMPLATE = subdirs +SUBDIRS = \ + tst_qthreadstorage.pro \ + crashOnExit.pro +CONFIG += parallel_test diff --git a/tests/auto/corelib/thread/qthreadstorage/tst_qthreadstorage.cpp b/tests/auto/corelib/thread/qthreadstorage/tst_qthreadstorage.cpp new file mode 100644 index 0000000000..e123fc4fea --- /dev/null +++ b/tests/auto/corelib/thread/qthreadstorage/tst_qthreadstorage.cpp @@ -0,0 +1,503 @@ +/**************************************************************************** +** +** 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 + +#include +#include +#include +#include +#include + +#ifdef Q_OS_UNIX +#include +#endif +#ifdef Q_OS_WIN +#ifndef Q_OS_WINCE +#include +#endif +#include +#endif + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QThreadStorage : public QObject +{ + Q_OBJECT + +public: + tst_QThreadStorage(); + +private slots: + void hasLocalData(); + void localData(); + void localData_const(); + void setLocalData(); + void autoDelete(); + void adoptedThreads(); + void ensureCleanupOrder(); + void QTBUG13877_crashOnExit(); + void QTBUG14579_leakInDestructor(); + void QTBUG14579_resetInDestructor(); + void valueBased(); +}; + +class Pointer +{ +public: + static int count; + inline Pointer() { ++count; } + inline ~Pointer() { --count; } +}; +int Pointer::count = 0; + +tst_QThreadStorage::tst_QThreadStorage() + +{ } + +void tst_QThreadStorage::hasLocalData() +{ + QThreadStorage pointers; + QVERIFY(!pointers.hasLocalData()); + pointers.setLocalData(new Pointer); + QVERIFY(pointers.hasLocalData()); + pointers.setLocalData(0); + QVERIFY(!pointers.hasLocalData()); +} + +void tst_QThreadStorage::localData() +{ + QThreadStorage pointers; + Pointer *p = new Pointer; + QVERIFY(!pointers.hasLocalData()); + pointers.setLocalData(p); + QVERIFY(pointers.hasLocalData()); + QCOMPARE(pointers.localData(), p); + pointers.setLocalData(0); + QCOMPARE(pointers.localData(), (Pointer *)0); + QVERIFY(!pointers.hasLocalData()); +} + +void tst_QThreadStorage::localData_const() +{ + QThreadStorage pointers; + const QThreadStorage &const_pointers = pointers; + Pointer *p = new Pointer; + QVERIFY(!pointers.hasLocalData()); + pointers.setLocalData(p); + QVERIFY(pointers.hasLocalData()); + QCOMPARE(const_pointers.localData(), p); + pointers.setLocalData(0); + QCOMPARE(const_pointers.localData(), (Pointer *)0); + QVERIFY(!pointers.hasLocalData()); +} + +void tst_QThreadStorage::setLocalData() +{ + QThreadStorage pointers; + QVERIFY(!pointers.hasLocalData()); + pointers.setLocalData(new Pointer); + QVERIFY(pointers.hasLocalData()); + pointers.setLocalData(0); + QVERIFY(!pointers.hasLocalData()); +} + +class Thread : public QThread +{ +public: + QThreadStorage &pointers; + + QMutex mutex; + QWaitCondition cond; + + Thread(QThreadStorage &p) + : pointers(p) + { } + + void run() + { + pointers.setLocalData(new Pointer); + + QMutexLocker locker(&mutex); + cond.wakeOne(); + cond.wait(&mutex); + } +}; + +void tst_QThreadStorage::autoDelete() +{ + QThreadStorage pointers; + QVERIFY(!pointers.hasLocalData()); + + Thread thread(pointers); + int c = Pointer::count; + { + QMutexLocker locker(&thread.mutex); + thread.start(); + thread.cond.wait(&thread.mutex); + // QCOMPARE(Pointer::count, c + 1); + thread.cond.wakeOne(); + } + thread.wait(); + QCOMPARE(Pointer::count, c); +} + +bool threadStorageOk; +void testAdoptedThreadStorageWin(void *p) +{ + QThreadStorage *pointers = reinterpret_cast *>(p); + if (pointers->hasLocalData()) { + threadStorageOk = false; + return; + } + + Pointer *pointer = new Pointer(); + pointers->setLocalData(pointer); + + if (pointers->hasLocalData() == false) { + threadStorageOk = false; + return; + } + + if (pointers->localData() != pointer) { + threadStorageOk = false; + return; + } + QObject::connect(QThread::currentThread(), SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); +} +void *testAdoptedThreadStorageUnix(void *pointers) +{ + testAdoptedThreadStorageWin(pointers); + return 0; +} +void tst_QThreadStorage::adoptedThreads() +{ + QTestEventLoop::instance(); // Make sure the instance is created in this thread. + QThreadStorage pointers; + int c = Pointer::count; + threadStorageOk = true; + { +#ifdef Q_OS_UNIX + pthread_t thread; + const int state = pthread_create(&thread, 0, testAdoptedThreadStorageUnix, &pointers); + QCOMPARE(state, 0); + pthread_join(thread, 0); +#elif defined Q_OS_WIN + HANDLE thread; +#if defined(Q_OS_WINCE) + thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)testAdoptedThreadStorageWin, &pointers, 0, NULL); +#else + thread = (HANDLE)_beginthread(testAdoptedThreadStorageWin, 0, &pointers); +#endif + QVERIFY(thread); + WaitForSingleObject(thread, INFINITE); +#endif + } + QVERIFY(threadStorageOk); + + QTestEventLoop::instance().enterLoop(2); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(Pointer::count, c); +} + +QBasicAtomicInt cleanupOrder = Q_BASIC_ATOMIC_INITIALIZER(0); + +class First +{ +public: + ~First() + { + order = cleanupOrder.fetchAndAddRelaxed(1); + } + static int order; +}; +int First::order = -1; + +class Second +{ +public: + ~Second() + { + order = cleanupOrder.fetchAndAddRelaxed(1); + } + static int order; +}; +int Second::order = -1; + +void tst_QThreadStorage::ensureCleanupOrder() +{ + class Thread : public QThread + { + public: + QThreadStorage &first; + QThreadStorage &second; + + Thread(QThreadStorage &first, + QThreadStorage &second) + : first(first), second(second) + { } + + void run() + { + // set in reverse order, but shouldn't matter, the data + // will be deleted in the order the thread storage objects + // were created + second.setLocalData(new Second); + first.setLocalData(new First); + } + }; + + QThreadStorage second; + QThreadStorage first; + Thread thread(first, second); + thread.start(); + thread.wait(); + + QVERIFY(First::order < Second::order); +} + +void tst_QThreadStorage::QTBUG13877_crashOnExit() +{ + QProcess process; +#ifdef Q_OS_WIN +# ifdef QT_NO_DEBUG + process.start("release/crashOnExit"); +# else + process.start("debug/crashOnExit"); +# endif +#else + process.start("./crashOnExit"); +#endif + QVERIFY(process.waitForFinished()); + QVERIFY(process.exitStatus() != QProcess::CrashExit); +} + +// S stands for thread Safe. +class SPointer +{ +public: + static QBasicAtomicInt count; + inline SPointer() { count.ref(); } + inline ~SPointer() { count.deref(); } + inline SPointer(const SPointer & /* other */) { count.ref(); } +}; +QBasicAtomicInt SPointer::count = Q_BASIC_ATOMIC_INITIALIZER(0); + +Q_GLOBAL_STATIC(QThreadStorage, QTBUG14579_pointers1) +Q_GLOBAL_STATIC(QThreadStorage, QTBUG14579_pointers2) + +class QTBUG14579_class +{ +public: + SPointer member; + inline ~QTBUG14579_class() { + QVERIFY(!QTBUG14579_pointers1()->hasLocalData()); + QVERIFY(!QTBUG14579_pointers2()->hasLocalData()); + QTBUG14579_pointers2()->setLocalData(new SPointer); + QTBUG14579_pointers1()->setLocalData(new SPointer); + QVERIFY(QTBUG14579_pointers1()->hasLocalData()); + QVERIFY(QTBUG14579_pointers2()->hasLocalData()); + } +}; + + +void tst_QThreadStorage::QTBUG14579_leakInDestructor() +{ + class Thread : public QThread + { + public: + QThreadStorage &tls; + + Thread(QThreadStorage &t) : tls(t) { } + + void run() + { + QVERIFY(!tls.hasLocalData()); + tls.setLocalData(new QTBUG14579_class); + QVERIFY(tls.hasLocalData()); + } + }; + int c = SPointer::count; + + QThreadStorage tls; + + QVERIFY(!QTBUG14579_pointers1()->hasLocalData()); + QThreadStorage tls2; //add some more tls to make sure ids are not following each other too much + QThreadStorage tls3; + QVERIFY(!tls2.hasLocalData()); + QVERIFY(!tls3.hasLocalData()); + QVERIFY(!tls.hasLocalData()); + + Thread t1(tls); + Thread t2(tls); + Thread t3(tls); + + t1.start(); + t2.start(); + t3.start(); + + QVERIFY(t1.wait()); + QVERIFY(t2.wait()); + QVERIFY(t3.wait()); + + //check all the constructed things have been destructed + QCOMPARE(int(SPointer::count), c); +} + +class QTBUG14579_reset { +public: + SPointer member; + ~QTBUG14579_reset(); +}; + +Q_GLOBAL_STATIC(QThreadStorage, QTBUG14579_resetTls) + +QTBUG14579_reset::~QTBUG14579_reset() { + //Quite stupid, but WTF::ThreadSpecific::destroy does it. + QTBUG14579_resetTls()->setLocalData(this); +} + +void tst_QThreadStorage::QTBUG14579_resetInDestructor() +{ + class Thread : public QThread + { + public: + void run() + { + QVERIFY(!QTBUG14579_resetTls()->hasLocalData()); + QTBUG14579_resetTls()->setLocalData(new QTBUG14579_reset); + QVERIFY(QTBUG14579_resetTls()->hasLocalData()); + } + }; + int c = SPointer::count; + + Thread t1; + Thread t2; + Thread t3; + t1.start(); + t2.start(); + t3.start(); + QVERIFY(t1.wait()); + QVERIFY(t2.wait()); + QVERIFY(t3.wait()); + + //check all the constructed things have been destructed + QCOMPARE(int(SPointer::count), c); +} + + +void tst_QThreadStorage::valueBased() +{ + struct Thread : QThread { + QThreadStorage &tlsSPointer; + QThreadStorage &tlsString; + QThreadStorage &tlsInt; + + int someNumber; + QString someString; + Thread(QThreadStorage &t1, QThreadStorage &t2, QThreadStorage &t3) + : tlsSPointer(t1), tlsString(t2), tlsInt(t3) { } + + void run() { + /*QVERIFY(!tlsSPointer.hasLocalData()); + QVERIFY(!tlsString.hasLocalData()); + QVERIFY(!tlsInt.hasLocalData());*/ + SPointer pointercopy = tlsSPointer.localData(); + + //Default constructed values + QVERIFY(tlsString.localData().isNull()); + QCOMPARE(tlsInt.localData(), 0); + + //setting + tlsString.setLocalData(someString); + tlsInt.setLocalData(someNumber); + + QCOMPARE(tlsString.localData(), someString); + QCOMPARE(tlsInt.localData(), someNumber); + + //changing + tlsSPointer.setLocalData(SPointer()); + tlsInt.localData() += 42; + tlsString.localData().append(QLatin1String(" world")); + + QCOMPARE(tlsString.localData(), (someString + QLatin1String(" world"))); + QCOMPARE(tlsInt.localData(), (someNumber + 42)); + + // operator= + tlsString.localData() = QString::number(someNumber); + QCOMPARE(tlsString.localData().toInt(), someNumber); + } + }; + + QThreadStorage tlsSPointer; + QThreadStorage tlsString; + QThreadStorage tlsInt; + + int c = SPointer::count; + + Thread t1(tlsSPointer, tlsString, tlsInt); + Thread t2(tlsSPointer, tlsString, tlsInt); + Thread t3(tlsSPointer, tlsString, tlsInt); + t1.someNumber = 42; + t2.someNumber = -128; + t3.someNumber = 78; + t1.someString = "hello"; + t2.someString = "trolltech"; + t3.someString = "nokia"; + + t1.start(); + t2.start(); + t3.start(); + + QVERIFY(t1.wait()); + QVERIFY(t2.wait()); + QVERIFY(t3.wait()); + + QCOMPARE(c, int(SPointer::count)); + +} + + +QTEST_MAIN(tst_QThreadStorage) +#include "tst_qthreadstorage.moc" diff --git a/tests/auto/corelib/thread/qthreadstorage/tst_qthreadstorage.pro b/tests/auto/corelib/thread/qthreadstorage/tst_qthreadstorage.pro new file mode 100644 index 0000000000..3071098629 --- /dev/null +++ b/tests/auto/corelib/thread/qthreadstorage/tst_qthreadstorage.pro @@ -0,0 +1,4 @@ +load(qttest_p4) +SOURCES += tst_qthreadstorage.cpp +QT = core +symbian:LIBS += -llibpthread diff --git a/tests/auto/corelib/thread/qwaitcondition/.gitignore b/tests/auto/corelib/thread/qwaitcondition/.gitignore new file mode 100644 index 0000000000..96531988d9 --- /dev/null +++ b/tests/auto/corelib/thread/qwaitcondition/.gitignore @@ -0,0 +1 @@ +tst_qwaitcondition diff --git a/tests/auto/corelib/thread/qwaitcondition/qwaitcondition.pro b/tests/auto/corelib/thread/qwaitcondition/qwaitcondition.pro new file mode 100644 index 0000000000..9af0c71301 --- /dev/null +++ b/tests/auto/corelib/thread/qwaitcondition/qwaitcondition.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +SOURCES += tst_qwaitcondition.cpp +QT = core + + +CONFIG += parallel_test diff --git a/tests/auto/corelib/thread/qwaitcondition/tst_qwaitcondition.cpp b/tests/auto/corelib/thread/qwaitcondition/tst_qwaitcondition.cpp new file mode 100644 index 0000000000..6545df9189 --- /dev/null +++ b/tests/auto/corelib/thread/qwaitcondition/tst_qwaitcondition.cpp @@ -0,0 +1,845 @@ +/**************************************************************************** +** +** 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 + +#include +#include +#include +#include + +#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 +#if defined(Q_OS_SOLARIS) || ( defined(Q_OS_LINUX) && defined(QT_ARCH_ARMV6) ) +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 ? 10 : 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 ? 10 : 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 ? 10 : 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 ? 10 : 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" diff --git a/tests/auto/corelib/thread/qwritelocker/.gitignore b/tests/auto/corelib/thread/qwritelocker/.gitignore new file mode 100644 index 0000000000..865739ad2c --- /dev/null +++ b/tests/auto/corelib/thread/qwritelocker/.gitignore @@ -0,0 +1 @@ +tst_qwritelocker diff --git a/tests/auto/corelib/thread/qwritelocker/qwritelocker.pro b/tests/auto/corelib/thread/qwritelocker/qwritelocker.pro new file mode 100644 index 0000000000..39a98aaba5 --- /dev/null +++ b/tests/auto/corelib/thread/qwritelocker/qwritelocker.pro @@ -0,0 +1,4 @@ +load(qttest_p4) +SOURCES += tst_qwritelocker.cpp +QT = core +CONFIG += parallel_test diff --git a/tests/auto/corelib/thread/qwritelocker/tst_qwritelocker.cpp b/tests/auto/corelib/thread/qwritelocker/tst_qwritelocker.cpp new file mode 100644 index 0000000000..a06431a5e1 --- /dev/null +++ b/tests/auto/corelib/thread/qwritelocker/tst_qwritelocker.cpp @@ -0,0 +1,231 @@ +/**************************************************************************** +** +** 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 + +#include +#include +#include +#include + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QWriteLockerThread : public QThread +{ +public: + QReadWriteLock lock; + QSemaphore semaphore, testSemaphore; + + void waitForTest() + { + semaphore.release(); + testSemaphore.acquire(); + } +}; + +class tst_QWriteLocker : public QObject +{ + Q_OBJECT + +public: + tst_QWriteLocker(); + ~tst_QWriteLocker(); + + tst_QWriteLockerThread *thread; + + void waitForThread() + { + thread->semaphore.acquire(); + } + void releaseThread() + { + thread->testSemaphore.release(); + } + +private slots: + void scopeTest(); + void unlockAndRelockTest(); + void lockerStateTest(); +}; + +tst_QWriteLocker::tst_QWriteLocker() +{ +} + +tst_QWriteLocker::~tst_QWriteLocker() +{ +} + +void tst_QWriteLocker::scopeTest() +{ + class ScopeTestThread : public tst_QWriteLockerThread + { + public: + void run() + { + waitForTest(); + + { + QWriteLocker locker(&lock); + waitForTest(); + } + + waitForTest(); + } + }; + + thread = new ScopeTestThread; + thread->start(); + + waitForThread(); + // lock should be unlocked before entering the scope that creates the QWriteLocker + QVERIFY(thread->lock.tryLockForWrite()); + thread->lock.unlock(); + releaseThread(); + + waitForThread(); + // lock should be locked by the QWriteLocker + QVERIFY(!thread->lock.tryLockForWrite()); + releaseThread(); + + waitForThread(); + // lock should be unlocked when the QWriteLocker goes out of scope + QVERIFY(thread->lock.tryLockForWrite()); + thread->lock.unlock(); + releaseThread(); + + QVERIFY(thread->wait()); + + delete thread; + thread = 0; +} + + +void tst_QWriteLocker::unlockAndRelockTest() +{ + class UnlockAndRelockThread : public tst_QWriteLockerThread + { + public: + void run() + { + QWriteLocker locker(&lock); + + waitForTest(); + + locker.unlock(); + + waitForTest(); + + locker.relock(); + + waitForTest(); + } + }; + + thread = new UnlockAndRelockThread; + thread->start(); + + waitForThread(); + // lock should be locked by the QWriteLocker + QVERIFY(!thread->lock.tryLockForWrite()); + releaseThread(); + + waitForThread(); + // lock has been explicitly unlocked via QWriteLocker + QVERIFY(thread->lock.tryLockForWrite()); + thread->lock.unlock(); + releaseThread(); + + waitForThread(); + // lock has been explicitly relocked via QWriteLocker + QVERIFY(!thread->lock.tryLockForWrite()); + releaseThread(); + + QVERIFY(thread->wait()); + + delete thread; + thread = 0; +} + +void tst_QWriteLocker::lockerStateTest() +{ + class LockerStateThread : public tst_QWriteLockerThread + { + public: + void run() + { + { + QWriteLocker locker(&lock); + locker.relock(); + locker.unlock(); + + waitForTest(); + } + + waitForTest(); + } + }; + + thread = new LockerStateThread; + thread->start(); + + waitForThread(); + // even though we relock() after creating the QWriteLocker, it shouldn't lock the lock more than once + QVERIFY(thread->lock.tryLockForWrite()); + thread->lock.unlock(); + releaseThread(); + + waitForThread(); + // if we call QWriteLocker::unlock(), its destructor should do nothing + QVERIFY(thread->lock.tryLockForWrite()); + thread->lock.unlock(); + releaseThread(); + + QVERIFY(thread->wait()); + + delete thread; + thread = 0; +} + +QTEST_MAIN(tst_QWriteLocker) +#include "tst_qwritelocker.moc" diff --git a/tests/auto/corelib/thread/thread.pro b/tests/auto/corelib/thread/thread.pro new file mode 100644 index 0000000000..a137748b75 --- /dev/null +++ b/tests/auto/corelib/thread/thread.pro @@ -0,0 +1,14 @@ +TEMPLATE=subdirs +SUBDIRS=\ + qatomicint \ + qatomicpointer \ + qmutex \ + qmutexlocker \ + qreadlocker \ + qreadwritelock \ + qsemaphore \ + qthread \ + qthreadonce \ + qthreadstorage \ + qwaitcondition \ + qwritelocker diff --git a/tests/auto/qatomicint/.gitignore b/tests/auto/qatomicint/.gitignore deleted file mode 100644 index 52998efd02..0000000000 --- a/tests/auto/qatomicint/.gitignore +++ /dev/null @@ -1 +0,0 @@ -tst_qatomicint diff --git a/tests/auto/qatomicint/qatomicint.pro b/tests/auto/qatomicint/qatomicint.pro deleted file mode 100644 index 7850d93dc7..0000000000 --- a/tests/auto/qatomicint/qatomicint.pro +++ /dev/null @@ -1,4 +0,0 @@ -load(qttest_p4) -SOURCES += tst_qatomicint.cpp -QT = core -CONFIG += parallel_test diff --git a/tests/auto/qatomicint/tst_qatomicint.cpp b/tests/auto/qatomicint/tst_qatomicint.cpp deleted file mode 100644 index 27a2cc2e9c..0000000000 --- a/tests/auto/qatomicint/tst_qatomicint.cpp +++ /dev/null @@ -1,791 +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 - -#include -#include - -#include - -//TESTED_CLASS= -//TESTED_FILES= - -class tst_QAtomicInt : public QObject -{ - Q_OBJECT - -public: - tst_QAtomicInt(); - ~tst_QAtomicInt(); - -private slots: - void warningFree(); - - // QAtomicInt members - void constructor_data(); - void constructor(); - void copy_constructor_data(); - void copy_constructor(); - void equality_operator_data(); - void equality_operator(); - void inequality_operator_data(); - void inequality_operator(); - void not_operator_data(); - void not_operator(); - void cast_operator_data(); - void cast_operator(); - void assignment_operator_data(); - void assignment_operator(); - - void isReferenceCountingNative(); - void isReferenceCountingWaitFree(); - void ref_data(); - void ref(); - void deref_data(); - void deref(); - - void isTestAndSetNative(); - void isTestAndSetWaitFree(); - void testAndSet_data(); - void testAndSet(); - - void isFetchAndStoreNative(); - void isFetchAndStoreWaitFree(); - void fetchAndStore_data(); - void fetchAndStore(); - - void isFetchAndAddNative(); - void isFetchAndAddWaitFree(); - void fetchAndAdd_data(); - void fetchAndAdd(); - - // stress tests - void testAndSet_loop(); - void fetchAndAdd_loop(); - void fetchAndAdd_threadedLoop(); - -private: - static void warningFreeHelper(); -}; - -tst_QAtomicInt::tst_QAtomicInt() -{ } - -tst_QAtomicInt::~tst_QAtomicInt() -{ } - -void tst_QAtomicInt::warningFreeHelper() -{ - qFatal("This code is bogus, and shouldn't be run. We're looking for compiler warnings only."); - - QBasicAtomicInt i = Q_BASIC_ATOMIC_INITIALIZER(0); - - int expectedValue = 0; - int newValue = 0; - int valueToAdd = 0; - - i.ref(); - i.deref(); - - i.testAndSetRelaxed(expectedValue, newValue); - i.testAndSetAcquire(expectedValue, newValue); - i.testAndSetRelease(expectedValue, newValue); - i.testAndSetOrdered(expectedValue, newValue); - - i.fetchAndStoreRelaxed(newValue); - i.fetchAndStoreAcquire(newValue); - i.fetchAndStoreRelease(newValue); - i.fetchAndStoreOrdered(newValue); - - i.fetchAndAddRelaxed(valueToAdd); - i.fetchAndAddAcquire(valueToAdd); - i.fetchAndAddRelease(valueToAdd); - i.fetchAndAddOrdered(valueToAdd); -} - -void tst_QAtomicInt::warningFree() -{ - // This is a compile time check for warnings. - // No need for actual work here. - - void (*foo)() = &warningFreeHelper; - (void)foo; -} - -void tst_QAtomicInt::constructor_data() -{ - QTest::addColumn("value"); - - QTest::newRow("0") << 31337; - QTest::newRow("1") << 0; - QTest::newRow("2") << 1; - QTest::newRow("3") << -1; - QTest::newRow("4") << 2; - QTest::newRow("5") << -2; - QTest::newRow("6") << 3; - QTest::newRow("7") << -3; - QTest::newRow("8") << INT_MAX; - QTest::newRow("9") << INT_MIN+1; -} - -void tst_QAtomicInt::constructor() -{ - QFETCH(int, value); - QAtomicInt atomic1(value); - QCOMPARE(int(atomic1), value); - QAtomicInt atomic2 = value; - QCOMPARE(int(atomic2), value); -} - -void tst_QAtomicInt::copy_constructor_data() -{ constructor_data(); } - -void tst_QAtomicInt::copy_constructor() -{ - QFETCH(int, value); - QAtomicInt atomic1(value); - QCOMPARE(int(atomic1), value); - - QAtomicInt atomic2(atomic1); - QCOMPARE(int(atomic2), value); - QAtomicInt atomic3 = atomic1; - QCOMPARE(int(atomic3), value); - QAtomicInt atomic4(atomic2); - QCOMPARE(int(atomic4), value); - QAtomicInt atomic5 = atomic2; - QCOMPARE(int(atomic5), value); -} - -void tst_QAtomicInt::equality_operator_data() -{ - QTest::addColumn("value1"); - QTest::addColumn("value2"); - QTest::addColumn("result"); - - QTest::newRow("success0") << 1 << 1 << 1; - QTest::newRow("success1") << -1 << -1 << 1; - QTest::newRow("failure0") << 0 << 1 << 0; - QTest::newRow("failure1") << 1 << 0 << 0; - QTest::newRow("failure2") << 0 << -1 << 0; - QTest::newRow("failure3") << -1 << 0 << 0; -} - -void tst_QAtomicInt::equality_operator() -{ - QFETCH(int, value1); - QFETCH(int, value2); - QAtomicInt x = value1; - QTEST(x == value2 ? 1 : 0, "result"); -} - -void tst_QAtomicInt::inequality_operator_data() -{ - QTest::addColumn("value1"); - QTest::addColumn("value2"); - QTest::addColumn("result"); - - QTest::newRow("failure0") << 1 << 1 << 0; - QTest::newRow("failure1") << -1 << -1 << 0; - QTest::newRow("success0") << 0 << 1 << 1; - QTest::newRow("success1") << 1 << 0 << 1; - QTest::newRow("success2") << 0 << -1 << 1; - QTest::newRow("success3") << -1 << 0 << 1; -} - -void tst_QAtomicInt::inequality_operator() -{ - QFETCH(int, value1); - QFETCH(int, value2); - QAtomicInt x = value1; - QTEST(x != value2 ? 1 : 0, "result"); -} - -void tst_QAtomicInt::not_operator_data() -{ constructor_data(); } - -void tst_QAtomicInt::not_operator() -{ - QFETCH(int, value); - QAtomicInt atomic = value; - QCOMPARE(!atomic, !value); -} - -void tst_QAtomicInt::cast_operator_data() -{ constructor_data(); } - -void tst_QAtomicInt::cast_operator() -{ - QFETCH(int, value); - QAtomicInt atomic = value; - int copy = atomic; - QCOMPARE(copy, value); -} - -void tst_QAtomicInt::assignment_operator_data() -{ - QTest::addColumn("value"); - QTest::addColumn("newval"); - - QTest::newRow("value0") << 0 << 1; - QTest::newRow("value1") << 1 << 0; - QTest::newRow("value2") << 0 << -1; - QTest::newRow("value3") << -1 << 0; - QTest::newRow("value4") << -1 << 1; - QTest::newRow("value5") << 1 << -1; -} - -void tst_QAtomicInt::assignment_operator() -{ - QFETCH(int, value); - QFETCH(int, newval); - - { - QAtomicInt atomic1 = value; - atomic1 = newval; - QCOMPARE(int(atomic1), newval); - atomic1 = value; - QCOMPARE(int(atomic1), value); - QAtomicInt atomic2 = newval; - atomic1 = atomic2; - QCOMPARE(atomic1, atomic2); - } -} - -void tst_QAtomicInt::isReferenceCountingNative() -{ -#if defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE) - // the runtime test should say the same thing - QVERIFY(QAtomicInt::isReferenceCountingNative()); - -# if (defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_SOMETIMES_NATIVE) \ - || defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NOT_NATIVE)) -# error "Define only one of Q_ATOMIC_INT_REFERENCE_COUNTING_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" -# endif -#elif defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_SOMETIMES_NATIVE) - // could be either, just want to make sure the function is implemented - QVERIFY(QAtomicInt::isReferenceCountingNative() || !QAtomicInt::isReferenceCountingNative()); - -# if (defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE) \ - || defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NOT_NATIVE)) -# error "Define only one of Q_ATOMIC_INT_REFERENCE_COUNTING_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" -# endif -#elif defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NOT_NATIVE) - // the runtime test should say the same thing - QVERIFY(!QAtomicInt::isReferenceCountingNative()); - -# if (defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE) \ - || defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_SOMETIMES_NATIVE)) -# error "Define only one of Q_ATOMIC_INT_REFERENCE_COUNTING_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" -# endif -#else -# error "Q_ATOMIC_INT_REFERENCE_COUNTING_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE is not defined" -#endif -} - -void tst_QAtomicInt::isReferenceCountingWaitFree() -{ -#if defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_WAIT_FREE) - // the runtime test should say the same thing - QVERIFY(QAtomicInt::isReferenceCountingWaitFree()); - - // enforce some invariants - QVERIFY(QAtomicInt::isReferenceCountingNative()); -# if defined(Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NOT_NATIVE) -# error "Reference counting cannot be wait-free and unsupported at the same time!" -# endif -#else - // the runtime test should say the same thing - QVERIFY(!QAtomicInt::isReferenceCountingWaitFree()); -#endif -} - -void tst_QAtomicInt::ref_data() -{ - QTest::addColumn("value"); - QTest::addColumn("result"); - QTest::addColumn("expected"); - - QTest::newRow("data0") << 0 << 1 << 1; - QTest::newRow("data1") << -1 << 0 << 0; - QTest::newRow("data2") << 1 << 1 << 2; -} - -void tst_QAtomicInt::ref() -{ - QFETCH(int, value); - QAtomicInt x = value; - QTEST(x.ref() ? 1 : 0, "result"); - QTEST(int(x), "expected"); -} - -void tst_QAtomicInt::deref_data() -{ - QTest::addColumn("value"); - QTest::addColumn("result"); - QTest::addColumn("expected"); - - QTest::newRow("data0") << 0 << 1 << -1; - QTest::newRow("data1") << 1 << 0 << 0; - QTest::newRow("data2") << 2 << 1 << 1; -} - -void tst_QAtomicInt::deref() -{ - QFETCH(int, value); - QAtomicInt x = value; - QTEST(x.deref() ? 1 : 0, "result"); - QTEST(int(x), "expected"); -} - -void tst_QAtomicInt::isTestAndSetNative() -{ -#if defined(Q_ATOMIC_INT_TEST_AND_SET_IS_ALWAYS_NATIVE) - // the runtime test should say the same thing - QVERIFY(QAtomicInt::isTestAndSetNative()); - -# if (defined(Q_ATOMIC_INT_TEST_AND_SET_IS_SOMETIMES_NATIVE) \ - || defined(Q_ATOMIC_INT_TEST_AND_SET_IS_NOT_NATIVE)) -# error "Define only one of Q_ATOMIC_INT_TEST_AND_SET_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" -# endif -#elif defined(Q_ATOMIC_INT_TEST_AND_SET_IS_SOMETIMES_NATIVE) - // could be either, just want to make sure the function is implemented - QVERIFY(QAtomicInt::isTestAndSetNative() || !QAtomicInt::isTestAndSetNative()); - -# if (defined(Q_ATOMIC_INT_TEST_AND_SET_IS_ALWAYS_NATIVE) \ - || defined(Q_ATOMIC_INT_TEST_AND_SET_IS_NOT_NATIVE)) -# error "Define only one of Q_ATOMIC_INT_TEST_AND_SET_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" -# endif -#elif defined(Q_ATOMIC_INT_TEST_AND_SET_IS_NOT_NATIVE) - // the runtime test should say the same thing - QVERIFY(!QAtomicInt::isTestAndSetNative()); - -# if (defined(Q_ATOMIC_INT_TEST_AND_SET_IS_ALWAYS_NATIVE) \ - || defined(Q_ATOMIC_INT_TEST_AND_SET_IS_SOMETIMES_NATIVE)) -# error "Define only one of Q_ATOMIC_INT_TEST_AND_SET_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" -# endif -#else -# error "Q_ATOMIC_INT_TEST_AND_SET_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE is not defined" -#endif -} - -void tst_QAtomicInt::isTestAndSetWaitFree() -{ -#if defined(Q_ATOMIC_INT_TEST_AND_SET_IS_WAIT_FREE) - // the runtime test should say the same thing - QVERIFY(QAtomicInt::isTestAndSetWaitFree()); - - // enforce some invariants - QVERIFY(QAtomicInt::isTestAndSetNative()); -# if defined(Q_ATOMIC_INT_TEST_AND_SET_IS_NOT_NATIVE) -# error "Reference counting cannot be wait-free and unsupported at the same time!" -# endif -#else - // the runtime test should say the same thing - QVERIFY(!QAtomicInt::isTestAndSetWaitFree()); -#endif -} - -void tst_QAtomicInt::testAndSet_data() -{ - QTest::addColumn("value"); - QTest::addColumn("expected"); - QTest::addColumn("newval"); - QTest::addColumn("result"); - - // these should succeed - QTest::newRow("success0") << 0 << 0 << 0 << 1; - QTest::newRow("success1") << 0 << 0 << 1 << 1; - QTest::newRow("success2") << 0 << 0 << -1 << 1; - QTest::newRow("success3") << 1 << 1 << 0 << 1; - QTest::newRow("success4") << 1 << 1 << 1 << 1; - QTest::newRow("success5") << 1 << 1 << -1 << 1; - QTest::newRow("success6") << -1 << -1 << 0 << 1; - QTest::newRow("success7") << -1 << -1 << 1 << 1; - QTest::newRow("success8") << -1 << -1 << -1 << 1; - QTest::newRow("success9") << INT_MIN+1 << INT_MIN+1 << INT_MIN+1 << 1; - QTest::newRow("successA") << INT_MIN+1 << INT_MIN+1 << 1 << 1; - QTest::newRow("successB") << INT_MIN+1 << INT_MIN+1 << -1 << 1; - QTest::newRow("successC") << INT_MAX << INT_MAX << INT_MAX << 1; - QTest::newRow("successD") << INT_MAX << INT_MAX << 1 << 1; - QTest::newRow("successE") << INT_MAX << INT_MAX << -1 << 1; - - // these should fail - QTest::newRow("failure0") << 0 << 1 << ~0 << 0; - QTest::newRow("failure1") << 0 << -1 << ~0 << 0; - QTest::newRow("failure2") << 1 << 0 << ~0 << 0; - QTest::newRow("failure3") << -1 << 0 << ~0 << 0; - QTest::newRow("failure4") << 1 << -1 << ~0 << 0; - QTest::newRow("failure5") << -1 << 1 << ~0 << 0; - QTest::newRow("failure6") << INT_MIN+1 << INT_MAX << ~0 << 0; - QTest::newRow("failure7") << INT_MAX << INT_MIN+1 << ~0 << 0; -} - -void tst_QAtomicInt::testAndSet() -{ - QFETCH(int, value); - QFETCH(int, expected); - QFETCH(int, newval); - - { - QAtomicInt atomic = value; - QTEST(atomic.testAndSetRelaxed(expected, newval) ? 1 : 0, "result"); - } - - { - QAtomicInt atomic = value; - QTEST(atomic.testAndSetAcquire(expected, newval) ? 1 : 0, "result"); - } - - { - QAtomicInt atomic = value; - QTEST(atomic.testAndSetRelease(expected, newval) ? 1 : 0, "result"); - } - - { - QAtomicInt atomic = value; - QTEST(atomic.testAndSetOrdered(expected, newval) ? 1 : 0, "result"); - } -} - -void tst_QAtomicInt::isFetchAndStoreNative() -{ -#if defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE) - // the runtime test should say the same thing - QVERIFY(QAtomicInt::isFetchAndStoreNative()); - -# if (defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_SOMETIMES_NATIVE) \ - || defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_NOT_NATIVE)) -# error "Define only one of Q_ATOMIC_INT_FETCH_AND_STORE_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" -# endif -#elif defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_SOMETIMES_NATIVE) - // could be either, just want to make sure the function is implemented - QVERIFY(QAtomicInt::isFetchAndStoreNative() || !QAtomicInt::isFetchAndStoreNative()); - -# if (defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE) \ - || defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_NOT_NATIVE)) -# error "Define only one of Q_ATOMIC_INT_FETCH_AND_STORE_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" -# endif -#elif defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_NOT_NATIVE) - // the runtime test should say the same thing - QVERIFY(!QAtomicInt::isFetchAndStoreNative()); - -# if (defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE) \ - || defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_SOMETIMES_NATIVE)) -# error "Define only one of Q_ATOMIC_INT_FETCH_AND_STORE_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" -# endif -#else -# error "Q_ATOMIC_INT_FETCH_AND_STORE_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE is not defined" -#endif -} - -void tst_QAtomicInt::isFetchAndStoreWaitFree() -{ -#if defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_WAIT_FREE) - // the runtime test should say the same thing - QVERIFY(QAtomicInt::isFetchAndStoreWaitFree()); - - // enforce some invariants - QVERIFY(QAtomicInt::isFetchAndStoreNative()); -# if defined(Q_ATOMIC_INT_FETCH_AND_STORE_IS_NOT_NATIVE) -# error "Reference counting cannot be wait-free and unsupported at the same time!" -# endif -#else - // the runtime test should say the same thing - QVERIFY(!QAtomicInt::isFetchAndStoreWaitFree()); -#endif -} - -void tst_QAtomicInt::fetchAndStore_data() -{ - QTest::addColumn("value"); - QTest::addColumn("newval"); - - QTest::newRow("data0") << 0 << 1; - QTest::newRow("data1") << 1 << 2; - QTest::newRow("data2") << 3 << 8; -} - -void tst_QAtomicInt::fetchAndStore() -{ - QFETCH(int, value); - QFETCH(int, newval); - - { - QAtomicInt atomic = value; - QCOMPARE(atomic.fetchAndStoreRelaxed(newval), value); - QCOMPARE(int(atomic), newval); - } - - { - QAtomicInt atomic = value; - QCOMPARE(atomic.fetchAndStoreAcquire(newval), value); - QCOMPARE(int(atomic), newval); - } - - { - QAtomicInt atomic = value; - QCOMPARE(atomic.fetchAndStoreRelease(newval), value); - QCOMPARE(int(atomic), newval); - } - - { - QAtomicInt atomic = value; - QCOMPARE(atomic.fetchAndStoreOrdered(newval), value); - QCOMPARE(int(atomic), newval); - } -} - -void tst_QAtomicInt::isFetchAndAddNative() -{ -#if defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_ALWAYS_NATIVE) - // the runtime test should say the same thing - QVERIFY(QAtomicInt::isFetchAndAddNative()); - -# if (defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_SOMETIMES_NATIVE) \ - || defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_NOT_NATIVE)) -# error "Define only one of Q_ATOMIC_INT_FETCH_AND_ADD_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" -# endif -#elif defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_SOMETIMES_NATIVE) - // could be either, just want to make sure the function is implemented - QVERIFY(QAtomicInt::isFetchAndAddNative() || !QAtomicInt::isFetchAndAddNative()); - -# if (defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_ALWAYS_NATIVE) \ - || defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_NOT_NATIVE)) -# error "Define only one of Q_ATOMIC_INT_FETCH_AND_ADD_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" -# endif -#elif defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_NOT_NATIVE) - // the runtime test should say the same thing - QVERIFY(!QAtomicInt::isFetchAndAddNative()); - -# if (defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_ALWAYS_NATIVE) \ - || defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_SOMETIMES_NATIVE)) -# error "Define only one of Q_ATOMIC_INT_FETCH_AND_ADD_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" -# endif -#else -# error "Q_ATOMIC_INT_FETCH_AND_ADD_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE is not defined" -#endif -} - -void tst_QAtomicInt::isFetchAndAddWaitFree() -{ -#if defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_WAIT_FREE) - // the runtime test should say the same thing - QVERIFY(QAtomicInt::isFetchAndAddWaitFree()); - - // enforce some invariants - QVERIFY(QAtomicInt::isFetchAndAddNative()); -# if defined(Q_ATOMIC_INT_FETCH_AND_ADD_IS_NOT_NATIVE) -# error "Reference counting cannot be wait-free and unsupported at the same time!" -# endif -#else - // the runtime test should say the same thing - QVERIFY(!QAtomicInt::isFetchAndAddWaitFree()); -#endif -} - -void tst_QAtomicInt::fetchAndAdd_data() -{ - QTest::addColumn("value1"); - QTest::addColumn("value2"); - - QTest::newRow("0+1") << 0 << 1; - QTest::newRow("1+0") << 1 << 0; - QTest::newRow("1+2") << 1 << 2; - QTest::newRow("2+1") << 2 << 1; - QTest::newRow("10+21") << 10 << 21; - QTest::newRow("31+40") << 31 << 40; - QTest::newRow("51+62") << 51 << 62; - QTest::newRow("72+81") << 72 << 81; - QTest::newRow("810+721") << 810 << 721; - QTest::newRow("631+540") << 631 << 540; - QTest::newRow("451+362") << 451 << 362; - QTest::newRow("272+181") << 272 << 181; - QTest::newRow("1810+8721") << 1810 << 8721; - QTest::newRow("3631+6540") << 3631 << 6540; - QTest::newRow("5451+4362") << 5451 << 4362; - QTest::newRow("7272+2181") << 7272 << 2181; - - QTest::newRow("0+-1") << 0 << -1; - QTest::newRow("1+0") << 1 << 0; - QTest::newRow("1+-2") << 1 << -2; - QTest::newRow("2+-1") << 2 << -1; - QTest::newRow("10+-21") << 10 << -21; - QTest::newRow("31+-40") << 31 << -40; - QTest::newRow("51+-62") << 51 << -62; - QTest::newRow("72+-81") << 72 << -81; - QTest::newRow("810+-721") << 810 << -721; - QTest::newRow("631+-540") << 631 << -540; - QTest::newRow("451+-362") << 451 << -362; - QTest::newRow("272+-181") << 272 << -181; - QTest::newRow("1810+-8721") << 1810 << -8721; - QTest::newRow("3631+-6540") << 3631 << -6540; - QTest::newRow("5451+-4362") << 5451 << -4362; - QTest::newRow("7272+-2181") << 7272 << -2181; - - QTest::newRow("0+1") << 0 << 1; - QTest::newRow("-1+0") << -1 << 0; - QTest::newRow("-1+2") << -1 << 2; - QTest::newRow("-2+1") << -2 << 1; - QTest::newRow("-10+21") << -10 << 21; - QTest::newRow("-31+40") << -31 << 40; - QTest::newRow("-51+62") << -51 << 62; - QTest::newRow("-72+81") << -72 << 81; - QTest::newRow("-810+721") << -810 << 721; - QTest::newRow("-631+540") << -631 << 540; - QTest::newRow("-451+362") << -451 << 362; - QTest::newRow("-272+181") << -272 << 181; - QTest::newRow("-1810+8721") << -1810 << 8721; - QTest::newRow("-3631+6540") << -3631 << 6540; - QTest::newRow("-5451+4362") << -5451 << 4362; - QTest::newRow("-7272+2181") << -7272 << 2181; -} - -void tst_QAtomicInt::fetchAndAdd() -{ - QFETCH(int, value1); - QFETCH(int, value2); - int result; - - { - QAtomicInt atomic = value1; - result = atomic.fetchAndAddRelaxed(value2); - QCOMPARE(result, value1); - QCOMPARE(int(atomic), value1 + value2); - } - - { - QAtomicInt atomic = value1; - result = atomic.fetchAndAddAcquire(value2); - QCOMPARE(result, value1); - QCOMPARE(int(atomic), value1 + value2); - } - - { - QAtomicInt atomic = value1; - result = atomic.fetchAndAddRelease(value2); - QCOMPARE(result, value1); - QCOMPARE(int(atomic), value1 + value2); - } - - { - QAtomicInt atomic = value1; - result = atomic.fetchAndAddOrdered(value2); - QCOMPARE(result, value1); - QCOMPARE(int(atomic), value1 + value2); - } -} - -void tst_QAtomicInt::testAndSet_loop() -{ - QTime stopWatch; - stopWatch.start(); - - int iterations = 10000000; - - QAtomicInt val=0; - for (int i = 0; i < iterations; ++i) { - QVERIFY(val.testAndSetRelaxed(val, val+1)); - if ((i % 1000) == 999) { - if (stopWatch.elapsed() > 60 * 1000) { - // This test shouldn't run for more than two minutes. - qDebug("Interrupted test after %d iterations (%.2f iterations/sec)", - i, (i * 1000.0) / double(stopWatch.elapsed())); - break; - } - } - } -} - -void tst_QAtomicInt::fetchAndAdd_loop() -{ - int iterations = 10000000; -#if defined (Q_OS_HPUX) - iterations = 1000000; -#endif - - QAtomicInt val=0; - for (int i = 0; i < iterations; ++i) { - const int prev = val.fetchAndAddRelaxed(1); - QCOMPARE(prev, int(val) -1); - } -} - -class FetchAndAddThread : public QThread -{ -public: - void run() - { - - for (int i = 0; i < iterations; ++i) - val->fetchAndAddAcquire(1); - - for (int i = 0; i < iterations; ++i) - val->fetchAndAddAcquire(-1); - - } -QAtomicInt *val; -int iterations; -}; - - -void tst_QAtomicInt::fetchAndAdd_threadedLoop() -{ - QAtomicInt val; - FetchAndAddThread t1; - t1.val = &val; - t1.iterations = 1000000; - - FetchAndAddThread t2; - t2.val = &val; - t2.iterations = 2000000; - - t1.start(); - t2.start(); - t1.wait(); - t2.wait(); - - QCOMPARE(int(val), 0); -} - -QTEST_MAIN(tst_QAtomicInt) -#include "tst_qatomicint.moc" diff --git a/tests/auto/qatomicpointer/.gitignore b/tests/auto/qatomicpointer/.gitignore deleted file mode 100644 index 2843c40749..0000000000 --- a/tests/auto/qatomicpointer/.gitignore +++ /dev/null @@ -1 +0,0 @@ -tst_qatomicpointer diff --git a/tests/auto/qatomicpointer/qatomicpointer.pro b/tests/auto/qatomicpointer/qatomicpointer.pro deleted file mode 100644 index 89ff137d39..0000000000 --- a/tests/auto/qatomicpointer/qatomicpointer.pro +++ /dev/null @@ -1,4 +0,0 @@ -load(qttest_p4) -SOURCES += tst_qatomicpointer.cpp -QT = core -CONFIG += parallel_test diff --git a/tests/auto/qatomicpointer/tst_qatomicpointer.cpp b/tests/auto/qatomicpointer/tst_qatomicpointer.cpp deleted file mode 100644 index 42e744aaa6..0000000000 --- a/tests/auto/qatomicpointer/tst_qatomicpointer.cpp +++ /dev/null @@ -1,674 +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 - -#include - -#include - -//TESTED_CLASS= -//TESTED_FILES= - -class tst_QAtomicPointer : public QObject -{ - Q_OBJECT - -public: - tst_QAtomicPointer(); - ~tst_QAtomicPointer(); - -private slots: - void warningFree(); - - void constructor(); - void copy_constructor(); - void equality_operator(); - void inequality_operator(); - void assignment_operator(); - void star_operator(); - void dereference_operator(); - - void isTestAndSetNative(); - void isTestAndSetWaitFree(); - void testAndSet(); - - void isFetchAndStoreNative(); - void isFetchAndStoreWaitFree(); - void fetchAndStore(); - - void isFetchAndAddNative(); - void isFetchAndAddWaitFree(); - void fetchAndAdd_data(); - void fetchAndAdd(); - -private: - static void warningFreeHelper(); -}; - -tst_QAtomicPointer::tst_QAtomicPointer() -{ } - -tst_QAtomicPointer::~tst_QAtomicPointer() -{ } - -struct WFHC -{ - void bar() {} -}; - -void tst_QAtomicPointer::warningFreeHelper() -{ - qFatal("This code is bogus, and shouldn't be run. We're looking for compiler warnings only."); - - QBasicAtomicPointer p = Q_BASIC_ATOMIC_INITIALIZER(0); - - p->bar(); - - WFHC *expectedValue = 0; - WFHC *newValue = 0; - qptrdiff valueToAdd = 0; - - p.testAndSetRelaxed(expectedValue, newValue); - p.testAndSetAcquire(expectedValue, newValue); - p.testAndSetRelease(expectedValue, newValue); - p.testAndSetOrdered(expectedValue, newValue); - - p.fetchAndStoreRelaxed(newValue); - p.fetchAndStoreAcquire(newValue); - p.fetchAndStoreRelease(newValue); - p.fetchAndStoreOrdered(newValue); - - p.fetchAndAddRelaxed(valueToAdd); - p.fetchAndAddAcquire(valueToAdd); - p.fetchAndAddRelease(valueToAdd); - p.fetchAndAddOrdered(valueToAdd); -} - -void tst_QAtomicPointer::warningFree() -{ - // This is a compile time check for warnings. - // No need for actual work here. - - void (*foo)() = &warningFreeHelper; - (void)foo; -} - -void tst_QAtomicPointer::constructor() -{ - void *one = this; - QAtomicPointer atomic1 = one; - QVERIFY(atomic1 == one); - - void *two = &one; - QAtomicPointer atomic2 = two; - QVERIFY(atomic2 == two); - - void *three = &two; - QAtomicPointer atomic3 = three; - QVERIFY(atomic3 == three); -} - -void tst_QAtomicPointer::copy_constructor() -{ - void *one = this; - QAtomicPointer atomic1 = one; - QAtomicPointer atomic1_copy = atomic1; - QVERIFY(atomic1_copy == one); - QCOMPARE(atomic1_copy, atomic1); - - void *two = &one; - QAtomicPointer atomic2 = two; - QAtomicPointer atomic2_copy = atomic2; - QVERIFY(atomic2_copy == two); - QCOMPARE(atomic2_copy, atomic2); - - void *three = &two; - QAtomicPointer atomic3 = three; - QAtomicPointer atomic3_copy = atomic3; - QVERIFY(atomic3_copy == three); - QCOMPARE(atomic3_copy, atomic3); -} - -void tst_QAtomicPointer::equality_operator() -{ - void *one = this; - void *two = &one; - void *three = &two; - - QAtomicPointer atomic1 = one; - QAtomicPointer atomic2 = two; - QAtomicPointer atomic3 = three; - - QVERIFY(atomic1 == one); - QVERIFY(!(atomic1 == two)); - QVERIFY(!(atomic1 == three)); - - QVERIFY(!(atomic2 == one)); - QVERIFY(atomic2 == two); - QVERIFY(!(atomic2 == three)); - - QVERIFY(!(atomic3 == one)); - QVERIFY(!(atomic3 == two)); - QVERIFY(atomic3 == three); -} - -void tst_QAtomicPointer::inequality_operator() -{ - void *one = this; - void *two = &one; - void *three = &two; - - QAtomicPointer atomic1 = one; - QAtomicPointer atomic2 = two; - QAtomicPointer atomic3 = three; - - QVERIFY(!(atomic1 != one)); - QVERIFY(atomic1 != two); - QVERIFY(atomic1 != three); - - QVERIFY(atomic2 != one); - QVERIFY(!(atomic2 != two)); - QVERIFY(atomic2 != three); - - QVERIFY(atomic3 != one); - QVERIFY(atomic3 != two); - QVERIFY(!(atomic3 != three)); -} - -void tst_QAtomicPointer::assignment_operator() -{ - void *one = this; - void *two = &one; - void *three = &two; - - QAtomicPointer atomic1 = one; - QAtomicPointer atomic2 = two; - QAtomicPointer atomic3 = three; - - QVERIFY(atomic1 == one); - QVERIFY(atomic2 == two); - QVERIFY(atomic3 == three); - - atomic1 = two; - atomic2 = three; - atomic3 = one; - - QVERIFY(atomic1 == two); - QVERIFY(atomic2 == three); - QVERIFY(atomic3 == one); -} - -struct Type -{ - inline const Type *self() const - { return this; } -}; - -void tst_QAtomicPointer::star_operator() -{ - Type t; - QAtomicPointer p = &t; - QCOMPARE((*p).self(), t.self()); -} - -void tst_QAtomicPointer::dereference_operator() -{ - Type t; - QAtomicPointer p = &t; - QCOMPARE(p->self(), t.self()); -} - -void tst_QAtomicPointer::isTestAndSetNative() -{ -#if defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE) - // the runtime test should say the same thing - QVERIFY(QAtomicPointer::isTestAndSetNative()); - -# if (defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_SOMETIMES_NATIVE) \ - || defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_NOT_NATIVE)) -# error "Define only one of Q_ATOMIC_POINTER_TEST_AND_SET_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" -# endif -#elif defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_SOMETIMES_NATIVE) - // could be either, just want to make sure the function is implemented - QVERIFY(QAtomicPointer::isTestAndSetNative() - || !QAtomicPointer::isTestAndSetNative()); - -# if (defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE) \ - || defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_NOT_NATIVE)) -# error "Define only one of Q_ATOMIC_POINTER_TEST_AND_SET_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" -# endif -#elif defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_NOT_NATIVE) - // the runtime test should say the same thing - QVERIFY(!QAtomicPointer::isTestAndSetNative()); - -# if (defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE) \ - || defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_SOMETIMES_NATIVE)) -# error "Define only one of Q_ATOMIC_POINTER_TEST_AND_SET_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" -# endif -#else -# error "Q_ATOMIC_POINTER_TEST_AND_SET_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE is not defined" -#endif -} - -void tst_QAtomicPointer::isTestAndSetWaitFree() -{ -#if defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_WAIT_FREE) - // the runtime test should say the same thing - QVERIFY(QAtomicPointer::isTestAndSetWaitFree()); - - // enforce some invariants - QVERIFY(QAtomicPointer::isTestAndSetNative()); -# if defined(Q_ATOMIC_POINTER_TEST_AND_SET_IS_NOT_NATIVE) -# error "Reference counting cannot be wait-free and unsupported at the same time!" -# endif -#else - // the runtime test should say the same thing - QVERIFY(!QAtomicPointer::isTestAndSetWaitFree()); -#endif -} - -void tst_QAtomicPointer::testAndSet() -{ - void *one = this; - void *two = &one; - void *three = &two; - - { - QAtomicPointer atomic1 = one; - QAtomicPointer atomic2 = two; - QAtomicPointer atomic3 = three; - - QVERIFY(atomic1 == one); - QVERIFY(atomic2 == two); - QVERIFY(atomic3 == three); - - QVERIFY(atomic1.testAndSetRelaxed(one, two)); - QVERIFY(atomic2.testAndSetRelaxed(two, three)); - QVERIFY(atomic3.testAndSetRelaxed(three, one)); - - QVERIFY(atomic1 == two); - QVERIFY(atomic2 == three); - QVERIFY(atomic3 == one); - } - - { - QAtomicPointer atomic1 = one; - QAtomicPointer atomic2 = two; - QAtomicPointer atomic3 = three; - - QVERIFY(atomic1 == one); - QVERIFY(atomic2 == two); - QVERIFY(atomic3 == three); - - QVERIFY(atomic1.testAndSetAcquire(one, two)); - QVERIFY(atomic2.testAndSetAcquire(two, three)); - QVERIFY(atomic3.testAndSetAcquire(three, one)); - - QVERIFY(atomic1 == two); - QVERIFY(atomic2 == three); - QVERIFY(atomic3 == one); - } - - { - QAtomicPointer atomic1 = one; - QAtomicPointer atomic2 = two; - QAtomicPointer atomic3 = three; - - QVERIFY(atomic1 == one); - QVERIFY(atomic2 == two); - QVERIFY(atomic3 == three); - - QVERIFY(atomic1.testAndSetRelease(one, two)); - QVERIFY(atomic2.testAndSetRelease(two, three)); - QVERIFY(atomic3.testAndSetRelease(three, one)); - - QVERIFY(atomic1 == two); - QVERIFY(atomic2 == three); - QVERIFY(atomic3 == one); - } - - { - QAtomicPointer atomic1 = one; - QAtomicPointer atomic2 = two; - QAtomicPointer atomic3 = three; - - QVERIFY(atomic1 == one); - QVERIFY(atomic2 == two); - QVERIFY(atomic3 == three); - - QVERIFY(atomic1.testAndSetOrdered(one, two)); - QVERIFY(atomic2.testAndSetOrdered(two, three)); - QVERIFY(atomic3.testAndSetOrdered(three, one)); - - QVERIFY(atomic1 == two); - QVERIFY(atomic2 == three); - QVERIFY(atomic3 == one); - } -} - -void tst_QAtomicPointer::isFetchAndStoreNative() -{ -#if defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE) - // the runtime test should say the same thing - QVERIFY(QAtomicPointer::isFetchAndStoreNative()); - -# if (defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_SOMETIMES_NATIVE) \ - || defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_NOT_NATIVE)) -# error "Define only one of Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" -# endif -#elif defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_SOMETIMES_NATIVE) - // could be either, just want to make sure the function is implemented - QVERIFY(QAtomicPointer::isFetchAndStoreNative() - || !QAtomicPointer::isFetchAndStoreNative()); - -# if (defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE) \ - || defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_NOT_NATIVE)) -# error "Define only one of Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" -# endif -#elif defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_NOT_NATIVE) - // the runtime test should say the same thing - QVERIFY(!QAtomicPointer::isFetchAndStoreNative()); - -# if (defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE) \ - || defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_SOMETIMES_NATIVE)) -# error "Define only one of Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" -# endif -#else -# error "Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE is not defined" -#endif -} - -void tst_QAtomicPointer::isFetchAndStoreWaitFree() -{ -#if defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_WAIT_FREE) - // the runtime test should say the same thing - QVERIFY(QAtomicPointer::isFetchAndStoreWaitFree()); - - // enforce some invariants - QVERIFY(QAtomicPointer::isFetchAndStoreNative()); -# if defined(Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_NOT_NATIVE) -# error "Reference counting cannot be wait-free and unsupported at the same time!" -# endif -#else - // the runtime test should say the same thing - QVERIFY(!QAtomicPointer::isFetchAndStoreWaitFree()); -#endif -} - -void tst_QAtomicPointer::fetchAndStore() -{ - void *one = this; - void *two = &one; - void *three = &two; - - { - QAtomicPointer atomic1 = one; - QAtomicPointer atomic2 = two; - QAtomicPointer atomic3 = three; - - QVERIFY(atomic1 == one); - QVERIFY(atomic2 == two); - QVERIFY(atomic3 == three); - - QCOMPARE(atomic1.fetchAndStoreRelaxed(two), one); - QCOMPARE(atomic2.fetchAndStoreRelaxed(three), two); - QCOMPARE(atomic3.fetchAndStoreRelaxed(one), three); - - QVERIFY(atomic1 == two); - QVERIFY(atomic2 == three); - QVERIFY(atomic3 == one); - } - - { - QAtomicPointer atomic1 = one; - QAtomicPointer atomic2 = two; - QAtomicPointer atomic3 = three; - - QVERIFY(atomic1 == one); - QVERIFY(atomic2 == two); - QVERIFY(atomic3 == three); - - QCOMPARE(atomic1.fetchAndStoreAcquire(two), one); - QCOMPARE(atomic2.fetchAndStoreAcquire(three), two); - QCOMPARE(atomic3.fetchAndStoreAcquire(one), three); - - QVERIFY(atomic1 == two); - QVERIFY(atomic2 == three); - QVERIFY(atomic3 == one); - } - - { - QAtomicPointer atomic1 = one; - QAtomicPointer atomic2 = two; - QAtomicPointer atomic3 = three; - - QVERIFY(atomic1 == one); - QVERIFY(atomic2 == two); - QVERIFY(atomic3 == three); - - QCOMPARE(atomic1.fetchAndStoreRelease(two), one); - QCOMPARE(atomic2.fetchAndStoreRelease(three), two); - QCOMPARE(atomic3.fetchAndStoreRelease(one), three); - - QVERIFY(atomic1 == two); - QVERIFY(atomic2 == three); - QVERIFY(atomic3 == one); - } - - { - QAtomicPointer atomic1 = one; - QAtomicPointer atomic2 = two; - QAtomicPointer atomic3 = three; - - QVERIFY(atomic1 == one); - QVERIFY(atomic2 == two); - QVERIFY(atomic3 == three); - - QCOMPARE(atomic1.fetchAndStoreOrdered(two), one); - QCOMPARE(atomic2.fetchAndStoreOrdered(three), two); - QCOMPARE(atomic3.fetchAndStoreOrdered(one), three); - - QVERIFY(atomic1 == two); - QVERIFY(atomic2 == three); - QVERIFY(atomic3 == one); - } -} - -void tst_QAtomicPointer::isFetchAndAddNative() -{ -#if defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE) - // the runtime test should say the same thing - QVERIFY(QAtomicPointer::isFetchAndAddNative()); - -# if (defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_SOMETIMES_NATIVE) \ - || defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_NOT_NATIVE)) -# error "Define only one of Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" -# endif -#elif defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_SOMETIMES_NATIVE) - // could be either, just want to make sure the function is implemented - QVERIFY(QAtomicPointer::isFetchAndAddNative() - || !QAtomicPointer::isFetchAndAddNative()); - -# if (defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE) \ - || defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_NOT_NATIVE)) -# error "Define only one of Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" -# endif -#elif defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_NOT_NATIVE) - // the runtime test should say the same thing - QVERIFY(!QAtomicPointer::isFetchAndAddNative()); - -# if (defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE) \ - || defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_SOMETIMES_NATIVE)) -# error "Define only one of Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE" -# endif -#else -# error "Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_{ALWAYS,SOMTIMES,NOT}_NATIVE is not defined" -#endif -} - -void tst_QAtomicPointer::isFetchAndAddWaitFree() -{ -#if defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_WAIT_FREE) - // the runtime test should say the same thing - QVERIFY(QAtomicPointer::isFetchAndAddWaitFree()); - - // enforce some invariants - QVERIFY(QAtomicPointer::isFetchAndAddNative()); -# if defined(Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_NOT_NATIVE) -# error "Reference counting cannot be wait-free and unsupported at the same time!" -# endif -#else - // the runtime test should say the same thing - QVERIFY(!QAtomicPointer::isFetchAndAddWaitFree()); -#endif -} - -void tst_QAtomicPointer::fetchAndAdd_data() -{ - QTest::addColumn("valueToAdd"); - - QTest::newRow("0") << 0; - QTest::newRow("1") << 1; - QTest::newRow("2") << 2; - QTest::newRow("10") << 10; - QTest::newRow("31") << 31; - QTest::newRow("51") << 51; - QTest::newRow("72") << 72; - QTest::newRow("810") << 810; - QTest::newRow("631") << 631; - QTest::newRow("451") << 451; - QTest::newRow("272") << 272; - QTest::newRow("1810") << 1810; - QTest::newRow("3631") << 3631; - QTest::newRow("5451") << 5451; - QTest::newRow("7272") << 7272; - QTest::newRow("-1") << -1; - QTest::newRow("-2") << -2; - QTest::newRow("-10") << -10; - QTest::newRow("-31") << -31; - QTest::newRow("-51") << -51; - QTest::newRow("-72") << -72; - QTest::newRow("-810") << -810; - QTest::newRow("-631") << -631; - QTest::newRow("-451") << -451; - QTest::newRow("-272") << -272; - QTest::newRow("-1810") << -1810; - QTest::newRow("-3631") << -3631; - QTest::newRow("-5451") << -5451; - QTest::newRow("-7272") << -7272; -} - -void tst_QAtomicPointer::fetchAndAdd() -{ - QFETCH(int, valueToAdd); - - char c; - char *pc = &c; - short s; - short *ps = &s; - int i; - int *pi = &i; - - { - QAtomicPointer pointer1 = pc; - QCOMPARE(quintptr(pointer1.fetchAndAddRelaxed(valueToAdd)), quintptr(pc)); - QCOMPARE(quintptr(pointer1.fetchAndAddRelaxed(-valueToAdd)), quintptr(pc + valueToAdd)); - QCOMPARE(quintptr(static_cast(pointer1)), quintptr(pc)); - QAtomicPointer pointer2 = ps; - QCOMPARE(quintptr(pointer2.fetchAndAddRelaxed(valueToAdd)), quintptr(ps)); - QCOMPARE(quintptr(pointer2.fetchAndAddRelaxed(-valueToAdd)), quintptr(ps + valueToAdd)); - QCOMPARE(quintptr(static_cast(pointer2)), quintptr(ps)); - QAtomicPointer pointer3 = pi; - QCOMPARE(quintptr(pointer3.fetchAndAddRelaxed(valueToAdd)), quintptr(pi)); - QCOMPARE(quintptr(pointer3.fetchAndAddRelaxed(-valueToAdd)), quintptr(pi + valueToAdd)); - QCOMPARE(quintptr(static_cast(pointer3)), quintptr(pi)); - } - - { - QAtomicPointer pointer1 = pc; - QCOMPARE(quintptr(pointer1.fetchAndAddAcquire(valueToAdd)), quintptr(pc)); - QCOMPARE(quintptr(pointer1.fetchAndAddAcquire(-valueToAdd)), quintptr(pc + valueToAdd)); - QCOMPARE(quintptr(static_cast(pointer1)), quintptr(pc)); - QAtomicPointer pointer2 = ps; - QCOMPARE(quintptr(pointer2.fetchAndAddAcquire(valueToAdd)), quintptr(ps)); - QCOMPARE(quintptr(pointer2.fetchAndAddAcquire(-valueToAdd)), quintptr(ps + valueToAdd)); - QCOMPARE(quintptr(static_cast(pointer2)), quintptr(ps)); - QAtomicPointer pointer3 = pi; - QCOMPARE(quintptr(pointer3.fetchAndAddAcquire(valueToAdd)), quintptr(pi)); - QCOMPARE(quintptr(pointer3.fetchAndAddAcquire(-valueToAdd)), quintptr(pi + valueToAdd)); - QCOMPARE(quintptr(static_cast(pointer3)), quintptr(pi)); - } - - { - QAtomicPointer pointer1 = pc; - QCOMPARE(quintptr(pointer1.fetchAndAddRelease(valueToAdd)), quintptr(pc)); - QCOMPARE(quintptr(pointer1.fetchAndAddRelease(-valueToAdd)), quintptr(pc + valueToAdd)); - QCOMPARE(quintptr(static_cast(pointer1)), quintptr(pc)); - QAtomicPointer pointer2 = ps; - QCOMPARE(quintptr(pointer2.fetchAndAddRelease(valueToAdd)), quintptr(ps)); - QCOMPARE(quintptr(pointer2.fetchAndAddRelease(-valueToAdd)), quintptr(ps + valueToAdd)); - QCOMPARE(quintptr(static_cast(pointer2)), quintptr(ps)); - QAtomicPointer pointer3 = pi; - QCOMPARE(quintptr(pointer3.fetchAndAddRelease(valueToAdd)), quintptr(pi)); - QCOMPARE(quintptr(pointer3.fetchAndAddRelease(-valueToAdd)), quintptr(pi + valueToAdd)); - QCOMPARE(quintptr(static_cast(pointer3)), quintptr(pi)); - } - - { - QAtomicPointer pointer1 = pc; - QCOMPARE(quintptr(pointer1.fetchAndAddOrdered(valueToAdd)), quintptr(pc)); - QCOMPARE(quintptr(pointer1.fetchAndAddOrdered(-valueToAdd)), quintptr(pc + valueToAdd)); - QCOMPARE(quintptr(static_cast(pointer1)), quintptr(pc)); - QAtomicPointer pointer2 = ps; - QCOMPARE(quintptr(pointer2.fetchAndAddOrdered(valueToAdd)), quintptr(ps)); - QCOMPARE(quintptr(pointer2.fetchAndAddOrdered(-valueToAdd)), quintptr(ps + valueToAdd)); - QCOMPARE(quintptr(static_cast(pointer2)), quintptr(ps)); - QAtomicPointer pointer3 = pi; - QCOMPARE(quintptr(pointer3.fetchAndAddOrdered(valueToAdd)), quintptr(pi)); - QCOMPARE(quintptr(pointer3.fetchAndAddOrdered(-valueToAdd)), quintptr(pi + valueToAdd)); - QCOMPARE(quintptr(static_cast(pointer3)), quintptr(pi)); - } -} - -QTEST_APPLESS_MAIN(tst_QAtomicPointer) -#include "tst_qatomicpointer.moc" diff --git a/tests/auto/qmutex/.gitignore b/tests/auto/qmutex/.gitignore deleted file mode 100644 index 2f6b74166f..0000000000 --- a/tests/auto/qmutex/.gitignore +++ /dev/null @@ -1 +0,0 @@ -tst_qmutex diff --git a/tests/auto/qmutex/qmutex.pro b/tests/auto/qmutex/qmutex.pro deleted file mode 100644 index 608b08e16e..0000000000 --- a/tests/auto/qmutex/qmutex.pro +++ /dev/null @@ -1,5 +0,0 @@ -load(qttest_p4) -SOURCES += tst_qmutex.cpp -QT = core -CONFIG += parallel_test -CONFIG += insignificant_test diff --git a/tests/auto/qmutex/tst_qmutex.cpp b/tests/auto/qmutex/tst_qmutex.cpp deleted file mode 100644 index 7ad6a98a4d..0000000000 --- a/tests/auto/qmutex/tst_qmutex.cpp +++ /dev/null @@ -1,640 +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 - -#include -#include -#include -#include -#include -#include - -//TESTED_CLASS= -//TESTED_FILES= - -class tst_QMutex : public QObject -{ - Q_OBJECT - -public: - tst_QMutex(); - virtual ~tst_QMutex(); - -private slots: - void tryLock(); - void lock_unlock_locked_tryLock(); - void stressTest(); - void tryLockRace(); - void qtbug16115_trylock(); - void moreStress(); -}; - -static const int iterations = 100; - -tst_QMutex::tst_QMutex() - -{ -} - -tst_QMutex::~tst_QMutex() -{ -} - -QAtomicInt lockCount(0); -QMutex normalMutex, recursiveMutex(QMutex::Recursive); -QSemaphore testsTurn; -QSemaphore threadsTurn; - -enum { waitTime = 100 }; - -void tst_QMutex::tryLock() -{ - // test non-recursive mutex - { - class Thread : public QThread - { - public: - void run() - { - testsTurn.release(); - - threadsTurn.acquire(); - QVERIFY(!normalMutex.tryLock()); - testsTurn.release(); - - threadsTurn.acquire(); - QVERIFY(normalMutex.tryLock()); - QVERIFY(lockCount.testAndSetRelaxed(0, 1)); - QVERIFY(!normalMutex.tryLock()); - QVERIFY(lockCount.testAndSetRelaxed(1, 0)); - normalMutex.unlock(); - testsTurn.release(); - - threadsTurn.acquire(); - QTime timer; - timer.start(); - QVERIFY(!normalMutex.tryLock(waitTime)); - QVERIFY(timer.elapsed() >= waitTime); - testsTurn.release(); - - threadsTurn.acquire(); - timer.start(); - QVERIFY(normalMutex.tryLock(waitTime)); - QVERIFY(timer.elapsed() <= waitTime); - QVERIFY(lockCount.testAndSetRelaxed(0, 1)); - timer.start(); - QVERIFY(!normalMutex.tryLock(waitTime)); - QVERIFY(timer.elapsed() >= waitTime); - QVERIFY(lockCount.testAndSetRelaxed(1, 0)); - normalMutex.unlock(); - testsTurn.release(); - - threadsTurn.acquire(); - QVERIFY(!normalMutex.tryLock(0)); - testsTurn.release(); - - threadsTurn.acquire(); - timer.start(); - QVERIFY(normalMutex.tryLock(0)); - QVERIFY(timer.elapsed() < waitTime); - QVERIFY(lockCount.testAndSetRelaxed(0, 1)); - QVERIFY(!normalMutex.tryLock(0)); - QVERIFY(lockCount.testAndSetRelaxed(1, 0)); - normalMutex.unlock(); - testsTurn.release(); - - threadsTurn.acquire(); - } - }; - - Thread thread; - thread.start(); - - // thread can't acquire lock - testsTurn.acquire(); - normalMutex.lock(); - QVERIFY(lockCount.testAndSetRelaxed(0, 1)); - threadsTurn.release(); - - // thread can acquire lock - testsTurn.acquire(); - QVERIFY(lockCount.testAndSetRelaxed(1, 0)); - normalMutex.unlock(); - threadsTurn.release(); - - // thread can't acquire lock, timeout = waitTime - testsTurn.acquire(); - normalMutex.lock(); - QVERIFY(lockCount.testAndSetRelaxed(0, 1)); - threadsTurn.release(); - - // thread can acquire lock, timeout = waitTime - testsTurn.acquire(); - QVERIFY(lockCount.testAndSetRelaxed(1, 0)); - normalMutex.unlock(); - threadsTurn.release(); - - // thread can't acquire lock, timeout = 0 - testsTurn.acquire(); - normalMutex.lock(); - QVERIFY(lockCount.testAndSetRelaxed(0, 1)); - threadsTurn.release(); - - // thread can acquire lock, timeout = 0 - testsTurn.acquire(); - QVERIFY(lockCount.testAndSetRelaxed(1, 0)); - normalMutex.unlock(); - threadsTurn.release(); - - // wait for thread to finish - testsTurn.acquire(); - threadsTurn.release(); - thread.wait(); - } - - // test recursive mutex - { - class Thread : public QThread - { - public: - void run() - { - testsTurn.release(); - - threadsTurn.acquire(); - QVERIFY(!recursiveMutex.tryLock()); - testsTurn.release(); - - threadsTurn.acquire(); - QVERIFY(recursiveMutex.tryLock()); - QVERIFY(lockCount.testAndSetRelaxed(0, 1)); - QVERIFY(recursiveMutex.tryLock()); - QVERIFY(lockCount.testAndSetRelaxed(1, 2)); - QVERIFY(lockCount.testAndSetRelaxed(2, 1)); - recursiveMutex.unlock(); - QVERIFY(lockCount.testAndSetRelaxed(1, 0)); - recursiveMutex.unlock(); - testsTurn.release(); - - threadsTurn.acquire(); - QTime timer; - timer.start(); - QVERIFY(!recursiveMutex.tryLock(waitTime)); - QVERIFY(timer.elapsed() >= waitTime); - QVERIFY(!recursiveMutex.tryLock(0)); - testsTurn.release(); - - threadsTurn.acquire(); - timer.start(); - QVERIFY(recursiveMutex.tryLock(waitTime)); - QVERIFY(timer.elapsed() <= waitTime); - QVERIFY(lockCount.testAndSetRelaxed(0, 1)); - QVERIFY(recursiveMutex.tryLock(waitTime)); - QVERIFY(lockCount.testAndSetRelaxed(1, 2)); - QVERIFY(lockCount.testAndSetRelaxed(2, 1)); - recursiveMutex.unlock(); - QVERIFY(lockCount.testAndSetRelaxed(1, 0)); - recursiveMutex.unlock(); - testsTurn.release(); - - threadsTurn.acquire(); - QVERIFY(!recursiveMutex.tryLock(0)); - QVERIFY(!recursiveMutex.tryLock(0)); - testsTurn.release(); - - threadsTurn.acquire(); - timer.start(); - QVERIFY(recursiveMutex.tryLock(0)); - QVERIFY(timer.elapsed() < waitTime); - QVERIFY(lockCount.testAndSetRelaxed(0, 1)); - QVERIFY(recursiveMutex.tryLock(0)); - QVERIFY(lockCount.testAndSetRelaxed(1, 2)); - QVERIFY(lockCount.testAndSetRelaxed(2, 1)); - recursiveMutex.unlock(); - QVERIFY(lockCount.testAndSetRelaxed(1, 0)); - recursiveMutex.unlock(); - testsTurn.release(); - - threadsTurn.acquire(); - } - }; - - Thread thread; - thread.start(); - - // thread can't acquire lock - testsTurn.acquire(); - recursiveMutex.lock(); - QVERIFY(lockCount.testAndSetRelaxed(0, 1)); - recursiveMutex.lock(); - QVERIFY(lockCount.testAndSetRelaxed(1, 2)); - threadsTurn.release(); - - // thread can acquire lock - testsTurn.acquire(); - QVERIFY(lockCount.testAndSetRelaxed(2, 1)); - recursiveMutex.unlock(); - QVERIFY(lockCount.testAndSetRelaxed(1, 0)); - recursiveMutex.unlock(); - threadsTurn.release(); - - // thread can't acquire lock, timeout = waitTime - testsTurn.acquire(); - recursiveMutex.lock(); - QVERIFY(lockCount.testAndSetRelaxed(0, 1)); - recursiveMutex.lock(); - QVERIFY(lockCount.testAndSetRelaxed(1, 2)); - threadsTurn.release(); - - // thread can acquire lock, timeout = waitTime - testsTurn.acquire(); - QVERIFY(lockCount.testAndSetRelaxed(2, 1)); - recursiveMutex.unlock(); - QVERIFY(lockCount.testAndSetRelaxed(1, 0)); - recursiveMutex.unlock(); - threadsTurn.release(); - - // thread can't acquire lock, timeout = 0 - testsTurn.acquire(); - recursiveMutex.lock(); - QVERIFY(lockCount.testAndSetRelaxed(0, 1)); - recursiveMutex.lock(); - QVERIFY(lockCount.testAndSetRelaxed(1, 2)); - threadsTurn.release(); - - // thread can acquire lock, timeout = 0 - testsTurn.acquire(); - QVERIFY(lockCount.testAndSetRelaxed(2, 1)); - recursiveMutex.unlock(); - QVERIFY(lockCount.testAndSetRelaxed(1, 0)); - recursiveMutex.unlock(); - threadsTurn.release(); - - // stop thread - testsTurn.acquire(); - threadsTurn.release(); - thread.wait(); - } -} - -class mutex_Thread : public QThread -{ -public: - QMutex mutex; - QWaitCondition cond; - - QMutex &test_mutex; - - inline mutex_Thread(QMutex &m) : test_mutex(m) { } - - void run() - { - test_mutex.lock(); - - mutex.lock(); - for (int i = 0; i < iterations; ++i) { - cond.wakeOne(); - cond.wait(&mutex); - } - mutex.unlock(); - - test_mutex.unlock(); - } -}; - -class rmutex_Thread : public QThread -{ -public: - QMutex mutex; - QWaitCondition cond; - - QMutex &test_mutex; - - inline rmutex_Thread(QMutex &m) : test_mutex(m) { } - - void run() - { - test_mutex.lock(); - test_mutex.lock(); - test_mutex.lock(); - test_mutex.lock(); - - mutex.lock(); - for (int i = 0; i < iterations; ++i) { - cond.wakeOne(); - cond.wait(&mutex); - } - mutex.unlock(); - - test_mutex.unlock(); - test_mutex.unlock(); - test_mutex.unlock(); - test_mutex.unlock(); - } -}; - -void tst_QMutex::lock_unlock_locked_tryLock() -{ - // normal mutex - QMutex mutex; - mutex_Thread thread(mutex); - - QMutex rmutex(QMutex::Recursive); - rmutex_Thread rthread(rmutex); - - for (int i = 0; i < iterations; ++i) { - // normal mutex - QVERIFY(mutex.tryLock()); - mutex.unlock(); - - thread.mutex.lock(); - thread.start(); - - for (int j = 0; j < iterations; ++j) { - QVERIFY(thread.cond.wait(&thread.mutex, 10000)); - QVERIFY(!mutex.tryLock()); - - thread.cond.wakeOne(); - } - - thread.mutex.unlock(); - - QVERIFY(thread.wait(10000)); - QVERIFY(mutex.tryLock()); - - mutex.unlock(); - - // recursive mutex - QVERIFY(rmutex.tryLock()); - QVERIFY(rmutex.tryLock()); - QVERIFY(rmutex.tryLock()); - QVERIFY(rmutex.tryLock()); - - rmutex.unlock(); - rmutex.unlock(); - rmutex.unlock(); - rmutex.unlock(); - - rthread.mutex.lock(); - rthread.start(); - - for (int k = 0; k < iterations; ++k) { - QVERIFY(rthread.cond.wait(&rthread.mutex, 10000)); - QVERIFY(!rmutex.tryLock()); - - rthread.cond.wakeOne(); - } - - rthread.mutex.unlock(); - - QVERIFY(rthread.wait(10000)); - QVERIFY(rmutex.tryLock()); - QVERIFY(rmutex.tryLock()); - QVERIFY(rmutex.tryLock()); - QVERIFY(rmutex.tryLock()); - - rmutex.unlock(); - rmutex.unlock(); - rmutex.unlock(); - rmutex.unlock(); - } -} - -enum { one_minute = 6 * 1000, //not really one minute, but else it is too long. - threadCount = 10 }; - -class StressTestThread : public QThread -{ - QTime t; -public: - static QBasicAtomicInt lockCount; - static QBasicAtomicInt sentinel; - static QMutex mutex; - static int errorCount; - void start() - { - t.start(); - QThread::start(); - } - void run() - { - while (t.elapsed() < one_minute) { - mutex.lock(); - if (sentinel.ref()) ++errorCount; - if (!sentinel.deref()) ++errorCount; - lockCount.ref(); - mutex.unlock(); - if (mutex.tryLock()) { - if (sentinel.ref()) ++errorCount; - if (!sentinel.deref()) ++errorCount; - lockCount.ref(); - mutex.unlock(); - } - } - } -}; -QMutex StressTestThread::mutex; -QBasicAtomicInt StressTestThread::lockCount = Q_BASIC_ATOMIC_INITIALIZER(0); -QBasicAtomicInt StressTestThread::sentinel = Q_BASIC_ATOMIC_INITIALIZER(-1); -int StressTestThread::errorCount = 0; - -void tst_QMutex::stressTest() -{ - StressTestThread 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)); - QCOMPARE(StressTestThread::errorCount, 0); - qDebug("locked %d times", int(StressTestThread::lockCount)); -} - -class TryLockRaceThread : public QThread -{ -public: - static QMutex mutex; - - void run() - { - QTime t; - t.start(); - do { - if (mutex.tryLock()) - mutex.unlock(); - } while (t.elapsed() < one_minute/2); - } -}; -QMutex TryLockRaceThread::mutex; - -void tst_QMutex::tryLockRace() -{ - // mutex not in use, should be able to lock it - QVERIFY(TryLockRaceThread::mutex.tryLock()); - TryLockRaceThread::mutex.unlock(); - - // try to break tryLock - TryLockRaceThread thread[threadCount]; - for (int i = 0; i < threadCount; ++i) - thread[i].start(); - for (int i = 0; i < threadCount; ++i) - QVERIFY(thread[i].wait()); - - // mutex not in use, should be able to lock it - QVERIFY(TryLockRaceThread::mutex.tryLock()); - TryLockRaceThread::mutex.unlock(); -} - -// Variable that will be protected by the mutex. Volatile so that the -// the optimiser doesn't mess with it based on the increment-then-decrement -// usage pattern. -static volatile int qtbug16115_trylock_counter; -// Counter for how many times the protected variable has an incorrect value. -static int qtbug16115_failure_count = 0; - -void tst_QMutex::qtbug16115_trylock() -{ - //Used to deadlock on unix - struct TrylockThread : QThread { - TrylockThread(QMutex &mut) : mut(mut) {} - QMutex &mut; - void run() { - for (int i = 0; i < 100000; ++i) { - if (mut.tryLock(0)) { - if ((++qtbug16115_trylock_counter) != 1) - ++qtbug16115_failure_count; - if ((--qtbug16115_trylock_counter) != 0) - ++qtbug16115_failure_count; - mut.unlock(); - } - } - } - }; - QMutex mut; - TrylockThread t1(mut); - TrylockThread t2(mut); - TrylockThread t3(mut); - t1.start(); - t2.start(); - t3.start(); - - for (int i = 0; i < 100000; ++i) { - mut.lock(); - if ((++qtbug16115_trylock_counter) != 1) - ++qtbug16115_failure_count; - if ((--qtbug16115_trylock_counter) != 0) - ++qtbug16115_failure_count; - mut.unlock(); - } - t1.wait(); - t2.wait(); - t3.wait(); - 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/auto/qmutexlocker/.gitignore b/tests/auto/qmutexlocker/.gitignore deleted file mode 100644 index 7c75c1c2f4..0000000000 --- a/tests/auto/qmutexlocker/.gitignore +++ /dev/null @@ -1 +0,0 @@ -tst_qmutexlocker diff --git a/tests/auto/qmutexlocker/qmutexlocker.pro b/tests/auto/qmutexlocker/qmutexlocker.pro deleted file mode 100644 index 01c369101b..0000000000 --- a/tests/auto/qmutexlocker/qmutexlocker.pro +++ /dev/null @@ -1,4 +0,0 @@ -load(qttest_p4) -SOURCES += tst_qmutexlocker.cpp -QT = core -CONFIG += parallel_test diff --git a/tests/auto/qmutexlocker/tst_qmutexlocker.cpp b/tests/auto/qmutexlocker/tst_qmutexlocker.cpp deleted file mode 100644 index a663b60be7..0000000000 --- a/tests/auto/qmutexlocker/tst_qmutexlocker.cpp +++ /dev/null @@ -1,236 +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 - -#include -#include -#include -#include - -//TESTED_CLASS= -//TESTED_FILES= - -class tst_QMutexLockerThread : public QThread -{ -public: - QMutex mutex; - QSemaphore semaphore, testSemaphore; - - void waitForTest() - { - semaphore.release(); - testSemaphore.acquire(); - } - - tst_QMutexLockerThread() - : mutex(QMutex::Recursive) - { - } -}; - -class tst_QMutexLocker : public QObject -{ - Q_OBJECT - -public: - tst_QMutexLocker(); - ~tst_QMutexLocker(); - - tst_QMutexLockerThread *thread; - - void waitForThread() - { - thread->semaphore.acquire(); - } - void releaseThread() - { - thread->testSemaphore.release(); - } - -private slots: - void scopeTest(); - void unlockAndRelockTest(); - void lockerStateTest(); -}; - -tst_QMutexLocker::tst_QMutexLocker() -{ -} - -tst_QMutexLocker::~tst_QMutexLocker() -{ -} - -void tst_QMutexLocker::scopeTest() -{ - class ScopeTestThread : public tst_QMutexLockerThread - { - public: - void run() - { - waitForTest(); - - { - QMutexLocker locker(&mutex); - waitForTest(); - } - - waitForTest(); - } - }; - - thread = new ScopeTestThread; - thread->start(); - - waitForThread(); - // mutex should be unlocked before entering the scope that creates the QMutexLocker - QVERIFY(thread->mutex.tryLock()); - thread->mutex.unlock(); - releaseThread(); - - waitForThread(); - // mutex should be locked by the QMutexLocker - QVERIFY(!thread->mutex.tryLock()); - releaseThread(); - - waitForThread(); - // mutex should be unlocked when the QMutexLocker goes out of scope - QVERIFY(thread->mutex.tryLock()); - thread->mutex.unlock(); - releaseThread(); - - QVERIFY(thread->wait()); - - delete thread; - thread = 0; -} - - -void tst_QMutexLocker::unlockAndRelockTest() -{ - class UnlockAndRelockThread : public tst_QMutexLockerThread - { - public: - void run() - { - QMutexLocker locker(&mutex); - - waitForTest(); - - locker.unlock(); - - waitForTest(); - - locker.relock(); - - waitForTest(); - } - }; - - thread = new UnlockAndRelockThread; - thread->start(); - - waitForThread(); - // mutex should be locked by the QMutexLocker - QVERIFY(!thread->mutex.tryLock()); - releaseThread(); - - waitForThread(); - // mutex has been explicitly unlocked via QMutexLocker - QVERIFY(thread->mutex.tryLock()); - thread->mutex.unlock(); - releaseThread(); - - waitForThread(); - // mutex has been explicitly relocked via QMutexLocker - QVERIFY(!thread->mutex.tryLock()); - releaseThread(); - - QVERIFY(thread->wait()); - - delete thread; - thread = 0; -} - -void tst_QMutexLocker::lockerStateTest() -{ - class LockerStateThread : public tst_QMutexLockerThread - { - public: - void run() - { - { - QMutexLocker locker(&mutex); - locker.relock(); - locker.unlock(); - - waitForTest(); - } - - waitForTest(); - } - }; - - thread = new LockerStateThread; - thread->start(); - - waitForThread(); - // even though we relock() after creating the QMutexLocker, it shouldn't lock the mutex more than once - QVERIFY(thread->mutex.tryLock()); - thread->mutex.unlock(); - releaseThread(); - - waitForThread(); - // if we call QMutexLocker::unlock(), its destructor should do nothing - QVERIFY(thread->mutex.tryLock()); - thread->mutex.unlock(); - releaseThread(); - - QVERIFY(thread->wait()); - - delete thread; - thread = 0; -} - -QTEST_MAIN(tst_QMutexLocker) -#include "tst_qmutexlocker.moc" diff --git a/tests/auto/qreadlocker/.gitignore b/tests/auto/qreadlocker/.gitignore deleted file mode 100644 index 2539362670..0000000000 --- a/tests/auto/qreadlocker/.gitignore +++ /dev/null @@ -1 +0,0 @@ -tst_qreadlocker diff --git a/tests/auto/qreadlocker/qreadlocker.pro b/tests/auto/qreadlocker/qreadlocker.pro deleted file mode 100644 index ee533070a7..0000000000 --- a/tests/auto/qreadlocker/qreadlocker.pro +++ /dev/null @@ -1,4 +0,0 @@ -load(qttest_p4) -SOURCES += tst_qreadlocker.cpp -QT = core -CONFIG += parallel_test diff --git a/tests/auto/qreadlocker/tst_qreadlocker.cpp b/tests/auto/qreadlocker/tst_qreadlocker.cpp deleted file mode 100644 index 3ec9f1cb25..0000000000 --- a/tests/auto/qreadlocker/tst_qreadlocker.cpp +++ /dev/null @@ -1,231 +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 - -#include -#include -#include -#include - -//TESTED_CLASS= -//TESTED_FILES= - -class tst_QReadLockerThread : public QThread -{ -public: - QReadWriteLock lock; - QSemaphore semaphore, testSemaphore; - - void waitForTest() - { - semaphore.release(); - testSemaphore.acquire(); - } -}; - -class tst_QReadLocker : public QObject -{ - Q_OBJECT - -public: - tst_QReadLocker(); - ~tst_QReadLocker(); - - tst_QReadLockerThread *thread; - - void waitForThread() - { - thread->semaphore.acquire(); - } - void releaseThread() - { - thread->testSemaphore.release(); - } - -private slots: - void scopeTest(); - void unlockAndRelockTest(); - void lockerStateTest(); -}; - -tst_QReadLocker::tst_QReadLocker() -{ -} - -tst_QReadLocker::~tst_QReadLocker() -{ -} - -void tst_QReadLocker::scopeTest() -{ - class ScopeTestThread : public tst_QReadLockerThread - { - public: - void run() - { - waitForTest(); - - { - QReadLocker locker(&lock); - waitForTest(); - } - - waitForTest(); - } - }; - - thread = new ScopeTestThread; - thread->start(); - - waitForThread(); - // lock should be unlocked before entering the scope that creates the QReadLocker - QVERIFY(thread->lock.tryLockForWrite()); - thread->lock.unlock(); - releaseThread(); - - waitForThread(); - // lock should be locked by the QReadLocker - QVERIFY(!thread->lock.tryLockForWrite()); - releaseThread(); - - waitForThread(); - // lock should be unlocked when the QReadLocker goes out of scope - QVERIFY(thread->lock.tryLockForWrite()); - thread->lock.unlock(); - releaseThread(); - - QVERIFY(thread->wait()); - - delete thread; - thread = 0; -} - - -void tst_QReadLocker::unlockAndRelockTest() -{ - class UnlockAndRelockThread : public tst_QReadLockerThread - { - public: - void run() - { - QReadLocker locker(&lock); - - waitForTest(); - - locker.unlock(); - - waitForTest(); - - locker.relock(); - - waitForTest(); - } - }; - - thread = new UnlockAndRelockThread; - thread->start(); - - waitForThread(); - // lock should be locked by the QReadLocker - QVERIFY(!thread->lock.tryLockForWrite()); - releaseThread(); - - waitForThread(); - // lock has been explicitly unlocked via QReadLocker - QVERIFY(thread->lock.tryLockForWrite()); - thread->lock.unlock(); - releaseThread(); - - waitForThread(); - // lock has been explicitly relocked via QReadLocker - QVERIFY(!thread->lock.tryLockForWrite()); - releaseThread(); - - QVERIFY(thread->wait()); - - delete thread; - thread = 0; -} - -void tst_QReadLocker::lockerStateTest() -{ - class LockerStateThread : public tst_QReadLockerThread - { - public: - void run() - { - { - QReadLocker locker(&lock); - locker.relock(); - locker.unlock(); - - waitForTest(); - } - - waitForTest(); - } - }; - - thread = new LockerStateThread; - thread->start(); - - waitForThread(); - // even though we relock() after creating the QReadLocker, it shouldn't lock the lock more than once - QVERIFY(thread->lock.tryLockForWrite()); - thread->lock.unlock(); - releaseThread(); - - waitForThread(); - // if we call QReadLocker::unlock(), its destructor should do nothing - QVERIFY(thread->lock.tryLockForWrite()); - thread->lock.unlock(); - releaseThread(); - - QVERIFY(thread->wait()); - - delete thread; - thread = 0; -} - -QTEST_MAIN(tst_QReadLocker) -#include "tst_qreadlocker.moc" 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 -#include - - -#include -#include -#include -#include - -#ifdef Q_OS_UNIX -#include -#endif -#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) -#include -#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 - -//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= 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()start(); - for (i=0; iwait(); - for (i=0; istart(); - for (i=0; iwait(); - for (i=0; istart(QThread::NormalPriority); - for (i=0; istart(QThread::IdlePriority); - - for (i=0; iwait(); - for (i=0; iwait(); - - for (i=0; istart(QThread::NormalPriority); - for (i=0; istart(QThread::LowestPriority); - - for (i=0; iwait(); - for (i=0; iwait(); - - for (i=0; ilock(); - 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() 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" diff --git a/tests/auto/qsemaphore/.gitignore b/tests/auto/qsemaphore/.gitignore deleted file mode 100644 index fe86486af4..0000000000 --- a/tests/auto/qsemaphore/.gitignore +++ /dev/null @@ -1 +0,0 @@ -tst_qsemaphore diff --git a/tests/auto/qsemaphore/qsemaphore.pro b/tests/auto/qsemaphore/qsemaphore.pro deleted file mode 100644 index a75bf443bc..0000000000 --- a/tests/auto/qsemaphore/qsemaphore.pro +++ /dev/null @@ -1,7 +0,0 @@ -load(qttest_p4) -SOURCES += tst_qsemaphore.cpp -QT = core - - -CONFIG += parallel_test -mac*:CONFIG+=insignificant_test diff --git a/tests/auto/qsemaphore/tst_qsemaphore.cpp b/tests/auto/qsemaphore/tst_qsemaphore.cpp deleted file mode 100644 index a2c6bf16b7..0000000000 --- a/tests/auto/qsemaphore/tst_qsemaphore.cpp +++ /dev/null @@ -1,450 +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 - - -#include -#include -#include - -//TESTED_CLASS= -//TESTED_FILES= - -class tst_QSemaphore : public QObject -{ - Q_OBJECT - -public: - tst_QSemaphore(); - ~tst_QSemaphore(); - -private slots: - void acquire(); - void tryAcquire(); - void tryAcquireWithTimeout_data(); - void tryAcquireWithTimeout(); - void tryAcquireWithTimeoutStarvation(); - void release(); - void available(); - void producerConsumer(); -}; - -static QSemaphore *semaphore = 0; - -tst_QSemaphore::tst_QSemaphore() -{ } - -tst_QSemaphore::~tst_QSemaphore() -{ } - -class ThreadOne : public QThread -{ -public: - ThreadOne() {} - -protected: - void run() - { - int i = 0; - while ( i < 100 ) { - semaphore->acquire(); - i++; - semaphore->release(); - } - } -}; - -class ThreadN : public QThread -{ - int N; - -public: - ThreadN(int n) :N(n) { } - -protected: - void run() - { - int i = 0; - while ( i < 100 ) { - semaphore->acquire(N); - i++; - semaphore->release(N); - } - } -}; - -void tst_QSemaphore::acquire() -{ - { - // old incrementOne() test - QVERIFY(!semaphore); - semaphore = new QSemaphore; - // make some "thing" available - semaphore->release(); - - ThreadOne t1; - ThreadOne t2; - - t1.start(); - t2.start(); - - QVERIFY(t1.wait(4000)); - QVERIFY(t2.wait(4000)); - - delete semaphore; - semaphore = 0; - } - - // old incrementN() test - { - QVERIFY(!semaphore); - semaphore = new QSemaphore; - // make 4 "things" available - semaphore->release(4); - - ThreadN t1(2); - ThreadN t2(3); - - t1.start(); - t2.start(); - - QVERIFY(t1.wait(4000)); - QVERIFY(t2.wait(4000)); - - delete semaphore; - semaphore = 0; - } - - QSemaphore semaphore; - - QCOMPARE(semaphore.available(), 0); - semaphore.release(); - QCOMPARE(semaphore.available(), 1); - semaphore.release(); - QCOMPARE(semaphore.available(), 2); - semaphore.release(10); - QCOMPARE(semaphore.available(), 12); - semaphore.release(10); - QCOMPARE(semaphore.available(), 22); - - semaphore.acquire(); - QCOMPARE(semaphore.available(), 21); - semaphore.acquire(); - QCOMPARE(semaphore.available(), 20); - semaphore.acquire(10); - QCOMPARE(semaphore.available(), 10); - semaphore.acquire(10); - QCOMPARE(semaphore.available(), 0); -} - -void tst_QSemaphore::tryAcquire() -{ - QSemaphore semaphore; - - QCOMPARE(semaphore.available(), 0); - - semaphore.release(); - QCOMPARE(semaphore.available(), 1); - QVERIFY(!semaphore.tryAcquire(2)); - QCOMPARE(semaphore.available(), 1); - - semaphore.release(); - QCOMPARE(semaphore.available(), 2); - QVERIFY(!semaphore.tryAcquire(3)); - QCOMPARE(semaphore.available(), 2); - - semaphore.release(10); - QCOMPARE(semaphore.available(), 12); - QVERIFY(!semaphore.tryAcquire(100)); - QCOMPARE(semaphore.available(), 12); - - semaphore.release(10); - QCOMPARE(semaphore.available(), 22); - QVERIFY(!semaphore.tryAcquire(100)); - QCOMPARE(semaphore.available(), 22); - - QVERIFY(semaphore.tryAcquire()); - QCOMPARE(semaphore.available(), 21); - - QVERIFY(semaphore.tryAcquire()); - QCOMPARE(semaphore.available(), 20); - - QVERIFY(semaphore.tryAcquire(10)); - QCOMPARE(semaphore.available(), 10); - - QVERIFY(semaphore.tryAcquire(10)); - QCOMPARE(semaphore.available(), 0); - - // should not be able to acquire more - QVERIFY(!semaphore.tryAcquire()); - QCOMPARE(semaphore.available(), 0); - - QVERIFY(!semaphore.tryAcquire()); - QCOMPARE(semaphore.available(), 0); - - QVERIFY(!semaphore.tryAcquire(10)); - QCOMPARE(semaphore.available(), 0); - - QVERIFY(!semaphore.tryAcquire(10)); - QCOMPARE(semaphore.available(), 0); -} - -void tst_QSemaphore::tryAcquireWithTimeout_data() -{ - QTest::addColumn("timeout"); - - QTest::newRow("1s") << 1000; - QTest::newRow("10s") << 10000; -} - -void tst_QSemaphore::tryAcquireWithTimeout() -{ - QFETCH(int, timeout); - - QSemaphore semaphore; - QTime time; - -#define QVERIFYGE(a,b) {int e = a; if (a= " << #b << "=" << b; QVERIFY(e>=b);} -#define QVERIFYLE(a,b) {int e = a; if (btryAcquire(amountToConsume, timeout)) - break; - semaphore->release(amountToConsume); - } - } - }; - - QSemaphore semaphore; - semaphore.release(1); - - Thread consumer; - consumer.semaphore = &semaphore; - consumer.amountToConsume = 1; - consumer.timeout = 1000; - - // start the thread and wait for it to start consuming - consumer.start(); - consumer.startup.acquire(); - - // try to consume more than the thread we started is, and provide a longer - // timeout... we should timeout, not wait indefinitely - QVERIFY(!semaphore.tryAcquire(consumer.amountToConsume * 2, consumer.timeout * 2)); - - // the consumer should still be running - QVERIFY(consumer.isRunning() && !consumer.isFinished()); - - // acquire, and wait for smallConsumer to timeout - semaphore.acquire(); - QVERIFY(consumer.wait()); -} - -void tst_QSemaphore::release() -{ DEPENDS_ON("acquire"); } - -void tst_QSemaphore::available() -{ DEPENDS_ON("acquire"); } - -const char alphabet[] = "ACGTH"; -const int AlphabetSize = sizeof(alphabet) - 1; - -const int BufferSize = 4096; // GCD of BufferSize and alphabet size must be 1 -char buffer[BufferSize]; - -#ifndef Q_OS_WINCE -const int ProducerChunkSize = 3; -const int ConsumerChunkSize = 7; -const int Multiplier = 10; -#else -const int ProducerChunkSize = 2; -const int ConsumerChunkSize = 5; -const int Multiplier = 3; -#endif - -// note: the code depends on the fact that DataSize is a multiple of -// ProducerChunkSize, ConsumerChunkSize, and BufferSize -const int DataSize = ProducerChunkSize * ConsumerChunkSize * BufferSize * Multiplier; - -QSemaphore freeSpace(BufferSize); -QSemaphore usedSpace; - -class Producer : public QThread -{ -public: - void run(); -}; - -void Producer::run() -{ - for (int i = 0; i < DataSize; ++i) { - freeSpace.acquire(); - buffer[i % BufferSize] = alphabet[i % AlphabetSize]; - usedSpace.release(); - } - for (int i = 0; i < DataSize; ++i) { - if ((i % ProducerChunkSize) == 0) - freeSpace.acquire(ProducerChunkSize); - buffer[i % BufferSize] = alphabet[i % AlphabetSize]; - if ((i % ProducerChunkSize) == (ProducerChunkSize - 1)) - usedSpace.release(ProducerChunkSize); - } -} - -class Consumer : public QThread -{ -public: - void run(); -}; - -void Consumer::run() -{ - for (int i = 0; i < DataSize; ++i) { - usedSpace.acquire(); - QCOMPARE(buffer[i % BufferSize], alphabet[i % AlphabetSize]); - freeSpace.release(); - } - for (int i = 0; i < DataSize; ++i) { - if ((i % ConsumerChunkSize) == 0) - usedSpace.acquire(ConsumerChunkSize); - QCOMPARE(buffer[i % BufferSize], alphabet[i % AlphabetSize]); - if ((i % ConsumerChunkSize) == (ConsumerChunkSize - 1)) - freeSpace.release(ConsumerChunkSize); - } -} - -void tst_QSemaphore::producerConsumer() -{ - Producer producer; - Consumer consumer; - producer.start(); - consumer.start(); - producer.wait(); - consumer.wait(); -} - -QTEST_MAIN(tst_QSemaphore) -#include "tst_qsemaphore.moc" diff --git a/tests/auto/qthread/.gitignore b/tests/auto/qthread/.gitignore deleted file mode 100644 index 4413a75588..0000000000 --- a/tests/auto/qthread/.gitignore +++ /dev/null @@ -1 +0,0 @@ -tst_qthread diff --git a/tests/auto/qthread/qthread.pro b/tests/auto/qthread/qthread.pro deleted file mode 100644 index d3b1028034..0000000000 --- a/tests/auto/qthread/qthread.pro +++ /dev/null @@ -1,5 +0,0 @@ -load(qttest_p4) -SOURCES += tst_qthread.cpp -QT = core -symbian:LIBS += -llibpthread -CONFIG += parallel_test diff --git a/tests/auto/qthread/tst_qthread.cpp b/tests/auto/qthread/tst_qthread.cpp deleted file mode 100644 index 3c46212c16..0000000000 --- a/tests/auto/qthread/tst_qthread.cpp +++ /dev/null @@ -1,1249 +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 - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef Q_OS_UNIX -#include -#endif -#if defined(Q_OS_WINCE) -#include -#elif defined(Q_OS_WIN) -#include -#include -#endif - -//TESTED_CLASS= -//TESTED_FILES= - -class tst_QThread : public QObject -{ - Q_OBJECT - -public: - tst_QThread(); - virtual ~tst_QThread(); - -private slots: - void currentThreadId(); - void currentThread(); - void idealThreadCount(); - void isFinished(); - void isRunning(); - void setPriority(); - void priority(); - void setStackSize(); - void stackSize(); - void exit(); - void start(); - void terminate(); - void quit(); - void wait(); - void started(); - void finished(); - void terminated(); - void run(); - void exec(); - void setTerminationEnabled(); - void sleep(); - void msleep(); - void usleep(); - - void nativeThreadAdoption(); - void adoptedThreadAffinity(); - void adoptedThreadSetPriority(); - void adoptedThreadExit(); - void adoptedThreadExec(); - void adoptedThreadFinished(); - void adoptedThreadExecFinished(); - void adoptMultipleThreads(); - void adoptMultipleThreadsOverlap(); - - void QTBUG13810_exitAndStart(); - void QTBUG15378_exitAndExec(); - - void connectThreadFinishedSignalToObjectDeleteLaterSlot(); - void wait2(); - void wait3_slowDestructor(); - void destroyFinishRace(); - void startFinishRace(); - void startAndQuitCustomEventLoop(); - - void stressTest(); -}; - -enum { one_minute = 60 * 1000, five_minutes = 5 * one_minute }; - -class SignalRecorder : public QObject -{ - Q_OBJECT -public: - QAtomicInt activationCount; - - inline SignalRecorder() - { activationCount = 0; } - - bool wasActivated() - { return activationCount > 0; } - -public slots: - void slot(); -}; - -void SignalRecorder::slot() -{ activationCount.ref(); } - -class Current_Thread : public QThread -{ -public: - Qt::HANDLE id; - QThread *thread; - - void run() - { - id = QThread::currentThreadId(); - thread = QThread::currentThread(); - } -}; - -class Simple_Thread : public QThread -{ -public: - QMutex mutex; - QWaitCondition cond; - - void run() - { - QMutexLocker locker(&mutex); - cond.wakeOne(); - } -}; - -class Exit_Object : public QObject -{ - Q_OBJECT -public: - QThread *thread; - int code; -public slots: - void slot() - { thread->exit(code); } -}; - -class Exit_Thread : public Simple_Thread -{ -public: - Exit_Object *object; - int code; - int result; - - void run() - { - Simple_Thread::run(); - if (object) { - object->thread = this; - object->code = code; - QTimer::singleShot(100, object, SLOT(slot())); - } - result = exec(); - } -}; - -class Terminate_Thread : public Simple_Thread -{ -public: - void run() - { - setTerminationEnabled(false); - { - QMutexLocker locker(&mutex); - cond.wakeOne(); - cond.wait(&mutex, five_minutes); - } - setTerminationEnabled(true); - qFatal("tst_QThread: test case hung"); - } -}; - -class Quit_Object : public QObject -{ - Q_OBJECT -public: - QThread *thread; -public slots: - void slot() - { thread->quit(); } -}; - -class Quit_Thread : public Simple_Thread -{ -public: - Quit_Object *object; - int result; - - void run() - { - Simple_Thread::run(); - if (object) { - object->thread = this; - QTimer::singleShot(100, object, SLOT(slot())); - } - result = exec(); - } -}; - -class Sleep_Thread : public Simple_Thread -{ -public: - enum SleepType { Second, Millisecond, Microsecond }; - - SleepType sleepType; - int interval; - - int elapsed; // result, in *MILLISECONDS* - - void run() - { - QMutexLocker locker(&mutex); - - elapsed = 0; - QTime time; - time.start(); - switch (sleepType) { - case Second: - sleep(interval); - break; - case Millisecond: - msleep(interval); - break; - case Microsecond: - usleep(interval); - break; - } - elapsed = time.elapsed(); - - cond.wakeOne(); - } -}; - -tst_QThread::tst_QThread() - -{ -} - -tst_QThread::~tst_QThread() -{ - -} - -void tst_QThread::currentThreadId() -{ - Current_Thread thread; - thread.id = 0; - thread.thread = 0; - thread.start(); - QVERIFY(thread.wait(five_minutes)); - QVERIFY(thread.id != 0); - QVERIFY(thread.id != QThread::currentThreadId()); -} - -void tst_QThread::currentThread() -{ - QVERIFY(QThread::currentThread() != 0); - QCOMPARE(QThread::currentThread(), thread()); - - Current_Thread thread; - thread.id = 0; - thread.thread = 0; - thread.start(); - QVERIFY(thread.wait(five_minutes)); - QCOMPARE(thread.thread, (QThread *)&thread); -} - -void tst_QThread::idealThreadCount() -{ - QVERIFY(QThread::idealThreadCount() > 0); - qDebug() << "Available cpu cores:" << QThread::idealThreadCount(); -} - -void tst_QThread::isFinished() -{ - Simple_Thread thread; - QVERIFY(!thread.isFinished()); - QMutexLocker locker(&thread.mutex); - thread.start(); - QVERIFY(!thread.isFinished()); - thread.cond.wait(locker.mutex()); - QVERIFY(thread.wait(five_minutes)); - QVERIFY(thread.isFinished()); -} - -void tst_QThread::isRunning() -{ - Simple_Thread thread; - QVERIFY(!thread.isRunning()); - QMutexLocker locker(&thread.mutex); - thread.start(); - QVERIFY(thread.isRunning()); - thread.cond.wait(locker.mutex()); - QVERIFY(thread.wait(five_minutes)); - QVERIFY(!thread.isRunning()); -} - -void tst_QThread::setPriority() -{ - Simple_Thread thread; - - // cannot change the priority, since the thread is not running - QCOMPARE(thread.priority(), QThread::InheritPriority); - QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running"); - thread.setPriority(QThread::IdlePriority); - QCOMPARE(thread.priority(), QThread::InheritPriority); - QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running"); - thread.setPriority(QThread::LowestPriority); - QCOMPARE(thread.priority(), QThread::InheritPriority); - QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running"); - thread.setPriority(QThread::LowPriority); - QCOMPARE(thread.priority(), QThread::InheritPriority); - QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running"); - thread.setPriority(QThread::NormalPriority); - QCOMPARE(thread.priority(), QThread::InheritPriority); - QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running"); - thread.setPriority(QThread::HighPriority); - QCOMPARE(thread.priority(), QThread::InheritPriority); - QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running"); - thread.setPriority(QThread::HighestPriority); - QCOMPARE(thread.priority(), QThread::InheritPriority); - QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running"); - thread.setPriority(QThread::TimeCriticalPriority); - QCOMPARE(thread.priority(), QThread::InheritPriority); - - QCOMPARE(thread.priority(), QThread::InheritPriority); - QMutexLocker locker(&thread.mutex); - thread.start(); - - // change the priority of a running thread - QCOMPARE(thread.priority(), QThread::InheritPriority); - thread.setPriority(QThread::IdlePriority); - QCOMPARE(thread.priority(), QThread::IdlePriority); - thread.setPriority(QThread::LowestPriority); - QCOMPARE(thread.priority(), QThread::LowestPriority); - thread.setPriority(QThread::LowPriority); - QCOMPARE(thread.priority(), QThread::LowPriority); - thread.setPriority(QThread::NormalPriority); - QCOMPARE(thread.priority(), QThread::NormalPriority); - thread.setPriority(QThread::HighPriority); - QCOMPARE(thread.priority(), QThread::HighPriority); - thread.setPriority(QThread::HighestPriority); - QCOMPARE(thread.priority(), QThread::HighestPriority); - thread.setPriority(QThread::TimeCriticalPriority); - QCOMPARE(thread.priority(), QThread::TimeCriticalPriority); - thread.cond.wait(locker.mutex()); - QVERIFY(thread.wait(five_minutes)); - - QCOMPARE(thread.priority(), QThread::InheritPriority); - QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running"); - thread.setPriority(QThread::IdlePriority); - QCOMPARE(thread.priority(), QThread::InheritPriority); - QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running"); - thread.setPriority(QThread::LowestPriority); - QCOMPARE(thread.priority(), QThread::InheritPriority); - QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running"); - thread.setPriority(QThread::LowPriority); - QCOMPARE(thread.priority(), QThread::InheritPriority); - QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running"); - thread.setPriority(QThread::NormalPriority); - QCOMPARE(thread.priority(), QThread::InheritPriority); - QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running"); - thread.setPriority(QThread::HighPriority); - QCOMPARE(thread.priority(), QThread::InheritPriority); - QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running"); - thread.setPriority(QThread::HighestPriority); - QCOMPARE(thread.priority(), QThread::InheritPriority); - QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running"); - thread.setPriority(QThread::TimeCriticalPriority); - QCOMPARE(thread.priority(), QThread::InheritPriority); -} - -void tst_QThread::priority() -{ DEPENDS_ON("setPriority"); } - -void tst_QThread::setStackSize() -{ - Simple_Thread thread; - QCOMPARE(thread.stackSize(), 0u); - thread.setStackSize(8192u); - QCOMPARE(thread.stackSize(), 8192u); - thread.setStackSize(0u); - QCOMPARE(thread.stackSize(), 0u); -} - -void tst_QThread::stackSize() -{ - DEPENDS_ON("setStackSize"); -} - -void tst_QThread::exit() -{ - Exit_Thread thread; - thread.object = new Exit_Object; - thread.object->moveToThread(&thread); - thread.code = 42; - thread.result = 0; - QVERIFY(!thread.isFinished()); - QVERIFY(!thread.isRunning()); - QMutexLocker locker(&thread.mutex); - thread.start(); - QVERIFY(thread.isRunning()); - QVERIFY(!thread.isFinished()); - thread.cond.wait(locker.mutex()); - QVERIFY(thread.wait(five_minutes)); - QVERIFY(thread.isFinished()); - QVERIFY(!thread.isRunning()); - QCOMPARE(thread.result, thread.code); - delete thread.object; - - Exit_Thread thread2; - thread2.object = 0; - thread2.code = 53; - thread2.result = 0; - QMutexLocker locker2(&thread2.mutex); - thread2.start(); - thread2.exit(thread2.code); - thread2.cond.wait(locker2.mutex()); - QVERIFY(thread2.wait(five_minutes)); - QCOMPARE(thread2.result, thread2.code); -} - -void tst_QThread::start() -{ - QThread::Priority priorities[] = { - QThread::IdlePriority, - QThread::LowestPriority, - QThread::LowPriority, - QThread::NormalPriority, - QThread::HighPriority, - QThread::HighestPriority, - QThread::TimeCriticalPriority, - QThread::InheritPriority - }; - const int prio_count = sizeof(priorities) / sizeof(QThread::Priority); - - for (int i = 0; i < prio_count; ++i) { - Simple_Thread thread; - QVERIFY(!thread.isFinished()); - QVERIFY(!thread.isRunning()); - QMutexLocker locker(&thread.mutex); - thread.start(priorities[i]); - QVERIFY(thread.isRunning()); - QVERIFY(!thread.isFinished()); - thread.cond.wait(locker.mutex()); - QVERIFY(thread.wait(five_minutes)); - QVERIFY(thread.isFinished()); - QVERIFY(!thread.isRunning()); - } -} - -void tst_QThread::terminate() -{ - Terminate_Thread thread; - { - QMutexLocker locker(&thread.mutex); - thread.start(); - QVERIFY(thread.cond.wait(locker.mutex(), five_minutes)); - thread.terminate(); - thread.cond.wakeOne(); - } - QVERIFY(thread.wait(five_minutes)); -} - -void tst_QThread::quit() -{ - Quit_Thread thread; - thread.object = new Quit_Object; - thread.object->moveToThread(&thread); - thread.result = -1; - QVERIFY(!thread.isFinished()); - QVERIFY(!thread.isRunning()); - QMutexLocker locker(&thread.mutex); - thread.start(); - QVERIFY(thread.isRunning()); - QVERIFY(!thread.isFinished()); - thread.cond.wait(locker.mutex()); - QVERIFY(thread.wait(five_minutes)); - QVERIFY(thread.isFinished()); - QVERIFY(!thread.isRunning()); - QCOMPARE(thread.result, 0); - delete thread.object; - - Quit_Thread thread2; - thread2.object = 0; - thread2.result = -1; - QMutexLocker locker2(&thread2.mutex); - thread2.start(); - thread2.quit(); - thread2.cond.wait(locker2.mutex()); - QVERIFY(thread2.wait(five_minutes)); - QCOMPARE(thread2.result, 0); -} - -void tst_QThread::wait() -{ - DEPENDS_ON("isRunning"); - DEPENDS_ON("isFinished"); -} - -void tst_QThread::started() -{ - SignalRecorder recorder; - Simple_Thread thread; - connect(&thread, SIGNAL(started()), &recorder, SLOT(slot()), Qt::DirectConnection); - thread.start(); - QVERIFY(thread.wait(five_minutes)); - QVERIFY(recorder.wasActivated()); -} - -void tst_QThread::finished() -{ - SignalRecorder recorder; - Simple_Thread thread; - connect(&thread, SIGNAL(finished()), &recorder, SLOT(slot()), Qt::DirectConnection); - thread.start(); - QVERIFY(thread.wait(five_minutes)); - QVERIFY(recorder.wasActivated()); -} - -void tst_QThread::terminated() -{ - SignalRecorder recorder; - Terminate_Thread thread; - connect(&thread, SIGNAL(terminated()), &recorder, SLOT(slot()), Qt::DirectConnection); - { - QMutexLocker locker(&thread.mutex); - thread.start(); - thread.cond.wait(locker.mutex()); - thread.terminate(); - thread.cond.wakeOne(); - } - QVERIFY(thread.wait(five_minutes)); - QVERIFY(recorder.wasActivated()); -} - -void tst_QThread::run() -{ DEPENDS_ON("wait()"); } - -void tst_QThread::exec() -{ - DEPENDS_ON("exit()"); - DEPENDS_ON("quit()"); - - class MultipleExecThread : public QThread - { - public: - int res1, res2; - - MultipleExecThread() : res1(-2), res2(-2) { } - - void run() - { - { - Exit_Object o; - o.thread = this; - o.code = 1; - QTimer::singleShot(100, &o, SLOT(slot())); - res1 = exec(); - } - { - Exit_Object o; - o.thread = this; - o.code = 2; - QTimer::singleShot(100, &o, SLOT(slot())); - res2 = exec(); - } - } - }; - - MultipleExecThread thread; - thread.start(); - QVERIFY(thread.wait()); - - QCOMPARE(thread.res1, 1); - QCOMPARE(thread.res2, 2); -} - -void tst_QThread::setTerminationEnabled() -{ DEPENDS_ON("terminate"); } - -void tst_QThread::sleep() -{ - Sleep_Thread thread; - thread.sleepType = Sleep_Thread::Second; - thread.interval = 2; - thread.start(); - QVERIFY(thread.wait(five_minutes)); - QVERIFY(thread.elapsed >= 2000); -} - -void tst_QThread::msleep() -{ - Sleep_Thread thread; - thread.sleepType = Sleep_Thread::Millisecond; - thread.interval = 120; - thread.start(); - QVERIFY(thread.wait(five_minutes)); -#if defined (Q_OS_WIN) - // Since the resolution of QTime is so coarse... - QVERIFY(thread.elapsed >= 100); -#else - QVERIFY(thread.elapsed >= 120); -#endif -} - -void tst_QThread::usleep() -{ - Sleep_Thread thread; - thread.sleepType = Sleep_Thread::Microsecond; - thread.interval = 120000; - thread.start(); - QVERIFY(thread.wait(five_minutes)); -#if defined (Q_OS_WIN) - // Since the resolution of QTime is so coarse... - QVERIFY(thread.elapsed >= 100); -#else - QVERIFY(thread.elapsed >= 120); -#endif -} - -typedef void (*FunctionPointer)(void *); -void noop(void*) { } - -#ifdef Q_OS_SYMBIAN -typedef RThread ThreadHandle; -#elif defined Q_OS_UNIX - typedef pthread_t ThreadHandle; -#elif defined Q_OS_WIN - typedef HANDLE ThreadHandle; -#endif - -#ifdef Q_OS_WIN -#define WIN_FIX_STDCALL __stdcall -#else -#define WIN_FIX_STDCALL -#endif - -class NativeThreadWrapper -{ -public: - NativeThreadWrapper() : qthread(0), waitForStop(false) {} - void start(FunctionPointer functionPointer = noop, void *data = 0); - void startAndWait(FunctionPointer functionPointer = noop, void *data = 0); - void join(); - void setWaitForStop() { waitForStop = true; } - void stop(); - - ThreadHandle nativeThreadHandle; - QThread *qthread; - QWaitCondition startCondition; - QMutex mutex; - bool waitForStop; - QWaitCondition stopCondition; -protected: - static void *runUnix(void *data); - static unsigned WIN_FIX_STDCALL runWin(void *data); - static int runSymbian(void *data); - - FunctionPointer functionPointer; - void *data; -}; - -void NativeThreadWrapper::start(FunctionPointer functionPointer, void *data) -{ - this->functionPointer = functionPointer; - this->data = data; -#ifdef Q_OS_SYMBIAN - qt_symbian_throwIfError(nativeThreadHandle.Create(KNullDesC(), NativeThreadWrapper::runSymbian, 1024, &User::Allocator(), this)); - nativeThreadHandle.Resume(); -#elif defined Q_OS_UNIX - const int state = pthread_create(&nativeThreadHandle, 0, NativeThreadWrapper::runUnix, this); - Q_UNUSED(state); -#elif defined(Q_OS_WINCE) - nativeThreadHandle = CreateThread(NULL, 0 , (LPTHREAD_START_ROUTINE)NativeThreadWrapper::runWin , this, 0, NULL); -#elif defined Q_OS_WIN - unsigned thrdid = 0; - nativeThreadHandle = (Qt::HANDLE) _beginthreadex(NULL, 0, NativeThreadWrapper::runWin, this, 0, &thrdid); -#endif -} - -void NativeThreadWrapper::startAndWait(FunctionPointer functionPointer, void *data) -{ - QMutexLocker locker(&mutex); - start(functionPointer, data); - startCondition.wait(locker.mutex()); -} - -void NativeThreadWrapper::join() -{ -#ifdef Q_OS_SYMBIAN - TRequestStatus stat; - nativeThreadHandle.Logon(stat); - User::WaitForRequest(stat); - nativeThreadHandle.Close(); -#elif defined Q_OS_UNIX - pthread_join(nativeThreadHandle, 0); -#elif defined Q_OS_WIN - WaitForSingleObject(nativeThreadHandle, INFINITE); - CloseHandle(nativeThreadHandle); -#endif -} - -void *NativeThreadWrapper::runUnix(void *that) -{ - NativeThreadWrapper *nativeThreadWrapper = reinterpret_cast(that); - - // Adopt thread, create QThread object. - nativeThreadWrapper->qthread = QThread::currentThread(); - - // Release main thread. - { - QMutexLocker lock(&nativeThreadWrapper->mutex); - nativeThreadWrapper->startCondition.wakeOne(); - } - - // Run function. - nativeThreadWrapper->functionPointer(nativeThreadWrapper->data); - - // Wait for stop. - { - QMutexLocker lock(&nativeThreadWrapper->mutex); - if (nativeThreadWrapper->waitForStop) - nativeThreadWrapper->stopCondition.wait(lock.mutex()); - } - - return 0; -} - -unsigned WIN_FIX_STDCALL NativeThreadWrapper::runWin(void *data) -{ - runUnix(data); - return 0; -} - -int NativeThreadWrapper::runSymbian(void *data) -{ - runUnix(data); - return 0; -} - -void NativeThreadWrapper::stop() -{ - QMutexLocker lock(&mutex); - waitForStop = false; - stopCondition.wakeOne(); -} - -bool threadAdoptedOk = false; -QThread *mainThread; -void testNativeThreadAdoption(void *) -{ - threadAdoptedOk = (QThread::currentThreadId() != 0 - && QThread::currentThread() != 0 - && QThread::currentThread() != mainThread); -} -void tst_QThread::nativeThreadAdoption() -{ - threadAdoptedOk = false; - mainThread = QThread::currentThread(); - NativeThreadWrapper nativeThread; - nativeThread.setWaitForStop(); - nativeThread.startAndWait(testNativeThreadAdoption); - QVERIFY(nativeThread.qthread); - - nativeThread.stop(); - nativeThread.join(); - - QVERIFY(threadAdoptedOk); -} - -void adoptedThreadAffinityFunction(void *arg) -{ - QThread **affinity = reinterpret_cast(arg); - QThread *current = QThread::currentThread(); - affinity[0] = current; - affinity[1] = current->thread(); -} - -void tst_QThread::adoptedThreadAffinity() -{ - QThread *affinity[2] = { 0, 0 }; - - NativeThreadWrapper thread; - thread.startAndWait(adoptedThreadAffinityFunction, affinity); - thread.join(); - - // adopted thread should have affinity to itself - QCOMPARE(affinity[0], affinity[1]); -} - -void tst_QThread::adoptedThreadSetPriority() -{ - - NativeThreadWrapper nativeThread; - nativeThread.setWaitForStop(); - nativeThread.startAndWait(); - - // change the priority of a running thread - QCOMPARE(nativeThread.qthread->priority(), QThread::InheritPriority); - nativeThread.qthread->setPriority(QThread::IdlePriority); - QCOMPARE(nativeThread.qthread->priority(), QThread::IdlePriority); - nativeThread.qthread->setPriority(QThread::LowestPriority); - QCOMPARE(nativeThread.qthread->priority(), QThread::LowestPriority); - nativeThread.qthread->setPriority(QThread::LowPriority); - QCOMPARE(nativeThread.qthread->priority(), QThread::LowPriority); - nativeThread.qthread->setPriority(QThread::NormalPriority); - QCOMPARE(nativeThread.qthread->priority(), QThread::NormalPriority); - nativeThread.qthread->setPriority(QThread::HighPriority); - QCOMPARE(nativeThread.qthread->priority(), QThread::HighPriority); - nativeThread.qthread->setPriority(QThread::HighestPriority); - QCOMPARE(nativeThread.qthread->priority(), QThread::HighestPriority); - nativeThread.qthread->setPriority(QThread::TimeCriticalPriority); - QCOMPARE(nativeThread.qthread->priority(), QThread::TimeCriticalPriority); - - nativeThread.stop(); - nativeThread.join(); -} - -void tst_QThread::adoptedThreadExit() -{ - NativeThreadWrapper nativeThread; - nativeThread.setWaitForStop(); - - nativeThread.startAndWait(); - QVERIFY(nativeThread.qthread); - QVERIFY(nativeThread.qthread->isRunning()); - QVERIFY(!nativeThread.qthread->isFinished()); - - nativeThread.stop(); - nativeThread.join(); -} - -void adoptedThreadExecFunction(void *) -{ - QThread * const adoptedThread = QThread::currentThread(); - QEventLoop eventLoop(adoptedThread); - - const int code = 1; - Exit_Object o; - o.thread = adoptedThread; - o.code = code; - QTimer::singleShot(100, &o, SLOT(slot())); - - const int result = eventLoop.exec(); - QCOMPARE(result, code); -} - -void tst_QThread::adoptedThreadExec() -{ - NativeThreadWrapper nativeThread; - nativeThread.start(adoptedThreadExecFunction); - nativeThread.join(); -} - -/* - Test that you get the finished signal when an adopted thread exits. -*/ -void tst_QThread::adoptedThreadFinished() -{ - NativeThreadWrapper nativeThread; - nativeThread.setWaitForStop(); - nativeThread.startAndWait(); - - QObject::connect(nativeThread.qthread, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); - - nativeThread.stop(); - nativeThread.join(); - - QTestEventLoop::instance().enterLoop(5); - QVERIFY(!QTestEventLoop::instance().timeout()); -} - -void tst_QThread::adoptedThreadExecFinished() -{ - NativeThreadWrapper nativeThread; - nativeThread.setWaitForStop(); - nativeThread.startAndWait(adoptedThreadExecFunction); - - QObject::connect(nativeThread.qthread, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); - - nativeThread.stop(); - nativeThread.join(); - - QTestEventLoop::instance().enterLoop(5); - QVERIFY(!QTestEventLoop::instance().timeout()); -} - -void tst_QThread::adoptMultipleThreads() -{ -#if defined(Q_OS_WIN) - // Windows CE is not capable of handling that many threads. On the emulator it is dead with 26 threads already. -# if defined(Q_OS_WINCE) - const int numThreads = 20; -# else - // need to test lots of threads, so that we exceed MAXIMUM_WAIT_OBJECTS in qt_adopted_thread_watcher() - const int numThreads = 200; -# endif -#else - const int numThreads = 5; -#endif - QVector nativeThreads; - - SignalRecorder recorder; - - for (int i = 0; i < numThreads; ++i) { - nativeThreads.append(new NativeThreadWrapper()); - nativeThreads.at(i)->setWaitForStop(); - nativeThreads.at(i)->startAndWait(); - QObject::connect(nativeThreads.at(i)->qthread, SIGNAL(finished()), &recorder, SLOT(slot())); - } - - QObject::connect(nativeThreads.at(numThreads - 1)->qthread, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); - - for (int i = 0; i < numThreads; ++i) { - nativeThreads.at(i)->stop(); - nativeThreads.at(i)->join(); - delete nativeThreads.at(i); - } - - QTestEventLoop::instance().enterLoop(5); - QVERIFY(!QTestEventLoop::instance().timeout()); - QCOMPARE(int(recorder.activationCount), numThreads); -} - -void tst_QThread::adoptMultipleThreadsOverlap() -{ -#if defined(Q_OS_WIN) - // Windows CE is not capable of handling that many threads. On the emulator it is dead with 26 threads already. -# if defined(Q_OS_WINCE) - const int numThreads = 20; -# else - // need to test lots of threads, so that we exceed MAXIMUM_WAIT_OBJECTS in qt_adopted_thread_watcher() - const int numThreads = 200; -# endif -#elif defined(Q_OS_SYMBIAN) - // stress the monitoring thread's add function - const int numThreads = 100; -#else - const int numThreads = 5; -#endif - QVector nativeThreads; - - SignalRecorder recorder; - - for (int i = 0; i < numThreads; ++i) { - nativeThreads.append(new NativeThreadWrapper()); - nativeThreads.at(i)->setWaitForStop(); - nativeThreads.at(i)->mutex.lock(); - nativeThreads.at(i)->start(); - } - for (int i = 0; i < numThreads; ++i) { - nativeThreads.at(i)->startCondition.wait(&nativeThreads.at(i)->mutex); - QObject::connect(nativeThreads.at(i)->qthread, SIGNAL(finished()), &recorder, SLOT(slot())); - nativeThreads.at(i)->mutex.unlock(); - } - - QObject::connect(nativeThreads.at(numThreads - 1)->qthread, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); - - for (int i = 0; i < numThreads; ++i) { - nativeThreads.at(i)->stop(); - nativeThreads.at(i)->join(); - delete nativeThreads.at(i); - } - - QTestEventLoop::instance().enterLoop(5); - QVERIFY(!QTestEventLoop::instance().timeout()); - QCOMPARE(int(recorder.activationCount), numThreads); -} -void tst_QThread::stressTest() -{ -#if defined(Q_OS_WINCE) - QSKIP("Disconnects on WinCE, skipping...", SkipAll); -#endif - QTime t; - t.start(); - while (t.elapsed() < one_minute) { - Current_Thread t; - t.start(); - t.wait(one_minute); - } -} - -class Syncronizer : public QObject -{ Q_OBJECT -public slots: - void setProp(int p) { - if(m_prop != p) { - m_prop = p; - emit propChanged(p); - } - } -signals: - void propChanged(int); -public: - Syncronizer() : m_prop(42) {} - int m_prop; -}; - -void tst_QThread::QTBUG13810_exitAndStart() -{ - QThread thread; - thread.exit(555); //should do nothing - - thread.start(); - - //test that the thread is running by executing queued connected signal there - Syncronizer sync1; - sync1.moveToThread(&thread); - Syncronizer sync2; - sync2.moveToThread(&thread); - connect(&sync2, SIGNAL(propChanged(int)), &sync1, SLOT(setProp(int)), Qt::QueuedConnection); - connect(&sync1, SIGNAL(propChanged(int)), &thread, SLOT(quit()), Qt::QueuedConnection); - QMetaObject::invokeMethod(&sync2, "setProp", Qt::QueuedConnection , Q_ARG(int, 89)); - QTest::qWait(50); - while(!thread.wait(10)) - QTest::qWait(10); - QCOMPARE(sync2.m_prop, 89); - QCOMPARE(sync1.m_prop, 89); -} - -void tst_QThread::QTBUG15378_exitAndExec() -{ - class Thread : public QThread { - public: - QSemaphore sem1; - QSemaphore sem2; - volatile int value; - void run() { - sem1.acquire(); - value = exec(); //First entrence - sem2.release(); - value = exec(); // Second loop - } - }; - Thread thread; - thread.value = 0; - thread.start(); - thread.exit(556); - thread.sem1.release(); //should exit the first loop - thread.sem2.acquire(); - int v = thread.value; - QCOMPARE(v, 556); - - //test that the thread is running by executing queued connected signal there - Syncronizer sync1; - sync1.moveToThread(&thread); - Syncronizer sync2; - sync2.moveToThread(&thread); - connect(&sync2, SIGNAL(propChanged(int)), &sync1, SLOT(setProp(int)), Qt::QueuedConnection); - connect(&sync1, SIGNAL(propChanged(int)), &thread, SLOT(quit()), Qt::QueuedConnection); - QMetaObject::invokeMethod(&sync2, "setProp", Qt::QueuedConnection , Q_ARG(int, 89)); - QTest::qWait(50); - while(!thread.wait(10)) - QTest::qWait(10); - QCOMPARE(sync2.m_prop, 89); - QCOMPARE(sync1.m_prop, 89); -} - -void tst_QThread::connectThreadFinishedSignalToObjectDeleteLaterSlot() -{ - QThread thread; - QObject *object = new QObject; - QWeakPointer p = object; - QVERIFY(!p.isNull()); - connect(&thread, SIGNAL(started()), &thread, SLOT(quit()), Qt::DirectConnection); - connect(&thread, SIGNAL(finished()), object, SLOT(deleteLater())); - object->moveToThread(&thread); - thread.start(); - QVERIFY(thread.wait(30000)); - QVERIFY(p.isNull()); -} - -class Waiting_Thread : public QThread -{ -public: - enum { WaitTime = 800 }; - QMutex mutex; - QWaitCondition cond1; - QWaitCondition cond2; - - void run() - { - QMutexLocker locker(&mutex); - cond1.wait(&mutex); - cond2.wait(&mutex, WaitTime); - } -}; - -void tst_QThread::wait2() -{ - QElapsedTimer timer; - Waiting_Thread thread; - thread.start(); - timer.start(); - QVERIFY(!thread.wait(Waiting_Thread::WaitTime)); - qint64 elapsed = timer.elapsed(); - - QVERIFY(elapsed >= Waiting_Thread::WaitTime); - //QVERIFY(elapsed < Waiting_Thread::WaitTime * 1.4); - - timer.start(); - thread.cond1.wakeOne(); - QVERIFY(thread.wait(/*Waiting_Thread::WaitTime * 1.4*/)); - elapsed = timer.elapsed(); - QVERIFY(elapsed >= Waiting_Thread::WaitTime); - //QVERIFY(elapsed < Waiting_Thread::WaitTime * 1.4); -} - - -class SlowSlotObject : public QObject { - Q_OBJECT -public: - QMutex mutex; - QWaitCondition cond; -public slots: - void slowSlot() { - QMutexLocker locker(&mutex); - cond.wait(&mutex); - } -}; - -void tst_QThread::wait3_slowDestructor() -{ - SlowSlotObject slow; - QThread thread; - QObject::connect(&thread, SIGNAL(finished()), &slow, SLOT(slowSlot()), Qt::DirectConnection); - - enum { WaitTime = 1800 }; - QElapsedTimer timer; - - thread.start(); - thread.quit(); - //the quit function will cause the thread to finish and enter the slowSlot that is blocking - - timer.start(); - QVERIFY(!thread.wait(Waiting_Thread::WaitTime)); - qint64 elapsed = timer.elapsed(); - - QVERIFY(elapsed >= Waiting_Thread::WaitTime); - //QVERIFY(elapsed < Waiting_Thread::WaitTime * 1.4); - - slow.cond.wakeOne(); - //now the thread should finish quickly - QVERIFY(thread.wait(one_minute)); -} - -void tst_QThread::destroyFinishRace() -{ - class Thread : public QThread { void run() {} }; - for (int i = 0; i < 15; i++) { - Thread *thr = new Thread; - connect(thr, SIGNAL(finished()), thr, SLOT(deleteLater())); - QWeakPointer weak(static_cast(thr)); - thr->start(); - while (weak) { - qApp->processEvents(); - qApp->processEvents(); - qApp->processEvents(); - qApp->processEvents(); - } - } -} - -void tst_QThread::startFinishRace() -{ - class Thread : public QThread { - public: - Thread() : i (50) {} - void run() { - i--; - if (!i) disconnect(this, SIGNAL(finished()), 0, 0); - } - int i; - }; - for (int i = 0; i < 15; i++) { - Thread thr; - connect(&thr, SIGNAL(finished()), &thr, SLOT(start())); - thr.start(); - while (!thr.isFinished() || thr.i != 0) { - qApp->processEvents(); - qApp->processEvents(); - qApp->processEvents(); - qApp->processEvents(); - } - QCOMPARE(thr.i, 0); - } -} - -void tst_QThread::startAndQuitCustomEventLoop() -{ - struct Thread : QThread { - void run() { QEventLoop().exec(); } - }; - - for (int i = 0; i < 5; i++) { - Thread t; - t.start(); - t.quit(); - t.wait(); - } -} - - -QTEST_MAIN(tst_QThread) -#include "tst_qthread.moc" diff --git a/tests/auto/qthreadonce/.gitignore b/tests/auto/qthreadonce/.gitignore deleted file mode 100644 index 856177d615..0000000000 --- a/tests/auto/qthreadonce/.gitignore +++ /dev/null @@ -1 +0,0 @@ -tst_qthreadonce diff --git a/tests/auto/qthreadonce/qthreadonce.cpp b/tests/auto/qthreadonce/qthreadonce.cpp deleted file mode 100644 index b23e11b153..0000000000 --- a/tests/auto/qthreadonce/qthreadonce.cpp +++ /dev/null @@ -1,121 +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 "qplatformdefs.h" -#include "qthreadonce.h" - -#ifndef QT_NO_THREAD -#include "qmutex.h" - -Q_GLOBAL_STATIC_WITH_ARGS(QMutex, onceInitializationMutex, (QMutex::Recursive)) - -enum QOnceExtra { - MustRunCode = 0x01, - MustUnlockMutex = 0x02 -}; - -/*! - \internal - Initialize the Q_ONCE structure. - - Q_ONCE consists of two variables: - - a static POD QOnceControl::ControlVariable (it's a QBasicAtomicInt) - - an automatic QOnceControl that controls the former - - The POD is initialized to 0. - - When QOnceControl's constructor starts, it'll lock the global - initialization mutex. It'll then check if it's the first to up - the control variable and will take note. - - The QOnceControl's destructor will unlock the global - initialization mutex. -*/ -QOnceControl::QOnceControl(QBasicAtomicInt *control) -{ - d = 0; - gv = control; - // check if code has already run once - if (*gv == 2) { - // uncontended case: it has already initialized - // no waiting - return; - } - - // acquire the path - onceInitializationMutex()->lock(); - extra = MustUnlockMutex; - - if (gv->testAndSetAcquire(0, 1)) { - // path acquired, we're the first - extra |= MustRunCode; - } -} - -QOnceControl::~QOnceControl() -{ - if (mustRunCode()) - // code wasn't run! - gv->testAndSetRelease(1, 0); - else - gv->testAndSetRelease(1, 2); - if (extra & MustUnlockMutex) - onceInitializationMutex()->unlock(); -} - -/*! - \internal - Returns true if the initialization code must be run. - - Obviously, the initialization code must be run only once... -*/ -bool QOnceControl::mustRunCode() -{ - return extra & MustRunCode; -} - -void QOnceControl::done() -{ - extra &= ~MustRunCode; -} - -#endif // QT_NO_THREAD diff --git a/tests/auto/qthreadonce/qthreadonce.h b/tests/auto/qthreadonce/qthreadonce.h deleted file mode 100644 index c33625cbde..0000000000 --- a/tests/auto/qthreadonce/qthreadonce.h +++ /dev/null @@ -1,114 +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$ -** -****************************************************************************/ - - -#ifndef QTHREADONCE_H -#define QTHREADONCE_H - -#include -#include - -QT_BEGIN_HEADER - -QT_MODULE(Core) - -#ifndef QT_NO_THREAD - -class QOnceControl -{ -public: - QOnceControl(QBasicAtomicInt *); - ~QOnceControl(); - - bool mustRunCode(); - void done(); - -private: - QBasicAtomicInt *gv; - union { - qint32 extra; - void *d; - }; -}; - -#define Q_ONCE_GV_NAME2(prefix, line) prefix ## line -#define Q_ONCE_GV_NAME(prefix, line) Q_ONCE_GV_NAME2(prefix, line) -#define Q_ONCE_GV Q_ONCE_GV_NAME(_q_once_, __LINE__) - -#define Q_ONCE \ - static QBasicAtomicInt Q_ONCE_GV = Q_BASIC_ATOMIC_INITIALIZER(0); \ - if (0){} else \ - for (QOnceControl _control_(&Q_ONCE_GV); _control_.mustRunCode(); _control_.done()) - -template -class QSingleton -{ - // this is a POD-like class - struct Destructor - { - T *&pointer; - Destructor(T *&ptr) : pointer(ptr) {} - ~Destructor() { delete pointer; } - }; - -public: - T *_q_value; - QBasicAtomicInt _q_guard; - - inline T *value() - { - for (QOnceControl control(&_q_guard); control.mustRunCode(); control.done()) { - _q_value = new T(); - static Destructor cleanup(_q_value); - } - return _q_value; - } - - inline T& operator*() { return *value(); } - inline T* operator->() { return value(); } - inline operator T*() { return value(); } -}; - -#endif // QT_NO_THREAD - -QT_END_HEADER - -#endif diff --git a/tests/auto/qthreadonce/qthreadonce.pro b/tests/auto/qthreadonce/qthreadonce.pro deleted file mode 100644 index d7ef4d4c23..0000000000 --- a/tests/auto/qthreadonce/qthreadonce.pro +++ /dev/null @@ -1,13 +0,0 @@ -load(qttest_p4) -SOURCES += tst_qthreadonce.cpp -QT = core - -# Don't use gcc's threadsafe statics -# Note: some versions of gcc generate invalid code with this option... -# Some versions of gcc don't even have it, so disable it -#*-g++*:QMAKE_CXXFLAGS += -fno-threadsafe-statics - -# Temporary: -SOURCES += qthreadonce.cpp - -CONFIG += parallel_test diff --git a/tests/auto/qthreadonce/tst_qthreadonce.cpp b/tests/auto/qthreadonce/tst_qthreadonce.cpp deleted file mode 100644 index dea4e43fef..0000000000 --- a/tests/auto/qthreadonce/tst_qthreadonce.cpp +++ /dev/null @@ -1,234 +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 - -#include -#include -#include -#include -#include "qthreadonce.h" - -//TESTED_CLASS= -//TESTED_FILES=corelib/thread/qthreadonce.h corelib/thread/qthreadonce.cpp - -class tst_QThreadOnce : public QObject -{ - Q_OBJECT - -private slots: - void sameThread(); - void sameThread_data(); - void multipleThreads(); - - void nesting(); - void reentering(); - void exception(); -}; - -class SingletonObject: public QObject -{ - Q_OBJECT -public: - static int runCount; - SingletonObject() { val = 42; ++runCount; } - ~SingletonObject() { } - - QBasicAtomicInt val; -}; - -class IncrementThread: public QThread -{ -public: - static QBasicAtomicInt runCount; - static QSingleton singleton; - QSemaphore &sem1, &sem2; - int &var; - - IncrementThread(QSemaphore *psem1, QSemaphore *psem2, int *pvar, QObject *parent) - : QThread(parent), sem1(*psem1), sem2(*psem2), var(*pvar) - { start(); } - - ~IncrementThread() { wait(); } - -protected: - void run() - { - sem2.release(); - sem1.acquire(); // synchronize - - Q_ONCE { - ++var; - } - runCount.ref(); - singleton->val.ref(); - } -}; -int SingletonObject::runCount = 0; -QBasicAtomicInt IncrementThread::runCount = Q_BASIC_ATOMIC_INITIALIZER(0); -QSingleton IncrementThread::singleton; - -void tst_QThreadOnce::sameThread_data() -{ - SingletonObject::runCount = 0; - QTest::addColumn("expectedValue"); - - QTest::newRow("first") << 42; - QTest::newRow("second") << 43; -} - -void tst_QThreadOnce::sameThread() -{ - static int controlVariable = 0; - Q_ONCE { - QCOMPARE(controlVariable, 0); - ++controlVariable; - } - QCOMPARE(controlVariable, 1); - - static QSingleton s; - QTEST((int)s->val, "expectedValue"); - s->val.ref(); - - QCOMPARE(SingletonObject::runCount, 1); -} - -void tst_QThreadOnce::multipleThreads() -{ -#if defined(Q_OS_WINCE) || defined(Q_OS_VXWORKS) || defined(Q_OS_SYMBIAN) - const int NumberOfThreads = 20; -#else - const int NumberOfThreads = 100; -#endif - int controlVariable = 0; - QSemaphore sem1, sem2(NumberOfThreads); - - QObject *parent = new QObject; - for (int i = 0; i < NumberOfThreads; ++i) - new IncrementThread(&sem1, &sem2, &controlVariable, parent); - - QCOMPARE(controlVariable, 0); // nothing must have set them yet - SingletonObject::runCount = 0; - IncrementThread::runCount = 0; - - // wait for all of them to be ready - sem2.acquire(NumberOfThreads); - // unleash the threads - sem1.release(NumberOfThreads); - - // wait for all of them to terminate: - delete parent; - - QCOMPARE(controlVariable, 1); - QCOMPARE((int)IncrementThread::runCount, NumberOfThreads); - QCOMPARE(SingletonObject::runCount, 1); -} - -void tst_QThreadOnce::nesting() -{ - int variable = 0; - Q_ONCE { - Q_ONCE { - ++variable; - } - } - - QVERIFY(variable == 1); -} - -static void reentrant(int control, int &counter) -{ - Q_ONCE { - if (counter) - reentrant(--control, counter); - ++counter; - } - static QSingleton s; - s->val.ref(); -} - -void tst_QThreadOnce::reentering() -{ - const int WantedRecursions = 5; - int count = 0; - SingletonObject::runCount = 0; - reentrant(WantedRecursions, count); - - // reentrancy is undefined behavior: - QVERIFY(count == 1 || count == WantedRecursions); - QCOMPARE(SingletonObject::runCount, 1); -} - -#if !defined(QT_NO_EXCEPTIONS) -static void exception_helper(int &val) -{ - Q_ONCE { - if (val++ == 0) throw 0; - } -} -#endif - -void tst_QThreadOnce::exception() -{ -#if defined(QT_NO_EXCEPTIONS) - QSKIP("Compiled without exceptions, skipping test", SkipAll); -#else - int count = 0; - - try { - exception_helper(count); - } catch (...) { - // nothing - } - QCOMPARE(count, 1); - - try { - exception_helper(count); - } catch (...) { - QVERIFY2(false, "Exception shouldn't have been thrown..."); - } - QCOMPARE(count, 2); -#endif -} - -QTEST_MAIN(tst_QThreadOnce) -#include "tst_qthreadonce.moc" diff --git a/tests/auto/qthreadstorage/.gitignore b/tests/auto/qthreadstorage/.gitignore deleted file mode 100644 index 301968a8f6..0000000000 --- a/tests/auto/qthreadstorage/.gitignore +++ /dev/null @@ -1 +0,0 @@ -tst_qthreadstorage diff --git a/tests/auto/qthreadstorage/crashOnExit.cpp b/tests/auto/qthreadstorage/crashOnExit.cpp deleted file mode 100644 index 92efcf3b3d..0000000000 --- a/tests/auto/qthreadstorage/crashOnExit.cpp +++ /dev/null @@ -1,64 +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 - -class Class -{ -public: - ~Class() - { - // trigger creation of a new QThreadStorage, after the previous QThreadStorage from main() was destructed - static QThreadStorage threadstorage; - threadstorage.setLocalData(new int); - threadstorage.setLocalData(new int); - } -}; - -int main() -{ - // instantiate the class that will use QThreadStorage from its destructor, it's destructor will be run last - static Class instance; - // instantiate QThreadStorage, it's destructor (and the global destructors for QThreadStorages internals) will run first - static QThreadStorage threadstorage; - threadstorage.setLocalData(new int); - threadstorage.setLocalData(new int); -} diff --git a/tests/auto/qthreadstorage/crashOnExit.pro b/tests/auto/qthreadstorage/crashOnExit.pro deleted file mode 100644 index 918ef398ba..0000000000 --- a/tests/auto/qthreadstorage/crashOnExit.pro +++ /dev/null @@ -1,4 +0,0 @@ -SOURCES += crashOnExit.cpp -QT = core -CONFIG-=app_bundle -CONFIG+=console diff --git a/tests/auto/qthreadstorage/qthreadstorage.pro b/tests/auto/qthreadstorage/qthreadstorage.pro deleted file mode 100644 index 0dc8d086df..0000000000 --- a/tests/auto/qthreadstorage/qthreadstorage.pro +++ /dev/null @@ -1,5 +0,0 @@ -TEMPLATE = subdirs -SUBDIRS = \ - tst_qthreadstorage.pro \ - crashOnExit.pro -CONFIG += parallel_test diff --git a/tests/auto/qthreadstorage/tst_qthreadstorage.cpp b/tests/auto/qthreadstorage/tst_qthreadstorage.cpp deleted file mode 100644 index e123fc4fea..0000000000 --- a/tests/auto/qthreadstorage/tst_qthreadstorage.cpp +++ /dev/null @@ -1,503 +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 - -#include -#include -#include -#include -#include - -#ifdef Q_OS_UNIX -#include -#endif -#ifdef Q_OS_WIN -#ifndef Q_OS_WINCE -#include -#endif -#include -#endif - -//TESTED_CLASS= -//TESTED_FILES= - -class tst_QThreadStorage : public QObject -{ - Q_OBJECT - -public: - tst_QThreadStorage(); - -private slots: - void hasLocalData(); - void localData(); - void localData_const(); - void setLocalData(); - void autoDelete(); - void adoptedThreads(); - void ensureCleanupOrder(); - void QTBUG13877_crashOnExit(); - void QTBUG14579_leakInDestructor(); - void QTBUG14579_resetInDestructor(); - void valueBased(); -}; - -class Pointer -{ -public: - static int count; - inline Pointer() { ++count; } - inline ~Pointer() { --count; } -}; -int Pointer::count = 0; - -tst_QThreadStorage::tst_QThreadStorage() - -{ } - -void tst_QThreadStorage::hasLocalData() -{ - QThreadStorage pointers; - QVERIFY(!pointers.hasLocalData()); - pointers.setLocalData(new Pointer); - QVERIFY(pointers.hasLocalData()); - pointers.setLocalData(0); - QVERIFY(!pointers.hasLocalData()); -} - -void tst_QThreadStorage::localData() -{ - QThreadStorage pointers; - Pointer *p = new Pointer; - QVERIFY(!pointers.hasLocalData()); - pointers.setLocalData(p); - QVERIFY(pointers.hasLocalData()); - QCOMPARE(pointers.localData(), p); - pointers.setLocalData(0); - QCOMPARE(pointers.localData(), (Pointer *)0); - QVERIFY(!pointers.hasLocalData()); -} - -void tst_QThreadStorage::localData_const() -{ - QThreadStorage pointers; - const QThreadStorage &const_pointers = pointers; - Pointer *p = new Pointer; - QVERIFY(!pointers.hasLocalData()); - pointers.setLocalData(p); - QVERIFY(pointers.hasLocalData()); - QCOMPARE(const_pointers.localData(), p); - pointers.setLocalData(0); - QCOMPARE(const_pointers.localData(), (Pointer *)0); - QVERIFY(!pointers.hasLocalData()); -} - -void tst_QThreadStorage::setLocalData() -{ - QThreadStorage pointers; - QVERIFY(!pointers.hasLocalData()); - pointers.setLocalData(new Pointer); - QVERIFY(pointers.hasLocalData()); - pointers.setLocalData(0); - QVERIFY(!pointers.hasLocalData()); -} - -class Thread : public QThread -{ -public: - QThreadStorage &pointers; - - QMutex mutex; - QWaitCondition cond; - - Thread(QThreadStorage &p) - : pointers(p) - { } - - void run() - { - pointers.setLocalData(new Pointer); - - QMutexLocker locker(&mutex); - cond.wakeOne(); - cond.wait(&mutex); - } -}; - -void tst_QThreadStorage::autoDelete() -{ - QThreadStorage pointers; - QVERIFY(!pointers.hasLocalData()); - - Thread thread(pointers); - int c = Pointer::count; - { - QMutexLocker locker(&thread.mutex); - thread.start(); - thread.cond.wait(&thread.mutex); - // QCOMPARE(Pointer::count, c + 1); - thread.cond.wakeOne(); - } - thread.wait(); - QCOMPARE(Pointer::count, c); -} - -bool threadStorageOk; -void testAdoptedThreadStorageWin(void *p) -{ - QThreadStorage *pointers = reinterpret_cast *>(p); - if (pointers->hasLocalData()) { - threadStorageOk = false; - return; - } - - Pointer *pointer = new Pointer(); - pointers->setLocalData(pointer); - - if (pointers->hasLocalData() == false) { - threadStorageOk = false; - return; - } - - if (pointers->localData() != pointer) { - threadStorageOk = false; - return; - } - QObject::connect(QThread::currentThread(), SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); -} -void *testAdoptedThreadStorageUnix(void *pointers) -{ - testAdoptedThreadStorageWin(pointers); - return 0; -} -void tst_QThreadStorage::adoptedThreads() -{ - QTestEventLoop::instance(); // Make sure the instance is created in this thread. - QThreadStorage pointers; - int c = Pointer::count; - threadStorageOk = true; - { -#ifdef Q_OS_UNIX - pthread_t thread; - const int state = pthread_create(&thread, 0, testAdoptedThreadStorageUnix, &pointers); - QCOMPARE(state, 0); - pthread_join(thread, 0); -#elif defined Q_OS_WIN - HANDLE thread; -#if defined(Q_OS_WINCE) - thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)testAdoptedThreadStorageWin, &pointers, 0, NULL); -#else - thread = (HANDLE)_beginthread(testAdoptedThreadStorageWin, 0, &pointers); -#endif - QVERIFY(thread); - WaitForSingleObject(thread, INFINITE); -#endif - } - QVERIFY(threadStorageOk); - - QTestEventLoop::instance().enterLoop(2); - QVERIFY(!QTestEventLoop::instance().timeout()); - - QCOMPARE(Pointer::count, c); -} - -QBasicAtomicInt cleanupOrder = Q_BASIC_ATOMIC_INITIALIZER(0); - -class First -{ -public: - ~First() - { - order = cleanupOrder.fetchAndAddRelaxed(1); - } - static int order; -}; -int First::order = -1; - -class Second -{ -public: - ~Second() - { - order = cleanupOrder.fetchAndAddRelaxed(1); - } - static int order; -}; -int Second::order = -1; - -void tst_QThreadStorage::ensureCleanupOrder() -{ - class Thread : public QThread - { - public: - QThreadStorage &first; - QThreadStorage &second; - - Thread(QThreadStorage &first, - QThreadStorage &second) - : first(first), second(second) - { } - - void run() - { - // set in reverse order, but shouldn't matter, the data - // will be deleted in the order the thread storage objects - // were created - second.setLocalData(new Second); - first.setLocalData(new First); - } - }; - - QThreadStorage second; - QThreadStorage first; - Thread thread(first, second); - thread.start(); - thread.wait(); - - QVERIFY(First::order < Second::order); -} - -void tst_QThreadStorage::QTBUG13877_crashOnExit() -{ - QProcess process; -#ifdef Q_OS_WIN -# ifdef QT_NO_DEBUG - process.start("release/crashOnExit"); -# else - process.start("debug/crashOnExit"); -# endif -#else - process.start("./crashOnExit"); -#endif - QVERIFY(process.waitForFinished()); - QVERIFY(process.exitStatus() != QProcess::CrashExit); -} - -// S stands for thread Safe. -class SPointer -{ -public: - static QBasicAtomicInt count; - inline SPointer() { count.ref(); } - inline ~SPointer() { count.deref(); } - inline SPointer(const SPointer & /* other */) { count.ref(); } -}; -QBasicAtomicInt SPointer::count = Q_BASIC_ATOMIC_INITIALIZER(0); - -Q_GLOBAL_STATIC(QThreadStorage, QTBUG14579_pointers1) -Q_GLOBAL_STATIC(QThreadStorage, QTBUG14579_pointers2) - -class QTBUG14579_class -{ -public: - SPointer member; - inline ~QTBUG14579_class() { - QVERIFY(!QTBUG14579_pointers1()->hasLocalData()); - QVERIFY(!QTBUG14579_pointers2()->hasLocalData()); - QTBUG14579_pointers2()->setLocalData(new SPointer); - QTBUG14579_pointers1()->setLocalData(new SPointer); - QVERIFY(QTBUG14579_pointers1()->hasLocalData()); - QVERIFY(QTBUG14579_pointers2()->hasLocalData()); - } -}; - - -void tst_QThreadStorage::QTBUG14579_leakInDestructor() -{ - class Thread : public QThread - { - public: - QThreadStorage &tls; - - Thread(QThreadStorage &t) : tls(t) { } - - void run() - { - QVERIFY(!tls.hasLocalData()); - tls.setLocalData(new QTBUG14579_class); - QVERIFY(tls.hasLocalData()); - } - }; - int c = SPointer::count; - - QThreadStorage tls; - - QVERIFY(!QTBUG14579_pointers1()->hasLocalData()); - QThreadStorage tls2; //add some more tls to make sure ids are not following each other too much - QThreadStorage tls3; - QVERIFY(!tls2.hasLocalData()); - QVERIFY(!tls3.hasLocalData()); - QVERIFY(!tls.hasLocalData()); - - Thread t1(tls); - Thread t2(tls); - Thread t3(tls); - - t1.start(); - t2.start(); - t3.start(); - - QVERIFY(t1.wait()); - QVERIFY(t2.wait()); - QVERIFY(t3.wait()); - - //check all the constructed things have been destructed - QCOMPARE(int(SPointer::count), c); -} - -class QTBUG14579_reset { -public: - SPointer member; - ~QTBUG14579_reset(); -}; - -Q_GLOBAL_STATIC(QThreadStorage, QTBUG14579_resetTls) - -QTBUG14579_reset::~QTBUG14579_reset() { - //Quite stupid, but WTF::ThreadSpecific::destroy does it. - QTBUG14579_resetTls()->setLocalData(this); -} - -void tst_QThreadStorage::QTBUG14579_resetInDestructor() -{ - class Thread : public QThread - { - public: - void run() - { - QVERIFY(!QTBUG14579_resetTls()->hasLocalData()); - QTBUG14579_resetTls()->setLocalData(new QTBUG14579_reset); - QVERIFY(QTBUG14579_resetTls()->hasLocalData()); - } - }; - int c = SPointer::count; - - Thread t1; - Thread t2; - Thread t3; - t1.start(); - t2.start(); - t3.start(); - QVERIFY(t1.wait()); - QVERIFY(t2.wait()); - QVERIFY(t3.wait()); - - //check all the constructed things have been destructed - QCOMPARE(int(SPointer::count), c); -} - - -void tst_QThreadStorage::valueBased() -{ - struct Thread : QThread { - QThreadStorage &tlsSPointer; - QThreadStorage &tlsString; - QThreadStorage &tlsInt; - - int someNumber; - QString someString; - Thread(QThreadStorage &t1, QThreadStorage &t2, QThreadStorage &t3) - : tlsSPointer(t1), tlsString(t2), tlsInt(t3) { } - - void run() { - /*QVERIFY(!tlsSPointer.hasLocalData()); - QVERIFY(!tlsString.hasLocalData()); - QVERIFY(!tlsInt.hasLocalData());*/ - SPointer pointercopy = tlsSPointer.localData(); - - //Default constructed values - QVERIFY(tlsString.localData().isNull()); - QCOMPARE(tlsInt.localData(), 0); - - //setting - tlsString.setLocalData(someString); - tlsInt.setLocalData(someNumber); - - QCOMPARE(tlsString.localData(), someString); - QCOMPARE(tlsInt.localData(), someNumber); - - //changing - tlsSPointer.setLocalData(SPointer()); - tlsInt.localData() += 42; - tlsString.localData().append(QLatin1String(" world")); - - QCOMPARE(tlsString.localData(), (someString + QLatin1String(" world"))); - QCOMPARE(tlsInt.localData(), (someNumber + 42)); - - // operator= - tlsString.localData() = QString::number(someNumber); - QCOMPARE(tlsString.localData().toInt(), someNumber); - } - }; - - QThreadStorage tlsSPointer; - QThreadStorage tlsString; - QThreadStorage tlsInt; - - int c = SPointer::count; - - Thread t1(tlsSPointer, tlsString, tlsInt); - Thread t2(tlsSPointer, tlsString, tlsInt); - Thread t3(tlsSPointer, tlsString, tlsInt); - t1.someNumber = 42; - t2.someNumber = -128; - t3.someNumber = 78; - t1.someString = "hello"; - t2.someString = "trolltech"; - t3.someString = "nokia"; - - t1.start(); - t2.start(); - t3.start(); - - QVERIFY(t1.wait()); - QVERIFY(t2.wait()); - QVERIFY(t3.wait()); - - QCOMPARE(c, int(SPointer::count)); - -} - - -QTEST_MAIN(tst_QThreadStorage) -#include "tst_qthreadstorage.moc" diff --git a/tests/auto/qthreadstorage/tst_qthreadstorage.pro b/tests/auto/qthreadstorage/tst_qthreadstorage.pro deleted file mode 100644 index 3071098629..0000000000 --- a/tests/auto/qthreadstorage/tst_qthreadstorage.pro +++ /dev/null @@ -1,4 +0,0 @@ -load(qttest_p4) -SOURCES += tst_qthreadstorage.cpp -QT = core -symbian:LIBS += -llibpthread diff --git a/tests/auto/qwaitcondition/.gitignore b/tests/auto/qwaitcondition/.gitignore deleted file mode 100644 index 96531988d9..0000000000 --- a/tests/auto/qwaitcondition/.gitignore +++ /dev/null @@ -1 +0,0 @@ -tst_qwaitcondition diff --git a/tests/auto/qwaitcondition/qwaitcondition.pro b/tests/auto/qwaitcondition/qwaitcondition.pro deleted file mode 100644 index 9af0c71301..0000000000 --- a/tests/auto/qwaitcondition/qwaitcondition.pro +++ /dev/null @@ -1,6 +0,0 @@ -load(qttest_p4) -SOURCES += tst_qwaitcondition.cpp -QT = core - - -CONFIG += parallel_test diff --git a/tests/auto/qwaitcondition/tst_qwaitcondition.cpp b/tests/auto/qwaitcondition/tst_qwaitcondition.cpp deleted file mode 100644 index 6545df9189..0000000000 --- a/tests/auto/qwaitcondition/tst_qwaitcondition.cpp +++ /dev/null @@ -1,845 +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 - -#include -#include -#include -#include - -#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 -#if defined(Q_OS_SOLARIS) || ( defined(Q_OS_LINUX) && defined(QT_ARCH_ARMV6) ) -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 ? 10 : 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 ? 10 : 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 ? 10 : 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 ? 10 : 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" diff --git a/tests/auto/qwritelocker/.gitignore b/tests/auto/qwritelocker/.gitignore deleted file mode 100644 index 865739ad2c..0000000000 --- a/tests/auto/qwritelocker/.gitignore +++ /dev/null @@ -1 +0,0 @@ -tst_qwritelocker diff --git a/tests/auto/qwritelocker/qwritelocker.pro b/tests/auto/qwritelocker/qwritelocker.pro deleted file mode 100644 index 39a98aaba5..0000000000 --- a/tests/auto/qwritelocker/qwritelocker.pro +++ /dev/null @@ -1,4 +0,0 @@ -load(qttest_p4) -SOURCES += tst_qwritelocker.cpp -QT = core -CONFIG += parallel_test diff --git a/tests/auto/qwritelocker/tst_qwritelocker.cpp b/tests/auto/qwritelocker/tst_qwritelocker.cpp deleted file mode 100644 index a06431a5e1..0000000000 --- a/tests/auto/qwritelocker/tst_qwritelocker.cpp +++ /dev/null @@ -1,231 +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 - -#include -#include -#include -#include - -//TESTED_CLASS= -//TESTED_FILES= - -class tst_QWriteLockerThread : public QThread -{ -public: - QReadWriteLock lock; - QSemaphore semaphore, testSemaphore; - - void waitForTest() - { - semaphore.release(); - testSemaphore.acquire(); - } -}; - -class tst_QWriteLocker : public QObject -{ - Q_OBJECT - -public: - tst_QWriteLocker(); - ~tst_QWriteLocker(); - - tst_QWriteLockerThread *thread; - - void waitForThread() - { - thread->semaphore.acquire(); - } - void releaseThread() - { - thread->testSemaphore.release(); - } - -private slots: - void scopeTest(); - void unlockAndRelockTest(); - void lockerStateTest(); -}; - -tst_QWriteLocker::tst_QWriteLocker() -{ -} - -tst_QWriteLocker::~tst_QWriteLocker() -{ -} - -void tst_QWriteLocker::scopeTest() -{ - class ScopeTestThread : public tst_QWriteLockerThread - { - public: - void run() - { - waitForTest(); - - { - QWriteLocker locker(&lock); - waitForTest(); - } - - waitForTest(); - } - }; - - thread = new ScopeTestThread; - thread->start(); - - waitForThread(); - // lock should be unlocked before entering the scope that creates the QWriteLocker - QVERIFY(thread->lock.tryLockForWrite()); - thread->lock.unlock(); - releaseThread(); - - waitForThread(); - // lock should be locked by the QWriteLocker - QVERIFY(!thread->lock.tryLockForWrite()); - releaseThread(); - - waitForThread(); - // lock should be unlocked when the QWriteLocker goes out of scope - QVERIFY(thread->lock.tryLockForWrite()); - thread->lock.unlock(); - releaseThread(); - - QVERIFY(thread->wait()); - - delete thread; - thread = 0; -} - - -void tst_QWriteLocker::unlockAndRelockTest() -{ - class UnlockAndRelockThread : public tst_QWriteLockerThread - { - public: - void run() - { - QWriteLocker locker(&lock); - - waitForTest(); - - locker.unlock(); - - waitForTest(); - - locker.relock(); - - waitForTest(); - } - }; - - thread = new UnlockAndRelockThread; - thread->start(); - - waitForThread(); - // lock should be locked by the QWriteLocker - QVERIFY(!thread->lock.tryLockForWrite()); - releaseThread(); - - waitForThread(); - // lock has been explicitly unlocked via QWriteLocker - QVERIFY(thread->lock.tryLockForWrite()); - thread->lock.unlock(); - releaseThread(); - - waitForThread(); - // lock has been explicitly relocked via QWriteLocker - QVERIFY(!thread->lock.tryLockForWrite()); - releaseThread(); - - QVERIFY(thread->wait()); - - delete thread; - thread = 0; -} - -void tst_QWriteLocker::lockerStateTest() -{ - class LockerStateThread : public tst_QWriteLockerThread - { - public: - void run() - { - { - QWriteLocker locker(&lock); - locker.relock(); - locker.unlock(); - - waitForTest(); - } - - waitForTest(); - } - }; - - thread = new LockerStateThread; - thread->start(); - - waitForThread(); - // even though we relock() after creating the QWriteLocker, it shouldn't lock the lock more than once - QVERIFY(thread->lock.tryLockForWrite()); - thread->lock.unlock(); - releaseThread(); - - waitForThread(); - // if we call QWriteLocker::unlock(), its destructor should do nothing - QVERIFY(thread->lock.tryLockForWrite()); - thread->lock.unlock(); - releaseThread(); - - QVERIFY(thread->wait()); - - delete thread; - thread = 0; -} - -QTEST_MAIN(tst_QWriteLocker) -#include "tst_qwritelocker.moc" -- cgit v1.2.3