From f4609b202208fe592d24c7ae3b4a48ee83045497 Mon Sep 17 00:00:00 2001 From: David Faure Date: Mon, 18 Mar 2013 15:19:44 +0100 Subject: QThread: fix race when setting the eventDispatcher Use QAtomicPointer to make this thread-safe. Change-Id: If71f204699fcefabdb59bd26342d777d1cc9e2a7 Reviewed-by: Olivier Goffart --- src/corelib/kernel/qabstracteventdispatcher.cpp | 2 +- src/corelib/kernel/qcoreapplication.cpp | 19 ++++++++++--------- src/corelib/kernel/qeventloop.cpp | 16 ++++++++-------- src/corelib/kernel/qobject.cpp | 20 ++++++++++---------- src/corelib/kernel/qsocketnotifier.cpp | 10 +++++----- src/corelib/kernel/qwineventnotifier.cpp | 4 ++-- 6 files changed, 36 insertions(+), 35 deletions(-) (limited to 'src/corelib/kernel') diff --git a/src/corelib/kernel/qabstracteventdispatcher.cpp b/src/corelib/kernel/qabstracteventdispatcher.cpp index c4e02c0347..6558893036 100644 --- a/src/corelib/kernel/qabstracteventdispatcher.cpp +++ b/src/corelib/kernel/qabstracteventdispatcher.cpp @@ -172,7 +172,7 @@ QAbstractEventDispatcher::~QAbstractEventDispatcher() QAbstractEventDispatcher *QAbstractEventDispatcher::instance(QThread *thread) { QThreadData *data = thread ? QThreadData::get2(thread) : QThreadData::current(); - return data->eventDispatcher; + return data->eventDispatcher.load(); } /*! diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index cce8c30d81..61a8b6a18c 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -689,7 +689,7 @@ void QCoreApplication::init() #ifndef QT_NO_QOBJECT // use the event dispatcher created by the app programmer (if any) if (!QCoreApplicationPrivate::eventDispatcher) - QCoreApplicationPrivate::eventDispatcher = d->threadData->eventDispatcher; + QCoreApplicationPrivate::eventDispatcher = d->threadData->eventDispatcher.load(); // otherwise we create one if (!QCoreApplicationPrivate::eventDispatcher) d->createEventDispatcher(); @@ -1031,9 +1031,9 @@ bool QCoreApplication::closingDown() void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags) { QThreadData *data = QThreadData::current(); - if (!data->eventDispatcher) + if (!data->hasEventDispatcher()) return; - data->eventDispatcher->processEvents(flags); + data->eventDispatcher.load()->processEvents(flags); } /*! @@ -1055,11 +1055,11 @@ void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags) void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags, int maxtime) { QThreadData *data = QThreadData::current(); - if (!data->eventDispatcher) + if (!data->hasEventDispatcher()) return; QElapsedTimer start; start.start(); - while (data->eventDispatcher->processEvents(flags & ~QEventLoop::WaitForMoreEvents)) { + while (data->eventDispatcher.load()->processEvents(flags & ~QEventLoop::WaitForMoreEvents)) { if (start.elapsed() > maxtime) break; } @@ -1258,8 +1258,9 @@ void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority) data->canWait = false; locker.unlock(); - if (data->eventDispatcher) - data->eventDispatcher->wakeUp(); + QAbstractEventDispatcher* dispatcher = data->eventDispatcher.loadAcquire(); + if (dispatcher) + dispatcher->wakeUp(); } /*! @@ -1379,8 +1380,8 @@ void QCoreApplicationPrivate::sendPostedEvents(QObject *receiver, int event_type } --data->postEventList.recursion; - if (!data->postEventList.recursion && !data->canWait && data->eventDispatcher) - data->eventDispatcher->wakeUp(); + if (!data->postEventList.recursion && !data->canWait && data->hasEventDispatcher()) + data->eventDispatcher.load()->wakeUp(); // clear the global list, i.e. remove everything that was // delivered. diff --git a/src/corelib/kernel/qeventloop.cpp b/src/corelib/kernel/qeventloop.cpp index fe254b5593..549b8db9ca 100644 --- a/src/corelib/kernel/qeventloop.cpp +++ b/src/corelib/kernel/qeventloop.cpp @@ -103,7 +103,7 @@ QEventLoop::QEventLoop(QObject *parent) Q_D(QEventLoop); if (!QCoreApplication::instance()) { qWarning("QEventLoop: Cannot be used without QApplication"); - } else if (!d->threadData->eventDispatcher) { + } else if (!d->threadData->eventDispatcher.load()) { QThreadPrivate::createEventDispatcher(d->threadData); } } @@ -131,9 +131,9 @@ QEventLoop::~QEventLoop() bool QEventLoop::processEvents(ProcessEventsFlags flags) { Q_D(QEventLoop); - if (!d->threadData->eventDispatcher) + if (!d->threadData->eventDispatcher.load()) return false; - return d->threadData->eventDispatcher->processEvents(flags); + return d->threadData->eventDispatcher.load()->processEvents(flags); } /*! @@ -234,7 +234,7 @@ int QEventLoop::exec(ProcessEventsFlags flags) void QEventLoop::processEvents(ProcessEventsFlags flags, int maxTime) { Q_D(QEventLoop); - if (!d->threadData->eventDispatcher) + if (!d->threadData->eventDispatcher.load()) return; QElapsedTimer start; @@ -263,12 +263,12 @@ void QEventLoop::processEvents(ProcessEventsFlags flags, int maxTime) void QEventLoop::exit(int returnCode) { Q_D(QEventLoop); - if (!d->threadData->eventDispatcher) + if (!d->threadData->eventDispatcher.load()) return; d->returnCode = returnCode; d->exit = true; - d->threadData->eventDispatcher->interrupt(); + d->threadData->eventDispatcher.load()->interrupt(); } /*! @@ -292,9 +292,9 @@ bool QEventLoop::isRunning() const void QEventLoop::wakeUp() { Q_D(QEventLoop); - if (!d->threadData->eventDispatcher) + if (!d->threadData->eventDispatcher.load()) return; - d->threadData->eventDispatcher->wakeUp(); + d->threadData->eventDispatcher.load()->wakeUp(); } diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 1312e64d8b..583e580762 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -216,8 +216,8 @@ QObjectPrivate::~QObjectPrivate() { if (extraData && !extraData->runningTimers.isEmpty()) { // unregister pending timers - if (threadData->eventDispatcher) - threadData->eventDispatcher->unregisterTimers(q_ptr); + if (threadData->eventDispatcher.load()) + threadData->eventDispatcher.load()->unregisterTimers(q_ptr); // release the timer ids back to the pool for (int i = 0; i < extraData->runningTimers.size(); ++i) @@ -1074,7 +1074,7 @@ bool QObject::event(QEvent *e) case QEvent::ThreadChange: { Q_D(QObject); QThreadData *threadData = d->threadData; - QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher; + QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher.load(); if (eventDispatcher) { QList timers = eventDispatcher->registeredTimers(this); if (!timers.isEmpty()) { @@ -1354,9 +1354,9 @@ void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData ++eventsMoved; } } - if (eventsMoved > 0 && targetData->eventDispatcher) { + if (eventsMoved > 0 && targetData->eventDispatcher.load()) { targetData->canWait = false; - targetData->eventDispatcher->wakeUp(); + targetData->eventDispatcher.load()->wakeUp(); } // the current emitting thread shouldn't restore currentSender after calling moveToThread() @@ -1379,7 +1379,7 @@ void QObjectPrivate::_q_reregisterTimers(void *pointer) { Q_Q(QObject); QList *timerList = reinterpret_cast *>(pointer); - QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher; + QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher.load(); for (int i = 0; i < timerList->size(); ++i) { const QAbstractEventDispatcher::TimerInfo &ti = timerList->at(i); eventDispatcher->registerTimer(ti.timerId, ti.interval, ti.timerType, q); @@ -1438,11 +1438,11 @@ int QObject::startTimer(int interval, Qt::TimerType timerType) return 0; } - if (!d->threadData->eventDispatcher) { + if (!d->threadData->eventDispatcher.load()) { qWarning("QObject::startTimer: QTimer can only be used with threads started with QThread"); return 0; } - int timerId = d->threadData->eventDispatcher->registerTimer(interval, timerType, this); + int timerId = d->threadData->eventDispatcher.load()->registerTimer(interval, timerType, this); if (!d->extraData) d->extraData = new QObjectPrivate::ExtraData; d->extraData->runningTimers.append(timerId); @@ -1472,8 +1472,8 @@ void QObject::killTimer(int id) return; } - if (d->threadData->eventDispatcher) - d->threadData->eventDispatcher->unregisterTimer(id); + if (d->threadData->eventDispatcher.load()) + d->threadData->eventDispatcher.load()->unregisterTimer(id); d->extraData->runningTimers.remove(at); QAbstractEventDispatcherPrivate::releaseTimerId(id); diff --git a/src/corelib/kernel/qsocketnotifier.cpp b/src/corelib/kernel/qsocketnotifier.cpp index ad687491f1..e0c7f171c3 100644 --- a/src/corelib/kernel/qsocketnotifier.cpp +++ b/src/corelib/kernel/qsocketnotifier.cpp @@ -187,10 +187,10 @@ QSocketNotifier::QSocketNotifier(qintptr socket, Type type, QObject *parent) d->sntype = type; d->snenabled = true; - if (!d->threadData->eventDispatcher) { + if (!d->threadData->eventDispatcher.load()) { qWarning("QSocketNotifier: Can only be used with threads started with QThread"); } else { - d->threadData->eventDispatcher->registerSocketNotifier(this); + d->threadData->eventDispatcher.load()->registerSocketNotifier(this); } } @@ -273,12 +273,12 @@ void QSocketNotifier::setEnabled(bool enable) return; d->snenabled = enable; - if (!d->threadData->eventDispatcher) // perhaps application/thread is shutting down + if (!d->threadData->eventDispatcher.load()) // perhaps application/thread is shutting down return; if (d->snenabled) - d->threadData->eventDispatcher->registerSocketNotifier(this); + d->threadData->eventDispatcher.load()->registerSocketNotifier(this); else - d->threadData->eventDispatcher->unregisterSocketNotifier(this); + d->threadData->eventDispatcher.load()->unregisterSocketNotifier(this); } diff --git a/src/corelib/kernel/qwineventnotifier.cpp b/src/corelib/kernel/qwineventnotifier.cpp index f24843dc4a..242702b304 100644 --- a/src/corelib/kernel/qwineventnotifier.cpp +++ b/src/corelib/kernel/qwineventnotifier.cpp @@ -135,7 +135,7 @@ QWinEventNotifier::QWinEventNotifier(HANDLE hEvent, QObject *parent) : QObject(*new QWinEventNotifierPrivate(hEvent, false), parent) { Q_D(QWinEventNotifier); - QAbstractEventDispatcher *eventDispatcher = d->threadData->eventDispatcher; + QAbstractEventDispatcher *eventDispatcher = d->threadData->eventDispatcher.load(); if (!eventDispatcher) { qWarning("QWinEventNotifier: Can only be used with threads started with QThread"); } else { @@ -208,7 +208,7 @@ void QWinEventNotifier::setEnabled(bool enable) return; d->enabled = enable; - QAbstractEventDispatcher *eventDispatcher = d->threadData->eventDispatcher; + QAbstractEventDispatcher *eventDispatcher = d->threadData->eventDispatcher.load(); if (!eventDispatcher) // perhaps application is shutting down return; -- cgit v1.2.3