diff options
author | Edward Welbourne <edward.welbourne@qt.io> | 2016-07-28 13:20:41 +0200 |
---|---|---|
committer | Edward Welbourne <edward.welbourne@qt.io> | 2016-08-01 18:20:00 +0200 |
commit | f6fc34294f5691da8aa7ab8dc0452c6fa9036b67 (patch) | |
tree | 3b8fe9841f88aa81e2f8f2d57cbbca2c4736ca6f /tests/auto/other | |
parent | 6f75096afc000991111bb0fd7a7e530ce3518627 (diff) | |
parent | 0eb77c3011ee4d6bbc46dd2d40c9324e9bfcbecf (diff) |
Merge remote-tracking branch 'origin/5.7' into dev
Conflicts:
configure
5.7 now supports clang on android; but dev re-worked configure
src/gui/kernel/qevent.h
One side renamed a parameter of a constructor; the other added an
alternate constructor on the next line. Applied the rename to both
for consistency.
tests/auto/tools/moc/tst_moc.cpp
Each side added a new test at the end.
.qmake.conf
Ignored 5.7's change to MODULE_VERSION.
configure.json
No conflict noticed by git; but changes in 5.7 were needed for the
re-worked configure to accommodate 5.7's stricter handling of C++11.
Change-Id: I9cda53836a32d7bf83828212c7ea00b1de3e09d2
Diffstat (limited to 'tests/auto/other')
-rw-r--r-- | tests/auto/other/qobjectrace/tst_qobjectrace.cpp | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/tests/auto/other/qobjectrace/tst_qobjectrace.cpp b/tests/auto/other/qobjectrace/tst_qobjectrace.cpp index ae5953aa35..aa78d70716 100644 --- a/tests/auto/other/qobjectrace/tst_qobjectrace.cpp +++ b/tests/auto/other/qobjectrace/tst_qobjectrace.cpp @@ -46,6 +46,7 @@ class tst_QObjectRace: public QObject private slots: void moveToThreadRace(); void destroyRace(); + void disconnectRace(); }; class RaceObject : public QObject @@ -293,6 +294,180 @@ void tst_QObjectRace::destroyRace() delete threads[i]; } +static QAtomicInteger<unsigned> countedStructObjectsCount; +struct CountedFunctor +{ + CountedFunctor() : destroyed(false) { countedStructObjectsCount.fetchAndAddRelaxed(1); } + CountedFunctor(const CountedFunctor &) : destroyed(false) { countedStructObjectsCount.fetchAndAddRelaxed(1); } + CountedFunctor &operator=(const CountedFunctor &) { return *this; } + ~CountedFunctor() { destroyed = true; countedStructObjectsCount.fetchAndAddRelaxed(-1);} + void operator()() const {QCOMPARE(destroyed, false);} + +private: + bool destroyed; +}; + +class DisconnectRaceSenderObject : public QObject +{ + Q_OBJECT +signals: + void theSignal(); +}; + +class DisconnectRaceThread : public QThread +{ + Q_OBJECT + + DisconnectRaceSenderObject *sender; + bool emitSignal; +public: + DisconnectRaceThread(DisconnectRaceSenderObject *s, bool emitIt) + : QThread(), sender(s), emitSignal(emitIt) + { + } + + void run() + { + while (!isInterruptionRequested()) { + QMetaObject::Connection conn = connect(sender, &DisconnectRaceSenderObject::theSignal, + sender, CountedFunctor(), Qt::BlockingQueuedConnection); + if (emitSignal) + emit sender->theSignal(); + disconnect(conn); + yieldCurrentThread(); + } + } +}; + +class DeleteReceiverRaceSenderThread : public QThread +{ + Q_OBJECT + + DisconnectRaceSenderObject *sender; +public: + DeleteReceiverRaceSenderThread(DisconnectRaceSenderObject *s) + : QThread(), sender(s) + { + } + + void run() + { + while (!isInterruptionRequested()) { + emit sender->theSignal(); + yieldCurrentThread(); + } + } +}; + +class DeleteReceiverRaceReceiver : public QObject +{ + Q_OBJECT + + DisconnectRaceSenderObject *sender; + QObject *receiver; + QTimer *timer; +public: + DeleteReceiverRaceReceiver(DisconnectRaceSenderObject *s) + : QObject(), sender(s), receiver(0) + { + timer = new QTimer(this); + connect(timer, &QTimer::timeout, this, &DeleteReceiverRaceReceiver::onTimeout); + timer->start(1); + } + + void onTimeout() + { + if (receiver) + delete receiver; + receiver = new QObject; + connect(sender, &DisconnectRaceSenderObject::theSignal, receiver, CountedFunctor(), Qt::BlockingQueuedConnection); + } +}; + +class DeleteReceiverRaceReceiverThread : public QThread +{ + Q_OBJECT + + DisconnectRaceSenderObject *sender; +public: + DeleteReceiverRaceReceiverThread(DisconnectRaceSenderObject *s) + : QThread(), sender(s) + { + } + + void run() + { + QScopedPointer<DeleteReceiverRaceReceiver> receiver(new DeleteReceiverRaceReceiver(sender)); + exec(); + } +}; + +void tst_QObjectRace::disconnectRace() +{ + enum { ThreadCount = 20, TimeLimit = 3000 }; + + QCOMPARE(countedStructObjectsCount.load(), 0u); + + { + QScopedPointer<DisconnectRaceSenderObject> sender(new DisconnectRaceSenderObject()); + QScopedPointer<QThread> senderThread(new QThread()); + senderThread->start(); + sender->moveToThread(senderThread.data()); + + DisconnectRaceThread *threads[ThreadCount]; + for (int i = 0; i < ThreadCount; ++i) { + threads[i] = new DisconnectRaceThread(sender.data(), !(i % 10)); + threads[i]->start(); + } + + QTime timeLimiter; + timeLimiter.start(); + + while (timeLimiter.elapsed() < TimeLimit) + QTest::qWait(10); + + for (int i = 0; i < ThreadCount; ++i) { + threads[i]->requestInterruption(); + QVERIFY(threads[i]->wait(300)); + delete threads[i]; + } + + senderThread->quit(); + QVERIFY(senderThread->wait(300)); + } + + QCOMPARE(countedStructObjectsCount.load(), 0u); + + { + QScopedPointer<DisconnectRaceSenderObject> sender(new DisconnectRaceSenderObject()); + QScopedPointer<DeleteReceiverRaceSenderThread> senderThread(new DeleteReceiverRaceSenderThread(sender.data())); + senderThread->start(); + sender->moveToThread(senderThread.data()); + + DeleteReceiverRaceReceiverThread *threads[ThreadCount]; + for (int i = 0; i < ThreadCount; ++i) { + threads[i] = new DeleteReceiverRaceReceiverThread(sender.data()); + threads[i]->start(); + } + + QTime timeLimiter; + timeLimiter.start(); + + while (timeLimiter.elapsed() < TimeLimit) + QTest::qWait(10); + + senderThread->requestInterruption(); + QVERIFY(senderThread->wait(300)); + + for (int i = 0; i < ThreadCount; ++i) { + threads[i]->quit(); + QVERIFY(threads[i]->wait(300)); + delete threads[i]; + } + } + + QCOMPARE(countedStructObjectsCount.load(), 0u); +} QTEST_MAIN(tst_QObjectRace) #include "tst_qobjectrace.moc" |