diff options
author | Olivier Goffart <olivier.goffart@nokia.com> | 2011-02-04 09:00:35 (GMT) |
---|---|---|
committer | Olivier Goffart <olivier.goffart@nokia.com> | 2011-02-07 15:11:06 (GMT) |
commit | a77ab4c4dd3c0d9c5cf71afc4d3efcc76a068430 (patch) | |
tree | 47d2955a71c203240a55b892561075c33b39b5c5 | |
parent | cce5cde471cb107924a31c91a05ca299f1668edb (diff) | |
download | Qt-a77ab4c4dd3c0d9c5cf71afc4d3efcc76a068430.zip Qt-a77ab4c4dd3c0d9c5cf71afc4d3efcc76a068430.tar.gz Qt-a77ab4c4dd3c0d9c5cf71afc4d3efcc76a068430.tar.bz2 |
Fix race condition between QEventLoop::exec and QThread::exit
As also mentioned in QTBUG-16692
Reviewed-by: brad
Task-number: QTBUG-17257
-rw-r--r-- | src/corelib/kernel/qeventloop.cpp | 5 | ||||
-rw-r--r-- | src/corelib/thread/qthread_unix.cpp | 5 | ||||
-rw-r--r-- | src/corelib/thread/qthread_win.cpp | 5 | ||||
-rw-r--r-- | tests/auto/qthread/tst_qthread.cpp | 16 |
4 files changed, 29 insertions, 2 deletions
diff --git a/src/corelib/kernel/qeventloop.cpp b/src/corelib/kernel/qeventloop.cpp index e78f86a..d213b0e 100644 --- a/src/corelib/kernel/qeventloop.cpp +++ b/src/corelib/kernel/qeventloop.cpp @@ -175,6 +175,8 @@ bool QEventLoop::processEvents(ProcessEventsFlags flags) int QEventLoop::exec(ProcessEventsFlags flags) { Q_D(QEventLoop); + //we need to protect from race condition with QThread::exit + QMutexLocker locker(&static_cast<QThreadPrivate *>(QObjectPrivate::get(d->threadData->thread))->mutex); if (d->threadData->quitNow) return -1; @@ -186,6 +188,7 @@ int QEventLoop::exec(ProcessEventsFlags flags) d->exit = false; ++d->threadData->loopLevel; d->threadData->eventLoops.push(this); + locker.unlock(); // remove posted quit events when entering a new event loop QCoreApplication *app = QCoreApplication::instance(); @@ -205,6 +208,7 @@ int QEventLoop::exec(ProcessEventsFlags flags) "reimplement QApplication::notify() and catch all exceptions there.\n"); // copied from below + locker.relock(); QEventLoop *eventLoop = d->threadData->eventLoops.pop(); Q_ASSERT_X(eventLoop == this, "QEventLoop::exec()", "internal error"); Q_UNUSED(eventLoop); // --release warning @@ -216,6 +220,7 @@ int QEventLoop::exec(ProcessEventsFlags flags) #endif // copied above + locker.relock(); QEventLoop *eventLoop = d->threadData->eventLoops.pop(); Q_ASSERT_X(eventLoop == this, "QEventLoop::exec()", "internal error"); Q_UNUSED(eventLoop); // --release warning diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index 891ac77..5e0d2a2 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -327,7 +327,10 @@ void *QThreadPrivate::start(void *arg) set_thread_data(data); data->ref(); - data->quitNow = false; + { + QMutexLocker locker(&thr->d_func()->mutex); + data->quitNow = thr->d_func()->exited; + } // ### TODO: allow the user to create a custom event dispatcher createEventDispatcher(data); diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp index cb2d1a9..f2d1310 100644 --- a/src/corelib/thread/qthread_win.cpp +++ b/src/corelib/thread/qthread_win.cpp @@ -298,7 +298,10 @@ unsigned int __stdcall QThreadPrivate::start(void *arg) QThread::setTerminationEnabled(false); - data->quitNow = false; + { + QMutexLocker locker(&thr->d_func()->mutex); + data->quitNow = !thr->d_func()->exited; + } // ### TODO: allow the user to create a custom event dispatcher createEventDispatcher(data); diff --git a/tests/auto/qthread/tst_qthread.cpp b/tests/auto/qthread/tst_qthread.cpp index 19c6c16..c69052e 100644 --- a/tests/auto/qthread/tst_qthread.cpp +++ b/tests/auto/qthread/tst_qthread.cpp @@ -113,6 +113,7 @@ private slots: void wait3_slowDestructor(); void destroyFinishRace(); void startFinishRace(); + void startAndQuitCustomEventLoop(); void stressTest(); }; @@ -1150,5 +1151,20 @@ void tst_QThread::startFinishRace() } } +void tst_QThread::startAndQuitCustomEventLoop() +{ + struct Thread : QThread { + void run() { QEventLoop().exec(); } + }; + + for (int i = 0; i < 5; i++) { + Thread t; + t.start(); + t.quit(); + t.wait(); + } +} + + QTEST_MAIN(tst_QThread) #include "tst_qthread.moc" |