summaryrefslogtreecommitdiffstats
path: root/src/corelib/thread
diff options
context:
space:
mode:
authorOlivier Goffart <olivier.goffart@nokia.com>2011-03-25 18:15:39 (GMT)
committerOlivier Goffart <olivier.goffart@nokia.com>2011-03-28 13:21:02 (GMT)
commit0ee221b374ffef3657247be4c78e05689e04bef7 (patch)
treeed422aeaeca48be516e2a87867d0f7ca89c080a2 /src/corelib/thread
parent383da4084ae0cd8dcb9777cbfa90a55c56f7ad09 (diff)
downloadQt-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.cpp6
-rw-r--r--src/corelib/thread/qthread_p.h1
-rw-r--r--src/corelib/thread/qthread_unix.cpp13
-rw-r--r--src/corelib/thread/qthread_win.cpp13
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