diff options
author | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2019-10-11 00:42:08 +0200 |
---|---|---|
committer | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2019-11-13 16:22:40 +0100 |
commit | 782df5b41dd3ab098fd1d3233339079487e1812f (patch) | |
tree | a2727ed7dda4ecff4331e99d05f085bb7fc01184 /src/corelib/kernel/qsocketnotifier.cpp | |
parent | 4e0d5498eb7ba401e6697182ce74b34d439ecf76 (diff) |
Make QObjectPrivate::threadData a proper atomic
QObjectPrivate::threadData used to be a QThreadData *, and was
read and written from multiple threads without proper synchronization.
As an example, it was read from QCoreApplication::postEvent and
written from QObject::moveToThread, therefore causing UB.
Port threadData to a proper atomic, removing the races. Fix all usage
points.
In general, QObject is documented to be simply reentrant,
not thread-safe, and certain bits (e.g. timers, moveToThread)
are not even reentrant. The reasoning therefore is that a given
QObject's threadData is not supposed to be touched by multiple
threads without some synchronization happening elsewhere, and
therefore relaxed loads should be sufficient.
As drive-by change: refactor QCoreApplication::postEvent.
It was particularly subtle, because it had a loop using a volatile
to cope with the possibility of the receiver object switching thread
while we tried to lock its thread's event queue.
However, volatile does not achieve any synchronization, so drop it,
and refactor the algorithm using better locking primitives.
Put this algorithm in a common place, and also reuse it from
removePostedEvents, which was lacking any synchronization.
Change-Id: Icc755f7eb418ff54b33db4bdd87fd8eaf4e82c7a
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/kernel/qsocketnotifier.cpp')
-rw-r--r-- | src/corelib/kernel/qsocketnotifier.cpp | 15 |
1 files changed, 10 insertions, 5 deletions
diff --git a/src/corelib/kernel/qsocketnotifier.cpp b/src/corelib/kernel/qsocketnotifier.cpp index 2a246b1204..78269ee605 100644 --- a/src/corelib/kernel/qsocketnotifier.cpp +++ b/src/corelib/kernel/qsocketnotifier.cpp @@ -147,12 +147,14 @@ QSocketNotifier::QSocketNotifier(qintptr socket, Type type, QObject *parent) d->sntype = type; d->snenabled = true; + auto thisThreadData = d->threadData.loadRelaxed(); + if (socket < 0) qWarning("QSocketNotifier: Invalid socket specified"); - else if (!d->threadData->hasEventDispatcher()) + else if (!thisThreadData->hasEventDispatcher()) qWarning("QSocketNotifier: Can only be used with threads started with QThread"); else - d->threadData->eventDispatcher.loadRelaxed()->registerSocketNotifier(this); + thisThreadData->eventDispatcher.loadRelaxed()->registerSocketNotifier(this); } /*! @@ -234,16 +236,19 @@ void QSocketNotifier::setEnabled(bool enable) return; d->snenabled = enable; - if (!d->threadData->hasEventDispatcher()) // perhaps application/thread is shutting down + + auto thisThreadData = d->threadData.loadRelaxed(); + + if (!thisThreadData->hasEventDispatcher()) // perhaps application/thread is shutting down return; if (Q_UNLIKELY(thread() != QThread::currentThread())) { qWarning("QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread"); return; } if (d->snenabled) - d->threadData->eventDispatcher.loadRelaxed()->registerSocketNotifier(this); + thisThreadData->eventDispatcher.loadRelaxed()->registerSocketNotifier(this); else - d->threadData->eventDispatcher.loadRelaxed()->unregisterSocketNotifier(this); + thisThreadData->eventDispatcher.loadRelaxed()->unregisterSocketNotifier(this); } |