diff options
author | Olivier Goffart <olivier.goffart@nokia.com> | 2011-03-25 18:15:39 (GMT) |
---|---|---|
committer | Olivier Goffart <olivier.goffart@nokia.com> | 2011-03-28 13:21:02 (GMT) |
commit | 0ee221b374ffef3657247be4c78e05689e04bef7 (patch) | |
tree | ed422aeaeca48be516e2a87867d0f7ca89c080a2 /src/corelib/thread | |
parent | 383da4084ae0cd8dcb9777cbfa90a55c56f7ad09 (diff) | |
download | Qt-0ee221b374ffef3657247be4c78e05689e04bef7.zip Qt-0ee221b374ffef3657247be4c78e05689e04bef7.tar.gz Qt-0ee221b374ffef3657247be4c78e05689e04bef7.tar.bz2 |
Fix the leak of QAdoptedThread and all dependent objects
if there is a QEventDispatcher in QAdoptedThread.
QAdoptedThread is supposed to be destroyed when the QThreadData is
destroyed. But QThreadData is ref-counted, and QEventDispatcher holds
a reference to it. QEventDispatcher is supposed to be destroyed
in QThreadPrivate::finish, which is supposed to be called from the
destructor of QAdoptedThread.
There is a circular dependence. We break it by calling finish in the
callback that is called when the thread is finished.
Task-number: QTBUG-17986
Reviewed-by: Brad
Diffstat (limited to 'src/corelib/thread')
-rw-r--r-- | src/corelib/thread/qthread.cpp | 6 | ||||
-rw-r--r-- | src/corelib/thread/qthread_p.h | 1 | ||||
-rw-r--r-- | src/corelib/thread/qthread_unix.cpp | 13 | ||||
-rw-r--r-- | src/corelib/thread/qthread_win.cpp | 13 |
4 files changed, 27 insertions, 6 deletions
diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp index 326f494..817e73e 100644 --- a/src/corelib/thread/qthread.cpp +++ b/src/corelib/thread/qthread.cpp @@ -78,7 +78,7 @@ QT_BEGIN_NAMESPACE QThreadData::QThreadData(int initialRefCount) : _ref(initialRefCount), thread(0), - quitNow(false), loopLevel(0), eventDispatcher(0), canWait(true) + quitNow(false), loopLevel(0), eventDispatcher(0), canWait(true), isAdopted(false) { // fprintf(stderr, "QThreadData %p created\n", this); } @@ -150,7 +150,7 @@ QAdoptedThread::QAdoptedThread(QThreadData *data) QAdoptedThread::~QAdoptedThread() { #ifndef QT_NO_THREAD - QThreadPrivate::finish(this); +// QThreadPrivate::finish(this); #endif // fprintf(stderr, "~QAdoptedThread = %p\n", this); } @@ -409,7 +409,7 @@ QThread::~QThread() wait(); locker.relock(); } - if (d->running && !d->finished) + if (d->running && !d->finished && !d->data->isAdopted) qWarning("QThread: Destroyed while thread is still running"); d->data->thread = 0; diff --git a/src/corelib/thread/qthread_p.h b/src/corelib/thread/qthread_p.h index 36e07c0..2413452 100644 --- a/src/corelib/thread/qthread_p.h +++ b/src/corelib/thread/qthread_p.h @@ -208,6 +208,7 @@ public: QPostEventList postEventList; bool canWait; QVector<void *> tls; + bool isAdopted; # ifdef Q_OS_SYMBIAN RThread symbian_thread_handle; diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index 811a193..484b455 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -148,7 +148,16 @@ static void destroy_current_thread_data(void *p) // this destructor function, so we need to set it back to the // right value... pthread_setspecific(current_thread_data_key, p); - reinterpret_cast<QThreadData *>(p)->deref(); + QThreadData *data = static_cast<QThreadData *>(p); + if (data->isAdopted) { + QThread *thread = data->thread; + Q_ASSERT(thread); + QThreadPrivate *thread_p = static_cast<QThreadPrivate *>(QObjectPrivate::get(thread)); + Q_ASSERT(!thread_p->finished); + thread_p->finish(thread); + } + data->deref(); + // ... but we must reset it to zero before returning so we aren't // called again (POSIX allows implementations to call destructor // functions repeatedly until all values are zero) @@ -251,6 +260,7 @@ QThreadData *QThreadData::current() } data->deref(); } + data->isAdopted = true; if (!QCoreApplicationPrivate::theMainThread) QCoreApplicationPrivate::theMainThread = data->thread; } @@ -376,7 +386,6 @@ void QThreadPrivate::finish(void *arg) #else QMutexLocker locker(&d->mutex); #endif - d->isInFinish = true; d->priority = QThread::InheritPriority; bool terminated = d->terminated; diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp index 6b7932b..b9c55b0 100644 --- a/src/corelib/thread/qthread_win.cpp +++ b/src/corelib/thread/qthread_win.cpp @@ -124,6 +124,7 @@ QThreadData *QThreadData::current() } threadData->deref(); } + threadData->isAdopted = true; if (!QCoreApplicationPrivate::theMainThread) { QCoreApplicationPrivate::theMainThread = threadData->thread; @@ -231,7 +232,17 @@ void qt_adopted_thread_watcher_function(void *) } else { // printf("(qt) - qt_adopted_thread_watcher_function... called\n"); const int qthreadIndex = handleIndex - 1; - QThreadData::get2(qt_adopted_qthreads.at(qthreadIndex))->deref(); + + QThreadData *data = QThreadData::get2(qt_adopted_qthreads.at(qthreadIndex)); + if (data->isAdopted) { + QThread *thread = data->thread; + Q_ASSERT(thread); + QThreadPrivate *thread_p = static_cast<QThreadPrivate *>(QObjectPrivate::get(thread)); + Q_ASSERT(!thread_p->finished); + thread_p->finish(thread); + } + data->deref(); + #if !defined(Q_OS_WINCE) || (defined(_WIN32_WCE) && (_WIN32_WCE>=0x600)) CloseHandle(qt_adopted_thread_handles.at(handleIndex)); #endif |