diff options
author | Qt Continuous Integration System <qt-info@nokia.com> | 2010-11-25 02:31:56 (GMT) |
---|---|---|
committer | Qt Continuous Integration System <qt-info@nokia.com> | 2010-11-25 02:31:56 (GMT) |
commit | e868e896054061f35b38dd3e7b688d932be40a55 (patch) | |
tree | 75eb8d69df9bd07f93dd1a75dd7d014486b11bd6 /tests | |
parent | 7f2877acd0183092c31b74ed0de8d54fb3c49caf (diff) | |
parent | 25c9b6ed488b1446cbdd38186992957264596314 (diff) | |
download | Qt-e868e896054061f35b38dd3e7b688d932be40a55.zip Qt-e868e896054061f35b38dd3e7b688d932be40a55.tar.gz Qt-e868e896054061f35b38dd3e7b688d932be40a55.tar.bz2 |
Merge branch 'master' of scm.dev.nokia.troll.no:qt/oslo-staging-2 into master-integration
* 'master' of scm.dev.nokia.troll.no:qt/oslo-staging-2:
QThread: fix a race condition when destroying or restarting thread from finished()
QThreadStorage: fix crash if thread local destructor reset himself
Add WA_MacNoShadow widget attribute
Doc: Fixing typo
Fix compilation on symbian
Fix a namespace error and some warnings found by clang
optimize ligatureHelper by using qBinaryFind instead of the for loop
QFileSystemWatcher: Do not require QApplication in the destructor.
Do not define METHOD if QT_NO_KEYWORD is defined.
QThreadPrivate::finish should not keep mutex locked when calling signals
Make QThreadStorage supports value type and not only pointers.
QThreadStorage: fix memory leak if thread storage are added while destroying
Compile fix.
Fix some warnings on Mac
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/qfilesystemwatcher/tst_qfilesystemwatcher.cpp | 20 | ||||
-rw-r--r-- | tests/auto/qthread/tst_qthread.cpp | 123 | ||||
-rw-r--r-- | tests/auto/qthreadstorage/tst_qthreadstorage.cpp | 190 |
3 files changed, 333 insertions, 0 deletions
diff --git a/tests/auto/qfilesystemwatcher/tst_qfilesystemwatcher.cpp b/tests/auto/qfilesystemwatcher/tst_qfilesystemwatcher.cpp index a26e34d..fd898ee 100644 --- a/tests/auto/qfilesystemwatcher/tst_qfilesystemwatcher.cpp +++ b/tests/auto/qfilesystemwatcher/tst_qfilesystemwatcher.cpp @@ -82,6 +82,8 @@ private slots: void removeFileAndUnWatch(); void cleanup(); + + void QTBUG15255_deadlock(); private: QStringList do_force_engines; bool do_force_native; @@ -557,5 +559,23 @@ void tst_QFileSystemWatcher::removeFileAndUnWatch() watcher.addPath(filename); } +class SomeSingleton : public QObject +{ +public: + SomeSingleton() : mFsWatcher(new QFileSystemWatcher(this)) { mFsWatcher->addPath(QLatin1String("/usr/lib"));} + void bla() const {} + QFileSystemWatcher* mFsWatcher; +}; + +Q_GLOBAL_STATIC(SomeSingleton, someSingleton) + +void tst_QFileSystemWatcher::QTBUG15255_deadlock() +{ + someSingleton()->bla(); + //the test must still finish + QTest::qWait(30); +} + + QTEST_MAIN(tst_QFileSystemWatcher) #include "tst_qfilesystemwatcher.moc" diff --git a/tests/auto/qthread/tst_qthread.cpp b/tests/auto/qthread/tst_qthread.cpp index f290a2b..01f080f 100644 --- a/tests/auto/qthread/tst_qthread.cpp +++ b/tests/auto/qthread/tst_qthread.cpp @@ -107,6 +107,10 @@ private slots: void QTBUG13810_exitAndStart(); void connectThreadFinishedSignalToObjectDeleteLaterSlot(); + void wait2(); + void wait3_slowDestructor(); + void destroyFinishRace(); + void startFinishRace(); void stressTest(); }; @@ -976,6 +980,7 @@ void tst_QThread::QTBUG13810_exitAndStart() QCOMPARE(sync1.m_prop, 89); } + void tst_QThread::connectThreadFinishedSignalToObjectDeleteLaterSlot() { QThread thread; @@ -990,5 +995,123 @@ void tst_QThread::connectThreadFinishedSignalToObjectDeleteLaterSlot() 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<QThread> weak(static_cast<QThread*>(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); + } +} + + + QTEST_MAIN(tst_QThread) #include "tst_qthread.moc" diff --git a/tests/auto/qthreadstorage/tst_qthreadstorage.cpp b/tests/auto/qthreadstorage/tst_qthreadstorage.cpp index ed86165..0237dac 100644 --- a/tests/auto/qthreadstorage/tst_qthreadstorage.cpp +++ b/tests/auto/qthreadstorage/tst_qthreadstorage.cpp @@ -77,6 +77,9 @@ private slots: void adoptedThreads(); void ensureCleanupOrder(); void QTBUG13877_crashOnExit(); + void QTBUG14579_leakInDestructor(); + void QTBUG14579_resetInDestructor(); + void valueBased(); }; class Pointer @@ -310,5 +313,192 @@ void tst_QThreadStorage::QTBUG13877_crashOnExit() 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<SPointer *>, QTBUG14579_pointers1) +Q_GLOBAL_STATIC(QThreadStorage<SPointer *>, 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<QTBUG14579_class *> &tls; + + Thread(QThreadStorage<QTBUG14579_class *> &t) : tls(t) { } + + void run() + { + QVERIFY(!tls.hasLocalData()); + tls.setLocalData(new QTBUG14579_class); + QVERIFY(tls.hasLocalData()); + } + }; + int c = SPointer::count; + + QThreadStorage<QTBUG14579_class *> tls; + + QVERIFY(!QTBUG14579_pointers1()->hasLocalData()); + QThreadStorage<int *> tls2; //add some more tls to make sure ids are not following each other too much + QThreadStorage<int *> 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; +Q_GLOBAL_STATIC(QThreadStorage<QTBUG14579_reset *>, QTBUG14579_resetTls) + +class QTBUG14579_reset { +public: + SPointer member; + ~QTBUG14579_reset() { + //Quite stupid, but WTF::ThreadSpecific<T>::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<SPointer> &tlsSPointer; + QThreadStorage<QString> &tlsString; + QThreadStorage<int> &tlsInt; + + int someNumber; + QString someString; + Thread(QThreadStorage<SPointer> &t1, QThreadStorage<QString> &t2, QThreadStorage<int> &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<SPointer> tlsSPointer; + QThreadStorage<QString> tlsString; + QThreadStorage<int> 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" |