summaryrefslogtreecommitdiffstats
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
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
-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
-rw-r--r--tests/auto/qthread/tst_qthread.cpp17
5 files changed, 44 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
diff --git a/tests/auto/qthread/tst_qthread.cpp b/tests/auto/qthread/tst_qthread.cpp
index c69052e..12709db 100644
--- a/tests/auto/qthread/tst_qthread.cpp
+++ b/tests/auto/qthread/tst_qthread.cpp
@@ -103,6 +103,7 @@ private slots:
void adoptedThreadExit();
void adoptedThreadExec();
void adoptedThreadFinished();
+ void adoptedThreadExecFinished();
void adoptMultipleThreads();
void QTBUG13810_exitAndStart();
@@ -895,6 +896,21 @@ void tst_QThread::adoptedThreadFinished()
QVERIFY(!QTestEventLoop::instance().timeout());
}
+void tst_QThread::adoptedThreadExecFinished()
+{
+ NativeThreadWrapper nativeThread;
+ nativeThread.setWaitForStop();
+ nativeThread.startAndWait(adoptedThreadExecFunction);
+
+ QObject::connect(nativeThread.qthread, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
+
+ nativeThread.stop();
+ nativeThread.join();
+
+ QTestEventLoop::instance().enterLoop(5);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+}
+
void tst_QThread::adoptMultipleThreads()
{
#if defined(Q_OS_WIN)
@@ -929,6 +945,7 @@ void tst_QThread::adoptMultipleThreads()
QTestEventLoop::instance().enterLoop(5);
QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(int(recorder.activationCount), numThreads);
+ qDeleteAll(nativeThreads);
}
void tst_QThread::stressTest()