From f4b2f4fa4a8b6ffecb2fcdb46b91f12d3820c5ac Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Sat, 20 Nov 2010 16:27:26 +0100 Subject: Fix some warnings on Mac Reviewed-by: Fabien Freling --- src/gui/dialogs/qcolordialog_mac.mm | 2 +- src/gui/image/qnativeimage.cpp | 2 ++ src/gui/kernel/qcocoaapplicationdelegate_mac.mm | 1 + src/gui/styles/qstyle.cpp | 2 ++ src/gui/styles/qstyleoption.cpp | 4 ++++ src/gui/widgets/qcocoamenu_mac.mm | 1 + 6 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/gui/dialogs/qcolordialog_mac.mm b/src/gui/dialogs/qcolordialog_mac.mm index 82cfa24..f2e4d53 100644 --- a/src/gui/dialogs/qcolordialog_mac.mm +++ b/src/gui/dialogs/qcolordialog_mac.mm @@ -439,7 +439,7 @@ void QColorDialogPrivate::openCocoaColorPanel(const QColor &initial, priv:this]; [colorPanel setDelegate:static_cast(delegate)]; } - [delegate setResultSet:false]; + [static_cast(delegate) setResultSet:NO]; setCocoaPanelColor(initial); [static_cast(delegate) showColorPanel]; } diff --git a/src/gui/image/qnativeimage.cpp b/src/gui/image/qnativeimage.cpp index 0f7872e..c154740 100644 --- a/src/gui/image/qnativeimage.cpp +++ b/src/gui/image/qnativeimage.cpp @@ -256,6 +256,8 @@ QNativeImage::QNativeImage(int width, int height, QImage::Format format, bool /* case QImage::Format_ARGB4444_Premultiplied: cgflags = kCGImageAlphaPremultipliedFirst; break; + default: + break; } #ifdef kCGBitmapByteOrder32Host //only needed because CGImage.h added symbols in the minor version diff --git a/src/gui/kernel/qcocoaapplicationdelegate_mac.mm b/src/gui/kernel/qcocoaapplicationdelegate_mac.mm index 9b07d64..383f05e 100644 --- a/src/gui/kernel/qcocoaapplicationdelegate_mac.mm +++ b/src/gui/kernel/qcocoaapplicationdelegate_mac.mm @@ -78,6 +78,7 @@ #import #import +#import #include #include #include diff --git a/src/gui/styles/qstyle.cpp b/src/gui/styles/qstyle.cpp index 3ebfab2..be8f794 100644 --- a/src/gui/styles/qstyle.cpp +++ b/src/gui/styles/qstyle.cpp @@ -2456,6 +2456,8 @@ QDebug operator<<(QDebug debug, QStyle::State state) qSort(states); debug << states.join(QLatin1String(" | ")); debug << ')'; +#else + Q_UNUSED(state); #endif return debug; } diff --git a/src/gui/styles/qstyleoption.cpp b/src/gui/styles/qstyleoption.cpp index 4780edf..05ca793 100644 --- a/src/gui/styles/qstyleoption.cpp +++ b/src/gui/styles/qstyleoption.cpp @@ -5483,6 +5483,8 @@ QDebug operator<<(QDebug debug, const QStyleOption::OptionType &optionType) case QStyleOption::SO_GraphicsItem: debug << "SO_GraphicsItem"; break; } +#else + Q_UNUSED(optionType); #endif return debug; } @@ -5496,6 +5498,8 @@ QDebug operator<<(QDebug debug, const QStyleOption &option) debug << ',' << option.state; debug << ',' << option.rect; debug << ')'; +#else + Q_UNUSED(option); #endif return debug; } diff --git a/src/gui/widgets/qcocoamenu_mac.mm b/src/gui/widgets/qcocoamenu_mac.mm index b670186..a22148e 100644 --- a/src/gui/widgets/qcocoamenu_mac.mm +++ b/src/gui/widgets/qcocoamenu_mac.mm @@ -44,6 +44,7 @@ #ifdef QT_MAC_USE_COCOA #import #import +#import #include #include #include -- cgit v0.12 From fb026f81bfe64be232a819fdac5b8dbcdd4fae4d Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Mon, 22 Nov 2010 13:58:08 +0100 Subject: Compile fix. --- src/corelib/tools/qstring.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index bb496c6..c30af64 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -714,7 +714,7 @@ const QString::Null QString::null = { }; formats, the \e precision represents the maximum number of significant digits (trailing zeroes are omitted). - \section1 More Efficient String Construction + \section1 More Efficient String Construction Using the QString \c{'+'} operator, it is easy to construct a complex string from multiple substrings. You will often write code @@ -924,7 +924,7 @@ int QString::grow(int size) /*! \since 4.2 - Returns a copy of the \a string, where the encoding of \a string depends on + Returns a copy of the \a string, where the encoding of \a string depends on the size of wchar. If wchar is 4 bytes, the \a string is interpreted as ucs-4, if wchar is 2 bytes it is interpreted as ucs-2. @@ -3606,7 +3606,7 @@ static QByteArray toLatin1_helper(const QChar *data, int length) } length = length % 16; } -#elif QT_ALWAYS_HAVE_NEON +#elif defined(QT_ALWAYS_HAVE_NEON) // Refer to the documentation of the SSE2 implementation // this use eactly the same method as for SSE except: // 1) neon has unsigned comparison -- cgit v0.12 From ed8f3b6c98f1b305f0d183bc70c5f810a9c45ef2 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Thu, 4 Nov 2010 13:37:48 +0100 Subject: QThreadStorage: fix memory leak if thread storage are added while destroying The destructor(q) function could use itself and create new QThreadStorage. This might be the case for example, when using qDebug in a destructor. Task-number: QTBUG-14579 Reveiwed-by: Joao Reviewed-by: Brad --- src/corelib/thread/qthreadstorage.cpp | 7 ++- tests/auto/qthreadstorage/tst_qthreadstorage.cpp | 72 ++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/src/corelib/thread/qthreadstorage.cpp b/src/corelib/thread/qthreadstorage.cpp index 2fc04f5..2222427 100644 --- a/src/corelib/thread/qthreadstorage.cpp +++ b/src/corelib/thread/qthreadstorage.cpp @@ -178,11 +178,12 @@ void QThreadStorageData::finish(void **p) return; // nothing to do DEBUG_MSG("QThreadStorageData: Destroying storage for thread %p", QThread::currentThread()); - - for(int i = tls->size() - 1; i >= 0; i--) { - void *&value = (*tls)[i]; + while (!tls->isEmpty()) { + void *&value = tls->last(); void *q = value; value = 0; + int i = tls->size() - 1; + tls->resize(i); if (!q) { // data already deleted diff --git a/tests/auto/qthreadstorage/tst_qthreadstorage.cpp b/tests/auto/qthreadstorage/tst_qthreadstorage.cpp index ed86165..54f8bd9 100644 --- a/tests/auto/qthreadstorage/tst_qthreadstorage.cpp +++ b/tests/auto/qthreadstorage/tst_qthreadstorage.cpp @@ -77,6 +77,7 @@ private slots: void adoptedThreads(); void ensureCleanupOrder(); void QTBUG13877_crashOnExit(); + void QTBUG14579_leakInDestructor(); }; class Pointer @@ -310,5 +311,76 @@ 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(); } +}; +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); +} + QTEST_MAIN(tst_QThreadStorage) #include "tst_qthreadstorage.moc" -- cgit v0.12 From 5e13c65b7083ba6a28820a82f2fa19ca8c1569b0 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Thu, 4 Nov 2010 17:23:04 +0100 Subject: Make QThreadStorage supports value type and not only pointers. Handling value type is much more natural than handling pointer. It was not possible to use normal type in QThreadStorage previously (probably because some compiler would not support it?) This should ease a lot the use of QThreadStorage and make it more intuitive. The only problem was the QThreadStorage::deleteData() that would not compile for nonn-pointer. This is now fixed Also updated the documentation. Reviewed-by: Joao Reviewed-by: Brad Task-number: QTBUG-15033 --- doc/src/snippets/threads/threads.cpp | 9 +-- src/corelib/thread/qthreadstorage.cpp | 47 +++++---------- src/corelib/thread/qthreadstorage.h | 13 ++++- tests/auto/qthreadstorage/tst_qthreadstorage.cpp | 74 ++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 39 deletions(-) diff --git a/doc/src/snippets/threads/threads.cpp b/doc/src/snippets/threads/threads.cpp index d8d1270..d16c398 100644 --- a/doc/src/snippets/threads/threads.cpp +++ b/doc/src/snippets/threads/threads.cpp @@ -93,15 +93,12 @@ private: typedef int SomeClass; //! [7] -QThreadStorage *> caches; +QThreadStorage > caches; void cacheObject(const QString &key, SomeClass *object) //! [7] //! [8] { - if (!caches.hasLocalData()) - caches.setLocalData(new QCache); - - caches.localData()->insert(key, object); + caches.localData().insert(key, object); } void removeFromCache(const QString &key) @@ -110,7 +107,7 @@ void removeFromCache(const QString &key) if (!caches.hasLocalData()) return; - caches.localData()->remove(key); + caches.localData().remove(key); } //! [9] diff --git a/src/corelib/thread/qthreadstorage.cpp b/src/corelib/thread/qthreadstorage.cpp index 2222427..8df6f39 100644 --- a/src/corelib/thread/qthreadstorage.cpp +++ b/src/corelib/thread/qthreadstorage.cpp @@ -216,19 +216,18 @@ void QThreadStorageData::finish(void **p) QThreadStorage is a template class that provides per-thread data storage. - \e{Note that due to compiler limitations, QThreadStorage can only - store pointers.} - The setLocalData() function stores a single thread-specific value for the calling thread. The data can be accessed later using - localData(). QThreadStorage takes ownership of the data (which - must be created on the heap with \c new) and deletes it when the - thread exits, either normally or via termination. + localData(). The hasLocalData() function allows the programmer to determine if data has previously been set using the setLocalData() function. This is also useful for lazy initializiation. + If T is a pointer type, QThreadStorage takes ownership of the data + (which must be created on the heap with \c new) and deletes it when + the thread exits, either normally or via termination. + For example, the following code uses QThreadStorage to store a single cache for each thread that calls the cacheObject() and removeFromCache() functions. The cache is automatically @@ -242,9 +241,6 @@ void QThreadStorageData::finish(void **p) \list - \o As noted above, QThreadStorage can only store pointers due to - compiler limitations. - \o The QThreadStorage destructor does not delete per-thread data. QThreadStorage only deletes per-thread data when the thread exits or when setLocalData() is called multiple times. @@ -280,8 +276,11 @@ void QThreadStorageData::finish(void **p) /*! \fn bool QThreadStorage::hasLocalData() const - Returns true if the calling thread has non-zero data available; - otherwise returns false. + If T is a pointer type, returns true if the calling thread has + non-zero data available. + + If T is a value type, returns wether the data has already been + constructed by calling setLocalData or localData. \sa localData() */ @@ -292,10 +291,8 @@ void QThreadStorageData::finish(void **p) Returns a reference to the data that was set by the calling thread. - Note: QThreadStorage can only store pointers. This function - returns a reference to the pointer that was set by the calling - thread. The value of this reference is 0 if no data was set by - the calling thread, + If no data has been set, this will create a default constructed + instance of type T. \sa hasLocalData() */ @@ -306,10 +303,6 @@ void QThreadStorageData::finish(void **p) Returns a copy of the data that was set by the calling thread. - Note: QThreadStorage can only store pointers. This function - returns a pointer to the data that was set by the calling thread. - If no data was set by the calling thread, this function returns 0. - \sa hasLocalData() */ @@ -319,19 +312,9 @@ void QThreadStorageData::finish(void **p) Sets the local data for the calling thread to \a data. It can be accessed later using the localData() functions. - If \a data is 0, this function deletes the previous data (if - any) and returns immediately. - - If \a data is non-zero, QThreadStorage takes ownership of the \a - data and deletes it automatically either when the thread exits - (either normally or via termination) or when setLocalData() is - called again. - - Note: QThreadStorage can only store pointers. The \a data - argument must be either a pointer to an object created on the heap - (i.e. using \c new) or 0. You should not delete \a data - yourself; QThreadStorage takes ownership and will delete the \a - data itself. + If T is a pointer type, QThreadStorage takes ownership of the data + and deletes it automatically either when the thread exits (either + normally or via termination) or when setLocalData() is called again. \sa localData(), hasLocalData() */ diff --git a/src/corelib/thread/qthreadstorage.h b/src/corelib/thread/qthreadstorage.h index 6264674..475d20d 100644 --- a/src/corelib/thread/qthreadstorage.h +++ b/src/corelib/thread/qthreadstorage.h @@ -91,6 +91,11 @@ inline void qThreadStorage_setLocalData(QThreadStorageData &d, T **t) { (void) d.set(*t); } +template +inline +void qThreadStorage_deleteData(void *d, T **) +{ delete static_cast(d); } + // value-based specialization template inline @@ -114,6 +119,12 @@ inline void qThreadStorage_setLocalData(QThreadStorageData &d, T *t) { (void) d.set(new T(*t)); } +template +inline +void qThreadStorage_deleteData(void *d, T *) +{ delete static_cast(d); } + + // MOC_SKIP_END #endif @@ -126,7 +137,7 @@ private: Q_DISABLE_COPY(QThreadStorage) static inline void deleteData(void *x) - { delete static_cast(x); } + { qThreadStorage_deleteData(x, reinterpret_cast(0)); } public: inline QThreadStorage() : d(deleteData) { } diff --git a/tests/auto/qthreadstorage/tst_qthreadstorage.cpp b/tests/auto/qthreadstorage/tst_qthreadstorage.cpp index 54f8bd9..90e0311 100644 --- a/tests/auto/qthreadstorage/tst_qthreadstorage.cpp +++ b/tests/auto/qthreadstorage/tst_qthreadstorage.cpp @@ -78,6 +78,7 @@ private slots: void ensureCleanupOrder(); void QTBUG13877_crashOnExit(); void QTBUG14579_leakInDestructor(); + void valueBased(); }; class Pointer @@ -318,6 +319,7 @@ 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); @@ -382,5 +384,77 @@ void tst_QThreadStorage::QTBUG14579_leakInDestructor() 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" -- cgit v0.12 From a43583e0221311b7fe666726ab668e41c5e4bba2 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Thu, 4 Nov 2010 15:52:12 +0100 Subject: QThreadPrivate::finish should not keep mutex locked when calling signals This fix the deadlock shown in the new test wait3_slowDestructor Add a test for QThread::wait(timeout) Task-number: QTBUG-15030 Reviewed-by: Joao Reviewed-by: Brad --- src/corelib/thread/qthread_unix.cpp | 36 +++++++++-------- src/corelib/thread/qthread_win.cpp | 29 ++++++++------ tests/auto/qthread/tst_qthread.cpp | 77 +++++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+), 28 deletions(-) diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index f508c0a..f409256 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -333,40 +333,44 @@ void QThreadPrivate::finish(void *arg) { QThread *thr = reinterpret_cast(arg); QThreadPrivate *d = thr->d_func(); + #ifdef Q_OS_SYMBIAN - if (lockAnyway) + QMutexLocker locker(lockAnyway ? &d->mutex : 0); +#else + QMutexLocker locker(&d->mutex); #endif - d->mutex.lock(); + d->priority = QThread::InheritPriority; - d->running = false; - d->finished = true; - if (d->terminated) + bool terminated = d->terminated; + void *data = &d->data->tls; + locker.unlock(); + if (terminated) emit thr->terminated(); - d->terminated = false; emit thr->finished(); QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + QThreadStorageData::finish((void **)data); + locker.relock(); + d->terminated = false; - if (d->data->eventDispatcher) { - d->data->eventDispatcher->closingDown(); - QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher; + QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher; + if (eventDispatcher) { d->data->eventDispatcher = 0; + locker.unlock(); + eventDispatcher->closingDown(); delete eventDispatcher; + locker.relock(); } - void *data = &d->data->tls; - QThreadStorageData::finish((void **)data); - d->thread_id = 0; #ifdef Q_OS_SYMBIAN if (closeNativeHandle) d->data->symbian_thread_handle.Close(); #endif + d->running = false; + d->finished = true; + d->thread_done.wakeAll(); -#ifdef Q_OS_SYMBIAN - if (lockAnyway) -#endif - d->mutex.unlock(); } diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp index 4a967ed..3706da8 100644 --- a/src/corelib/thread/qthread_win.cpp +++ b/src/corelib/thread/qthread_win.cpp @@ -323,25 +323,32 @@ void QThreadPrivate::finish(void *arg, bool lockAnyway) QThread *thr = reinterpret_cast(arg); QThreadPrivate *d = thr->d_func(); - if (lockAnyway) - d->mutex.lock(); + QMutexLocker locker(lockAnyway ? &d->mutex : 0); d->priority = QThread::InheritPriority; - d->running = false; - d->finished = true; - if (d->terminated) + bool terminated = d->terminated; + void **tls_data = reinterpret_cast(&d->data->tls); + locker.unlock(); + if (terminated) emit thr->terminated(); - d->terminated = false; emit thr->finished(); QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + QThreadStorageData::finish(tls_data); + locker.relock(); + + d->terminated = false; - if (d->data->eventDispatcher) { - d->data->eventDispatcher->closingDown(); - QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher; + QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher; + if (eventDispatcher) { d->data->eventDispatcher = 0; + locker.unlock(); + eventDispatcher->closingDown(); delete eventDispatcher; + locker.relock(); } - QThreadStorageData::finish(reinterpret_cast(&d->data->tls)); + d->running = false; + d->finished = true; + if (!d->waiters) { CloseHandle(d->handle); @@ -350,8 +357,6 @@ void QThreadPrivate::finish(void *arg, bool lockAnyway) d->id = 0; - if (lockAnyway) - d->mutex.unlock(); } /************************************************************************** diff --git a/tests/auto/qthread/tst_qthread.cpp b/tests/auto/qthread/tst_qthread.cpp index f290a2b..49c3576 100644 --- a/tests/auto/qthread/tst_qthread.cpp +++ b/tests/auto/qthread/tst_qthread.cpp @@ -107,6 +107,8 @@ private slots: void QTBUG13810_exitAndStart(); void connectThreadFinishedSignalToObjectDeleteLaterSlot(); + void wait2(); + void wait3_slowDestructor(); void stressTest(); }; @@ -976,6 +978,7 @@ void tst_QThread::QTBUG13810_exitAndStart() QCOMPARE(sync1.m_prop, 89); } + void tst_QThread::connectThreadFinishedSignalToObjectDeleteLaterSlot() { QThread thread; @@ -990,5 +993,79 @@ 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 shoud finish quickly + QVERIFY(thread.wait(one_minute)); +} + QTEST_MAIN(tst_QThread) #include "tst_qthread.moc" -- cgit v0.12 From 39f2dc87dbec95934cb4596c46f8b17994048de2 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Fri, 5 Nov 2010 10:27:50 +0100 Subject: Do not define METHOD if QT_NO_KEYWORD is defined. METHOD is never used in Qt, and is conflicting with other libraries. Task-number: QTBUG-14514 Reviewed-by: Joao Reviewed-by: Brad --- src/corelib/kernel/qobjectdefs.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h index db46ba5..b4e4aa5 100644 --- a/src/corelib/kernel/qobjectdefs.h +++ b/src/corelib/kernel/qobjectdefs.h @@ -215,11 +215,15 @@ Q_CORE_EXPORT const char *qFlagLocation(const char *method); #define QTOSTRING(s) QTOSTRING_HELPER(s) #ifndef QT_NO_DEBUG # define QLOCATION "\0"__FILE__":"QTOSTRING(__LINE__) -# define METHOD(a) qFlagLocation("0"#a QLOCATION) +# ifndef QT_NO_KEYWORDS +# define METHOD(a) qFlagLocation("0"#a QLOCATION) +# endif # define SLOT(a) qFlagLocation("1"#a QLOCATION) # define SIGNAL(a) qFlagLocation("2"#a QLOCATION) #else -# define METHOD(a) "0"#a +# ifndef QT_NO_KEYWORDS +# define METHOD(a) "0"#a +# endif # define SLOT(a) "1"#a # define SIGNAL(a) "2"#a #endif -- cgit v0.12 From 9036fe3d2ffabde9b49ced0ba8835d8403b11ff4 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Fri, 12 Nov 2010 10:49:13 +0100 Subject: QFileSystemWatcher: Do not require QApplication in the destructor. QThread::quit() is threadsafe, and can safely (and should) be called from the parent thread. Using invokeMethod requires an instance of QCoreApplication. There is no reason we should depend on that. Task-number: QTBUG-15255 Task-number: QT-3305 Reviewed-by: Denis Reviewed-by: Brad --- src/corelib/io/qfilesystemwatcher.cpp | 7 +------ src/corelib/io/qfilesystemwatcher_inotify.cpp | 2 +- src/corelib/io/qfilesystemwatcher_symbian.cpp | 2 +- .../qfilesystemwatcher/tst_qfilesystemwatcher.cpp | 20 ++++++++++++++++++++ 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/corelib/io/qfilesystemwatcher.cpp b/src/corelib/io/qfilesystemwatcher.cpp index 18c3c9f..3a7d795 100644 --- a/src/corelib/io/qfilesystemwatcher.cpp +++ b/src/corelib/io/qfilesystemwatcher.cpp @@ -198,7 +198,7 @@ QStringList QPollingFileSystemWatcherEngine::removePaths(const QStringList &path void QPollingFileSystemWatcherEngine::stop() { - QMetaObject::invokeMethod(this, "quit"); + quit(); } void QPollingFileSystemWatcherEngine::timeout() @@ -426,11 +426,6 @@ QFileSystemWatcher::QFileSystemWatcher(const QStringList &paths, QObject *parent /*! Destroys the file system watcher. - - \note To avoid deadlocks on shutdown, all instances of QFileSystemWatcher - need to be destroyed before QCoreApplication. Note that passing - QCoreApplication::instance() as the parent object when creating - QFileSystemWatcher is not sufficient. */ QFileSystemWatcher::~QFileSystemWatcher() { diff --git a/src/corelib/io/qfilesystemwatcher_inotify.cpp b/src/corelib/io/qfilesystemwatcher_inotify.cpp index dc18ae7..939eb73 100644 --- a/src/corelib/io/qfilesystemwatcher_inotify.cpp +++ b/src/corelib/io/qfilesystemwatcher_inotify.cpp @@ -340,7 +340,7 @@ QStringList QInotifyFileSystemWatcherEngine::removePaths(const QStringList &path void QInotifyFileSystemWatcherEngine::stop() { - QMetaObject::invokeMethod(this, "quit"); + quit(); } void QInotifyFileSystemWatcherEngine::readFromInotify() diff --git a/src/corelib/io/qfilesystemwatcher_symbian.cpp b/src/corelib/io/qfilesystemwatcher_symbian.cpp index 6136742..ee66c36 100644 --- a/src/corelib/io/qfilesystemwatcher_symbian.cpp +++ b/src/corelib/io/qfilesystemwatcher_symbian.cpp @@ -215,7 +215,7 @@ void QSymbianFileSystemWatcherEngine::emitPathChanged(QNotifyChangeEvent *e) void QSymbianFileSystemWatcherEngine::stop() { - QMetaObject::invokeMethod(this, "quit"); + quit(); wait(); } 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" -- cgit v0.12 From 360f596183969a4c690c77df08d94101428c97c0 Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Mon, 22 Nov 2010 15:20:42 +0100 Subject: optimize ligatureHelper by using qBinaryFind instead of the for loop Merge-request: 890 Reviewed-by: Olivier Goffart --- src/corelib/tools/qchar.cpp | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/corelib/tools/qchar.cpp b/src/corelib/tools/qchar.cpp index bb777cd..43b1552 100644 --- a/src/corelib/tools/qchar.cpp +++ b/src/corelib/tools/qchar.cpp @@ -48,11 +48,11 @@ # undef QT_NO_CAST_TO_ASCII #endif #include "qchar.h" + #include "qdatastream.h" #include "qtextcodec.h" #include "qunicodetables_p.h" - #include "qunicodetables.cpp" QT_BEGIN_NAMESPACE @@ -1489,6 +1489,16 @@ static void decomposeHelper(QString *str, bool canonical, QChar::UnicodeVersion } +struct UCS2Pair { + ushort u1; + ushort u2; +}; + +static inline bool operator<(ushort u1, const UCS2Pair &ligature) +{ return u1 < ligature.u1; } +static inline bool operator<(const UCS2Pair &ligature, ushort u1) +{ return ligature.u1 < u1; } + static ushort ligatureHelper(ushort u1, ushort u2) { // hangul L-V pair @@ -1511,12 +1521,14 @@ static ushort ligatureHelper(ushort u1, ushort u2) if (index == 0xffff) return 0; const unsigned short *ligatures = uc_ligature_map+index; - ushort length = *ligatures; - ++ligatures; - // ### use bsearch - for (uint i = 0; i < length; ++i) - if (ligatures[2*i] == u1) - return ligatures[2*i+1]; + ushort length = *ligatures++; + { + const UCS2Pair *data = reinterpret_cast(ligatures); + const UCS2Pair *r = qBinaryFind(data, data + length, u1); + if (r != data + length) + return r->u2; + } + return 0; } -- cgit v0.12