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>
This commit is contained in:
parent
4e0d5498eb
commit
782df5b41d
@ -246,7 +246,7 @@ bool QProcessPrivate::openChannel(Channel &channel)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// create the socket notifiers
|
// create the socket notifiers
|
||||||
if (threadData->hasEventDispatcher()) {
|
if (threadData.loadRelaxed()->hasEventDispatcher()) {
|
||||||
if (&channel == &stdinChannel) {
|
if (&channel == &stdinChannel) {
|
||||||
channel.notifier = new QSocketNotifier(channel.pipe[1],
|
channel.notifier = new QSocketNotifier(channel.pipe[1],
|
||||||
QSocketNotifier::Write, q);
|
QSocketNotifier::Write, q);
|
||||||
@ -377,7 +377,7 @@ void QProcessPrivate::startProcess()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (threadData->hasEventDispatcher()) {
|
if (threadData.loadRelaxed()->hasEventDispatcher()) {
|
||||||
startupSocketNotifier = new QSocketNotifier(childStartedPipe[0],
|
startupSocketNotifier = new QSocketNotifier(childStartedPipe[0],
|
||||||
QSocketNotifier::Read, q);
|
QSocketNotifier::Read, q);
|
||||||
QObject::connect(startupSocketNotifier, SIGNAL(activated(int)),
|
QObject::connect(startupSocketNotifier, SIGNAL(activated(int)),
|
||||||
@ -517,7 +517,7 @@ void QProcessPrivate::startProcess()
|
|||||||
if (stderrChannel.pipe[0] != -1)
|
if (stderrChannel.pipe[0] != -1)
|
||||||
::fcntl(stderrChannel.pipe[0], F_SETFL, ::fcntl(stderrChannel.pipe[0], F_GETFL) | O_NONBLOCK);
|
::fcntl(stderrChannel.pipe[0], F_SETFL, ::fcntl(stderrChannel.pipe[0], F_GETFL) | O_NONBLOCK);
|
||||||
|
|
||||||
if (threadData->eventDispatcher.loadAcquire()) {
|
if (threadData.loadRelaxed()->eventDispatcher.loadAcquire()) {
|
||||||
deathNotifier = new QSocketNotifier(forkfd, QSocketNotifier::Read, q);
|
deathNotifier = new QSocketNotifier(forkfd, QSocketNotifier::Read, q);
|
||||||
QObject::connect(deathNotifier, SIGNAL(activated(int)),
|
QObject::connect(deathNotifier, SIGNAL(activated(int)),
|
||||||
q, SLOT(_q_processDied()));
|
q, SLOT(_q_processDied()));
|
||||||
|
@ -590,7 +590,7 @@ void QProcessPrivate::startProcess()
|
|||||||
if (!pid)
|
if (!pid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (threadData->hasEventDispatcher()) {
|
if (threadData.loadRelaxed()->hasEventDispatcher()) {
|
||||||
processFinishedNotifier = new QWinEventNotifier(pid->hProcess, q);
|
processFinishedNotifier = new QWinEventNotifier(pid->hProcess, q);
|
||||||
QObject::connect(processFinishedNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_processDied()));
|
QObject::connect(processFinishedNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_processDied()));
|
||||||
processFinishedNotifier->setEnabled(true);
|
processFinishedNotifier->setEnabled(true);
|
||||||
|
@ -135,23 +135,6 @@
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
#ifndef QT_NO_QOBJECT
|
|
||||||
class QMutexUnlocker
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
inline explicit QMutexUnlocker(QMutex *m)
|
|
||||||
: mtx(m)
|
|
||||||
{ }
|
|
||||||
inline ~QMutexUnlocker() { unlock(); }
|
|
||||||
inline void unlock() { if (mtx) mtx->unlock(); mtx = 0; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Q_DISABLE_COPY(QMutexUnlocker)
|
|
||||||
|
|
||||||
QMutex *mtx;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
|
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
|
||||||
extern QString qAppFileName();
|
extern QString qAppFileName();
|
||||||
#endif
|
#endif
|
||||||
@ -517,25 +500,27 @@ QCoreApplicationPrivate::~QCoreApplicationPrivate()
|
|||||||
|
|
||||||
void QCoreApplicationPrivate::cleanupThreadData()
|
void QCoreApplicationPrivate::cleanupThreadData()
|
||||||
{
|
{
|
||||||
if (threadData && !threadData_clean) {
|
auto thisThreadData = threadData.loadRelaxed();
|
||||||
|
|
||||||
|
if (thisThreadData && !threadData_clean) {
|
||||||
#if QT_CONFIG(thread)
|
#if QT_CONFIG(thread)
|
||||||
void *data = &threadData->tls;
|
void *data = &thisThreadData->tls;
|
||||||
QThreadStorageData::finish((void **)data);
|
QThreadStorageData::finish((void **)data);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// need to clear the state of the mainData, just in case a new QCoreApplication comes along.
|
// need to clear the state of the mainData, just in case a new QCoreApplication comes along.
|
||||||
const auto locker = qt_scoped_lock(threadData->postEventList.mutex);
|
const auto locker = qt_scoped_lock(thisThreadData->postEventList.mutex);
|
||||||
for (int i = 0; i < threadData->postEventList.size(); ++i) {
|
for (int i = 0; i < thisThreadData->postEventList.size(); ++i) {
|
||||||
const QPostEvent &pe = threadData->postEventList.at(i);
|
const QPostEvent &pe = thisThreadData->postEventList.at(i);
|
||||||
if (pe.event) {
|
if (pe.event) {
|
||||||
--pe.receiver->d_func()->postedEvents;
|
--pe.receiver->d_func()->postedEvents;
|
||||||
pe.event->posted = false;
|
pe.event->posted = false;
|
||||||
delete pe.event;
|
delete pe.event;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
threadData->postEventList.clear();
|
thisThreadData->postEventList.clear();
|
||||||
threadData->postEventList.recursion = 0;
|
thisThreadData->postEventList.recursion = 0;
|
||||||
threadData->quitNow = false;
|
thisThreadData->quitNow = false;
|
||||||
threadData_clean = true;
|
threadData_clean = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -858,7 +843,8 @@ void QCoreApplicationPrivate::init()
|
|||||||
#ifndef QT_NO_QOBJECT
|
#ifndef QT_NO_QOBJECT
|
||||||
// use the event dispatcher created by the app programmer (if any)
|
// use the event dispatcher created by the app programmer (if any)
|
||||||
Q_ASSERT(!eventDispatcher);
|
Q_ASSERT(!eventDispatcher);
|
||||||
eventDispatcher = threadData->eventDispatcher.loadRelaxed();
|
auto thisThreadData = threadData.loadRelaxed();
|
||||||
|
eventDispatcher = thisThreadData->eventDispatcher.loadRelaxed();
|
||||||
|
|
||||||
// otherwise we create one
|
// otherwise we create one
|
||||||
if (!eventDispatcher)
|
if (!eventDispatcher)
|
||||||
@ -866,11 +852,11 @@ void QCoreApplicationPrivate::init()
|
|||||||
Q_ASSERT(eventDispatcher);
|
Q_ASSERT(eventDispatcher);
|
||||||
|
|
||||||
if (!eventDispatcher->parent()) {
|
if (!eventDispatcher->parent()) {
|
||||||
eventDispatcher->moveToThread(threadData->thread.loadAcquire());
|
eventDispatcher->moveToThread(thisThreadData->thread.loadAcquire());
|
||||||
eventDispatcher->setParent(q);
|
eventDispatcher->setParent(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
threadData->eventDispatcher = eventDispatcher;
|
thisThreadData->eventDispatcher = eventDispatcher;
|
||||||
eventDispatcherReady();
|
eventDispatcherReady();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -914,7 +900,7 @@ QCoreApplication::~QCoreApplication()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef QT_NO_QOBJECT
|
#ifndef QT_NO_QOBJECT
|
||||||
d_func()->threadData->eventDispatcher = nullptr;
|
d_func()->threadData.loadRelaxed()->eventDispatcher = nullptr;
|
||||||
if (QCoreApplicationPrivate::eventDispatcher)
|
if (QCoreApplicationPrivate::eventDispatcher)
|
||||||
QCoreApplicationPrivate::eventDispatcher->closingDown();
|
QCoreApplicationPrivate::eventDispatcher->closingDown();
|
||||||
QCoreApplicationPrivate::eventDispatcher = nullptr;
|
QCoreApplicationPrivate::eventDispatcher = nullptr;
|
||||||
@ -1185,7 +1171,7 @@ static bool doNotify(QObject *receiver, QEvent *event)
|
|||||||
bool QCoreApplicationPrivate::sendThroughApplicationEventFilters(QObject *receiver, QEvent *event)
|
bool QCoreApplicationPrivate::sendThroughApplicationEventFilters(QObject *receiver, QEvent *event)
|
||||||
{
|
{
|
||||||
// We can't access the application event filters outside of the main thread (race conditions)
|
// We can't access the application event filters outside of the main thread (race conditions)
|
||||||
Q_ASSERT(receiver->d_func()->threadData->thread.loadAcquire() == mainThread());
|
Q_ASSERT(receiver->d_func()->threadData.loadRelaxed()->thread.loadAcquire() == mainThread());
|
||||||
|
|
||||||
if (extraData) {
|
if (extraData) {
|
||||||
// application event filters are only called for objects in the GUI thread
|
// application event filters are only called for objects in the GUI thread
|
||||||
@ -1238,7 +1224,7 @@ bool QCoreApplicationPrivate::notify_helper(QObject *receiver, QEvent * event)
|
|||||||
|
|
||||||
// send to all application event filters (only does anything in the main thread)
|
// send to all application event filters (only does anything in the main thread)
|
||||||
if (QCoreApplication::self
|
if (QCoreApplication::self
|
||||||
&& receiver->d_func()->threadData->thread.loadAcquire() == mainThread()
|
&& receiver->d_func()->threadData.loadRelaxed()->thread.loadAcquire() == mainThread()
|
||||||
&& QCoreApplication::self->d_func()->sendThroughApplicationEventFilters(receiver, event)) {
|
&& QCoreApplication::self->d_func()->sendThroughApplicationEventFilters(receiver, event)) {
|
||||||
filtered = true;
|
filtered = true;
|
||||||
return filtered;
|
return filtered;
|
||||||
@ -1414,7 +1400,7 @@ int QCoreApplication::exec()
|
|||||||
|
|
||||||
void QCoreApplicationPrivate::execCleanup()
|
void QCoreApplicationPrivate::execCleanup()
|
||||||
{
|
{
|
||||||
threadData->quitNow = false;
|
threadData.loadRelaxed()->quitNow = false;
|
||||||
in_exec = false;
|
in_exec = false;
|
||||||
if (!aboutToQuitEmitted)
|
if (!aboutToQuitEmitted)
|
||||||
emit q_func()->aboutToQuit(QCoreApplication::QPrivateSignal());
|
emit q_func()->aboutToQuit(QCoreApplication::QPrivateSignal());
|
||||||
@ -1451,7 +1437,7 @@ void QCoreApplication::exit(int returnCode)
|
|||||||
{
|
{
|
||||||
if (!self)
|
if (!self)
|
||||||
return;
|
return;
|
||||||
QThreadData *data = self->d_func()->threadData;
|
QThreadData *data = self->d_func()->threadData.loadRelaxed();
|
||||||
data->quitNow = true;
|
data->quitNow = true;
|
||||||
for (int i = 0; i < data->eventLoops.size(); ++i) {
|
for (int i = 0; i < data->eventLoops.size(); ++i) {
|
||||||
QEventLoop *eventLoop = data->eventLoops.at(i);
|
QEventLoop *eventLoop = data->eventLoops.at(i);
|
||||||
@ -1501,6 +1487,38 @@ bool QCoreApplication::sendSpontaneousEvent(QObject *receiver, QEvent *event)
|
|||||||
|
|
||||||
#endif // QT_NO_QOBJECT
|
#endif // QT_NO_QOBJECT
|
||||||
|
|
||||||
|
QCoreApplicationPrivate::QPostEventListLocker QCoreApplicationPrivate::lockThreadPostEventList(QObject *object)
|
||||||
|
{
|
||||||
|
QPostEventListLocker locker;
|
||||||
|
|
||||||
|
if (!object) {
|
||||||
|
locker.threadData = QThreadData::current();
|
||||||
|
locker.locker = qt_unique_lock(locker.threadData->postEventList.mutex);
|
||||||
|
return locker;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &threadData = QObjectPrivate::get(object)->threadData;
|
||||||
|
|
||||||
|
// if object has moved to another thread, follow it
|
||||||
|
for (;;) {
|
||||||
|
// synchronizes with the storeRelease in QObject::moveToThread
|
||||||
|
locker.threadData = threadData.loadAcquire();
|
||||||
|
if (!locker.threadData) {
|
||||||
|
// destruction in progress
|
||||||
|
return locker;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto temporaryLocker = qt_unique_lock(locker.threadData->postEventList.mutex);
|
||||||
|
if (locker.threadData == threadData.loadAcquire()) {
|
||||||
|
locker.locker = std::move(temporaryLocker);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_ASSERT(locker.threadData);
|
||||||
|
return locker;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\since 4.3
|
\since 4.3
|
||||||
|
|
||||||
@ -1536,32 +1554,14 @@ void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QThreadData * volatile * pdata = &receiver->d_func()->threadData;
|
auto locker = QCoreApplicationPrivate::lockThreadPostEventList(receiver);
|
||||||
QThreadData *data = *pdata;
|
if (!locker.threadData) {
|
||||||
if (!data) {
|
|
||||||
// posting during destruction? just delete the event to prevent a leak
|
// posting during destruction? just delete the event to prevent a leak
|
||||||
delete event;
|
delete event;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// lock the post event mutex
|
QThreadData *data = locker.threadData;
|
||||||
data->postEventList.mutex.lock();
|
|
||||||
|
|
||||||
// if object has moved to another thread, follow it
|
|
||||||
while (data != *pdata) {
|
|
||||||
data->postEventList.mutex.unlock();
|
|
||||||
|
|
||||||
data = *pdata;
|
|
||||||
if (!data) {
|
|
||||||
// posting during destruction? just delete the event to prevent a leak
|
|
||||||
delete event;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
data->postEventList.mutex.lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
QMutexUnlocker locker(&data->postEventList.mutex);
|
|
||||||
|
|
||||||
// if this is one of the compressible events, do compression
|
// if this is one of the compressible events, do compression
|
||||||
if (receiver->d_func()->postedEvents
|
if (receiver->d_func()->postedEvents
|
||||||
@ -1860,8 +1860,8 @@ void QCoreApplicationPrivate::sendPostedEvents(QObject *receiver, int event_type
|
|||||||
|
|
||||||
void QCoreApplication::removePostedEvents(QObject *receiver, int eventType)
|
void QCoreApplication::removePostedEvents(QObject *receiver, int eventType)
|
||||||
{
|
{
|
||||||
QThreadData *data = receiver ? receiver->d_func()->threadData : QThreadData::current();
|
auto locker = QCoreApplicationPrivate::lockThreadPostEventList(receiver);
|
||||||
auto locker = qt_unique_lock(data->postEventList.mutex);
|
QThreadData *data = locker.threadData;
|
||||||
|
|
||||||
// the QObject destructor calls this function directly. this can
|
// the QObject destructor calls this function directly. this can
|
||||||
// happen while the event loop is in the middle of posting events,
|
// happen while the event loop is in the middle of posting events,
|
||||||
|
@ -61,6 +61,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#ifndef QT_NO_QOBJECT
|
#ifndef QT_NO_QOBJECT
|
||||||
#include "private/qobject_p.h"
|
#include "private/qobject_p.h"
|
||||||
|
#include "private/qlocking_p.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef Q_OS_MACOS
|
#ifdef Q_OS_MACOS
|
||||||
@ -140,6 +141,15 @@ public:
|
|||||||
|
|
||||||
static void checkReceiverThread(QObject *receiver);
|
static void checkReceiverThread(QObject *receiver);
|
||||||
void cleanupThreadData();
|
void cleanupThreadData();
|
||||||
|
|
||||||
|
struct QPostEventListLocker
|
||||||
|
{
|
||||||
|
QThreadData *threadData;
|
||||||
|
std::unique_lock<QMutex> locker;
|
||||||
|
|
||||||
|
void unlock() { locker.unlock(); }
|
||||||
|
};
|
||||||
|
static QPostEventListLocker lockThreadPostEventList(QObject *object);
|
||||||
#endif // QT_NO_QOBJECT
|
#endif // QT_NO_QOBJECT
|
||||||
|
|
||||||
int &argc;
|
int &argc;
|
||||||
|
@ -918,7 +918,7 @@ QDebug operator<<(QDebug dbg, const MSG &msg)
|
|||||||
#ifndef QT_NO_QOBJECT
|
#ifndef QT_NO_QOBJECT
|
||||||
void QCoreApplicationPrivate::removePostedTimerEvent(QObject *object, int timerId)
|
void QCoreApplicationPrivate::removePostedTimerEvent(QObject *object, int timerId)
|
||||||
{
|
{
|
||||||
QThreadData *data = object->d_func()->threadData;
|
QThreadData *data = object->d_func()->threadData.loadRelaxed();
|
||||||
|
|
||||||
const auto locker = qt_scoped_lock(data->postEventList.mutex);
|
const auto locker = qt_scoped_lock(data->postEventList.mutex);
|
||||||
if (data->postEventList.size() == 0)
|
if (data->postEventList.size() == 0)
|
||||||
|
@ -463,13 +463,15 @@ bool QEventDispatcherUNIX::processEvents(QEventLoop::ProcessEventsFlags flags)
|
|||||||
|
|
||||||
// we are awake, broadcast it
|
// we are awake, broadcast it
|
||||||
emit awake();
|
emit awake();
|
||||||
QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData);
|
|
||||||
|
auto threadData = d->threadData.loadRelaxed();
|
||||||
|
QCoreApplicationPrivate::sendPostedEvents(0, 0, threadData);
|
||||||
|
|
||||||
const bool include_timers = (flags & QEventLoop::X11ExcludeTimers) == 0;
|
const bool include_timers = (flags & QEventLoop::X11ExcludeTimers) == 0;
|
||||||
const bool include_notifiers = (flags & QEventLoop::ExcludeSocketNotifiers) == 0;
|
const bool include_notifiers = (flags & QEventLoop::ExcludeSocketNotifiers) == 0;
|
||||||
const bool wait_for_events = flags & QEventLoop::WaitForMoreEvents;
|
const bool wait_for_events = flags & QEventLoop::WaitForMoreEvents;
|
||||||
|
|
||||||
const bool canWait = (d->threadData->canWaitLocked()
|
const bool canWait = (threadData->canWaitLocked()
|
||||||
&& !d->interrupt.loadRelaxed()
|
&& !d->interrupt.loadRelaxed()
|
||||||
&& wait_for_events);
|
&& wait_for_events);
|
||||||
|
|
||||||
|
@ -1048,7 +1048,7 @@ bool QEventDispatcherWin32::event(QEvent *e)
|
|||||||
void QEventDispatcherWin32::sendPostedEvents()
|
void QEventDispatcherWin32::sendPostedEvents()
|
||||||
{
|
{
|
||||||
Q_D(QEventDispatcherWin32);
|
Q_D(QEventDispatcherWin32);
|
||||||
QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData);
|
QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData.loadRelaxed());
|
||||||
}
|
}
|
||||||
|
|
||||||
HWND QEventDispatcherWin32::internalHwnd()
|
HWND QEventDispatcherWin32::internalHwnd()
|
||||||
|
@ -106,7 +106,7 @@ QEventLoop::QEventLoop(QObject *parent)
|
|||||||
if (!QCoreApplication::instance() && QCoreApplicationPrivate::threadRequiresCoreApplication()) {
|
if (!QCoreApplication::instance() && QCoreApplicationPrivate::threadRequiresCoreApplication()) {
|
||||||
qWarning("QEventLoop: Cannot be used without QApplication");
|
qWarning("QEventLoop: Cannot be used without QApplication");
|
||||||
} else {
|
} else {
|
||||||
d->threadData->ensureEventDispatcher();
|
d->threadData.loadRelaxed()->ensureEventDispatcher();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,9 +133,10 @@ QEventLoop::~QEventLoop()
|
|||||||
bool QEventLoop::processEvents(ProcessEventsFlags flags)
|
bool QEventLoop::processEvents(ProcessEventsFlags flags)
|
||||||
{
|
{
|
||||||
Q_D(QEventLoop);
|
Q_D(QEventLoop);
|
||||||
if (!d->threadData->hasEventDispatcher())
|
auto threadData = d->threadData.loadRelaxed();
|
||||||
|
if (!threadData->hasEventDispatcher())
|
||||||
return false;
|
return false;
|
||||||
return d->threadData->eventDispatcher.loadRelaxed()->processEvents(flags);
|
return threadData->eventDispatcher.loadRelaxed()->processEvents(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -164,9 +165,11 @@ bool QEventLoop::processEvents(ProcessEventsFlags flags)
|
|||||||
int QEventLoop::exec(ProcessEventsFlags flags)
|
int QEventLoop::exec(ProcessEventsFlags flags)
|
||||||
{
|
{
|
||||||
Q_D(QEventLoop);
|
Q_D(QEventLoop);
|
||||||
|
auto threadData = d->threadData.loadRelaxed();
|
||||||
|
|
||||||
//we need to protect from race condition with QThread::exit
|
//we need to protect from race condition with QThread::exit
|
||||||
QMutexLocker locker(&static_cast<QThreadPrivate *>(QObjectPrivate::get(d->threadData->thread.loadAcquire()))->mutex);
|
QMutexLocker locker(&static_cast<QThreadPrivate *>(QObjectPrivate::get(threadData->thread.loadAcquire()))->mutex);
|
||||||
if (d->threadData->quitNow)
|
if (threadData->quitNow)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (d->inExec) {
|
if (d->inExec) {
|
||||||
@ -183,8 +186,11 @@ int QEventLoop::exec(ProcessEventsFlags flags)
|
|||||||
{
|
{
|
||||||
d->inExec = true;
|
d->inExec = true;
|
||||||
d->exit.storeRelease(false);
|
d->exit.storeRelease(false);
|
||||||
++d->threadData->loopLevel;
|
|
||||||
d->threadData->eventLoops.push(d->q_func());
|
auto threadData = d->threadData.loadRelaxed();
|
||||||
|
++threadData->loopLevel;
|
||||||
|
threadData->eventLoops.push(d->q_func());
|
||||||
|
|
||||||
locker.unlock();
|
locker.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,11 +204,12 @@ int QEventLoop::exec(ProcessEventsFlags flags)
|
|||||||
"QCoreApplication::notify() and catch all exceptions there.\n");
|
"QCoreApplication::notify() and catch all exceptions there.\n");
|
||||||
}
|
}
|
||||||
locker.relock();
|
locker.relock();
|
||||||
QEventLoop *eventLoop = d->threadData->eventLoops.pop();
|
auto threadData = d->threadData.loadRelaxed();
|
||||||
|
QEventLoop *eventLoop = threadData->eventLoops.pop();
|
||||||
Q_ASSERT_X(eventLoop == d->q_func(), "QEventLoop::exec()", "internal error");
|
Q_ASSERT_X(eventLoop == d->q_func(), "QEventLoop::exec()", "internal error");
|
||||||
Q_UNUSED(eventLoop); // --release warning
|
Q_UNUSED(eventLoop); // --release warning
|
||||||
d->inExec = false;
|
d->inExec = false;
|
||||||
--d->threadData->loopLevel;
|
--threadData->loopLevel;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
LoopReference ref(d, locker);
|
LoopReference ref(d, locker);
|
||||||
@ -217,7 +224,7 @@ int QEventLoop::exec(ProcessEventsFlags flags)
|
|||||||
// exception, which returns control to the browser while preserving the C++ stack.
|
// exception, which returns control to the browser while preserving the C++ stack.
|
||||||
// Event processing then continues as normal. The sleep call below never returns.
|
// Event processing then continues as normal. The sleep call below never returns.
|
||||||
// QTBUG-70185
|
// QTBUG-70185
|
||||||
if (d->threadData->loopLevel > 1)
|
if (threadData->loopLevel > 1)
|
||||||
emscripten_sleep(1);
|
emscripten_sleep(1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -247,7 +254,7 @@ int QEventLoop::exec(ProcessEventsFlags flags)
|
|||||||
void QEventLoop::processEvents(ProcessEventsFlags flags, int maxTime)
|
void QEventLoop::processEvents(ProcessEventsFlags flags, int maxTime)
|
||||||
{
|
{
|
||||||
Q_D(QEventLoop);
|
Q_D(QEventLoop);
|
||||||
if (!d->threadData->hasEventDispatcher())
|
if (!d->threadData.loadRelaxed()->hasEventDispatcher())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QElapsedTimer start;
|
QElapsedTimer start;
|
||||||
@ -276,21 +283,22 @@ void QEventLoop::processEvents(ProcessEventsFlags flags, int maxTime)
|
|||||||
void QEventLoop::exit(int returnCode)
|
void QEventLoop::exit(int returnCode)
|
||||||
{
|
{
|
||||||
Q_D(QEventLoop);
|
Q_D(QEventLoop);
|
||||||
if (!d->threadData->hasEventDispatcher())
|
auto threadData = d->threadData.loadAcquire();
|
||||||
|
if (!threadData->hasEventDispatcher())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
d->returnCode.storeRelaxed(returnCode);
|
d->returnCode.storeRelaxed(returnCode);
|
||||||
d->exit.storeRelease(true);
|
d->exit.storeRelease(true);
|
||||||
d->threadData->eventDispatcher.loadRelaxed()->interrupt();
|
threadData->eventDispatcher.loadRelaxed()->interrupt();
|
||||||
|
|
||||||
#ifdef Q_OS_WASM
|
#ifdef Q_OS_WASM
|
||||||
// QEventLoop::exec() never returns in emscripten. We implement approximate behavior here.
|
// QEventLoop::exec() never returns in emscripten. We implement approximate behavior here.
|
||||||
// QTBUG-70185
|
// QTBUG-70185
|
||||||
if (d->threadData->loopLevel == 1) {
|
if (threadData->loopLevel == 1) {
|
||||||
emscripten_force_exit(returnCode);
|
emscripten_force_exit(returnCode);
|
||||||
} else {
|
} else {
|
||||||
d->inExec = false;
|
d->inExec = false;
|
||||||
--d->threadData->loopLevel;
|
--threadData->loopLevel;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -316,9 +324,10 @@ bool QEventLoop::isRunning() const
|
|||||||
void QEventLoop::wakeUp()
|
void QEventLoop::wakeUp()
|
||||||
{
|
{
|
||||||
Q_D(QEventLoop);
|
Q_D(QEventLoop);
|
||||||
if (!d->threadData->hasEventDispatcher())
|
auto threadData = d->threadData.loadAcquire();
|
||||||
|
if (!threadData->hasEventDispatcher())
|
||||||
return;
|
return;
|
||||||
d->threadData->eventDispatcher.loadRelaxed()->wakeUp();
|
threadData->eventDispatcher.loadRelaxed()->wakeUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -212,11 +212,12 @@ QObjectPrivate::QObjectPrivate(int version)
|
|||||||
|
|
||||||
QObjectPrivate::~QObjectPrivate()
|
QObjectPrivate::~QObjectPrivate()
|
||||||
{
|
{
|
||||||
|
auto thisThreadData = threadData.loadRelaxed();
|
||||||
if (extraData && !extraData->runningTimers.isEmpty()) {
|
if (extraData && !extraData->runningTimers.isEmpty()) {
|
||||||
if (Q_LIKELY(threadData->thread.loadAcquire() == QThread::currentThread())) {
|
if (Q_LIKELY(thisThreadData->thread.loadAcquire() == QThread::currentThread())) {
|
||||||
// unregister pending timers
|
// unregister pending timers
|
||||||
if (threadData->hasEventDispatcher())
|
if (thisThreadData->hasEventDispatcher())
|
||||||
threadData->eventDispatcher.loadRelaxed()->unregisterTimers(q_ptr);
|
thisThreadData->eventDispatcher.loadRelaxed()->unregisterTimers(q_ptr);
|
||||||
|
|
||||||
// release the timer ids back to the pool
|
// release the timer ids back to the pool
|
||||||
for (int i = 0; i < extraData->runningTimers.size(); ++i)
|
for (int i = 0; i < extraData->runningTimers.size(); ++i)
|
||||||
@ -229,7 +230,7 @@ QObjectPrivate::~QObjectPrivate()
|
|||||||
if (postedEvents)
|
if (postedEvents)
|
||||||
QCoreApplication::removePostedEvents(q_ptr, 0);
|
QCoreApplication::removePostedEvents(q_ptr, 0);
|
||||||
|
|
||||||
threadData->deref();
|
thisThreadData->deref();
|
||||||
|
|
||||||
if (metaObject) metaObject->objectDestroyed(q_ptr);
|
if (metaObject) metaObject->objectDestroyed(q_ptr);
|
||||||
|
|
||||||
@ -920,11 +921,12 @@ QObject::QObject(QObjectPrivate &dd, QObject *parent)
|
|||||||
|
|
||||||
Q_D(QObject);
|
Q_D(QObject);
|
||||||
d_ptr->q_ptr = this;
|
d_ptr->q_ptr = this;
|
||||||
d->threadData = (parent && !parent->thread()) ? parent->d_func()->threadData : QThreadData::current();
|
auto threadData = (parent && !parent->thread()) ? parent->d_func()->threadData.loadRelaxed() : QThreadData::current();
|
||||||
d->threadData->ref();
|
threadData->ref();
|
||||||
|
d->threadData.storeRelaxed(threadData);
|
||||||
if (parent) {
|
if (parent) {
|
||||||
QT_TRY {
|
QT_TRY {
|
||||||
if (!check_parent_thread(parent, parent ? parent->d_func()->threadData : 0, d->threadData))
|
if (!check_parent_thread(parent, parent ? parent->d_func()->threadData.loadRelaxed() : 0, threadData))
|
||||||
parent = 0;
|
parent = 0;
|
||||||
if (d->isWidget) {
|
if (d->isWidget) {
|
||||||
if (parent) {
|
if (parent) {
|
||||||
@ -936,7 +938,7 @@ QObject::QObject(QObjectPrivate &dd, QObject *parent)
|
|||||||
setParent(parent);
|
setParent(parent);
|
||||||
}
|
}
|
||||||
} QT_CATCH(...) {
|
} QT_CATCH(...) {
|
||||||
d->threadData->deref();
|
threadData->deref();
|
||||||
QT_RETHROW;
|
QT_RETHROW;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1320,7 +1322,7 @@ bool QObject::event(QEvent *e)
|
|||||||
|
|
||||||
case QEvent::ThreadChange: {
|
case QEvent::ThreadChange: {
|
||||||
Q_D(QObject);
|
Q_D(QObject);
|
||||||
QThreadData *threadData = d->threadData;
|
QThreadData *threadData = d->threadData.loadRelaxed();
|
||||||
QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher.loadRelaxed();
|
QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher.loadRelaxed();
|
||||||
if (eventDispatcher) {
|
if (eventDispatcher) {
|
||||||
QList<QAbstractEventDispatcher::TimerInfo> timers = eventDispatcher->registeredTimers(this);
|
QList<QAbstractEventDispatcher::TimerInfo> timers = eventDispatcher->registeredTimers(this);
|
||||||
@ -1487,7 +1489,7 @@ bool QObject::blockSignals(bool block) noexcept
|
|||||||
*/
|
*/
|
||||||
QThread *QObject::thread() const
|
QThread *QObject::thread() const
|
||||||
{
|
{
|
||||||
return d_func()->threadData->thread.loadAcquire();
|
return d_func()->threadData.loadRelaxed()->thread.loadAcquire();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -1534,7 +1536,7 @@ void QObject::moveToThread(QThread *targetThread)
|
|||||||
{
|
{
|
||||||
Q_D(QObject);
|
Q_D(QObject);
|
||||||
|
|
||||||
if (d->threadData->thread.loadAcquire() == targetThread) {
|
if (d->threadData.loadRelaxed()->thread.loadAcquire() == targetThread) {
|
||||||
// object is already in this thread
|
// object is already in this thread
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1550,13 +1552,14 @@ void QObject::moveToThread(QThread *targetThread)
|
|||||||
|
|
||||||
QThreadData *currentData = QThreadData::current();
|
QThreadData *currentData = QThreadData::current();
|
||||||
QThreadData *targetData = targetThread ? QThreadData::get2(targetThread) : nullptr;
|
QThreadData *targetData = targetThread ? QThreadData::get2(targetThread) : nullptr;
|
||||||
if (d->threadData->thread.loadAcquire() == 0 && currentData == targetData) {
|
QThreadData *thisThreadData = d->threadData.loadRelaxed();
|
||||||
|
if (!thisThreadData->thread.loadAcquire() && currentData == targetData) {
|
||||||
// one exception to the rule: we allow moving objects with no thread affinity to the current thread
|
// one exception to the rule: we allow moving objects with no thread affinity to the current thread
|
||||||
currentData = d->threadData;
|
currentData = d->threadData;
|
||||||
} else if (d->threadData != currentData) {
|
} else if (thisThreadData != currentData) {
|
||||||
qWarning("QObject::moveToThread: Current thread (%p) is not the object's thread (%p).\n"
|
qWarning("QObject::moveToThread: Current thread (%p) is not the object's thread (%p).\n"
|
||||||
"Cannot move to target thread (%p)\n",
|
"Cannot move to target thread (%p)\n",
|
||||||
currentData->thread.loadRelaxed(), d->threadData->thread.loadRelaxed(), targetData ? targetData->thread.loadRelaxed() : nullptr);
|
currentData->thread.loadRelaxed(), thisThreadData->thread.loadRelaxed(), targetData ? targetData->thread.loadRelaxed() : nullptr);
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
qWarning("You might be loading two sets of Qt binaries into the same process. "
|
qWarning("You might be loading two sets of Qt binaries into the same process. "
|
||||||
@ -1653,8 +1656,10 @@ void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData
|
|||||||
|
|
||||||
// set new thread data
|
// set new thread data
|
||||||
targetData->ref();
|
targetData->ref();
|
||||||
threadData->deref();
|
threadData.loadRelaxed()->deref();
|
||||||
threadData = targetData;
|
|
||||||
|
// synchronizes with loadAcquire e.g. in QCoreApplication::postEvent
|
||||||
|
threadData.storeRelease(targetData);
|
||||||
|
|
||||||
for (int i = 0; i < children.size(); ++i) {
|
for (int i = 0; i < children.size(); ++i) {
|
||||||
QObject *child = children.at(i);
|
QObject *child = children.at(i);
|
||||||
@ -1666,7 +1671,7 @@ void QObjectPrivate::_q_reregisterTimers(void *pointer)
|
|||||||
{
|
{
|
||||||
Q_Q(QObject);
|
Q_Q(QObject);
|
||||||
QList<QAbstractEventDispatcher::TimerInfo> *timerList = reinterpret_cast<QList<QAbstractEventDispatcher::TimerInfo> *>(pointer);
|
QList<QAbstractEventDispatcher::TimerInfo> *timerList = reinterpret_cast<QList<QAbstractEventDispatcher::TimerInfo> *>(pointer);
|
||||||
QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher.loadRelaxed();
|
QAbstractEventDispatcher *eventDispatcher = threadData.loadRelaxed()->eventDispatcher.loadRelaxed();
|
||||||
for (int i = 0; i < timerList->size(); ++i) {
|
for (int i = 0; i < timerList->size(); ++i) {
|
||||||
const QAbstractEventDispatcher::TimerInfo &ti = timerList->at(i);
|
const QAbstractEventDispatcher::TimerInfo &ti = timerList->at(i);
|
||||||
eventDispatcher->registerTimer(ti.timerId, ti.interval, ti.timerType, q);
|
eventDispatcher->registerTimer(ti.timerId, ti.interval, ti.timerType, q);
|
||||||
@ -1724,7 +1729,9 @@ int QObject::startTimer(int interval, Qt::TimerType timerType)
|
|||||||
qWarning("QObject::startTimer: Timers cannot have negative intervals");
|
qWarning("QObject::startTimer: Timers cannot have negative intervals");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (Q_UNLIKELY(!d->threadData->hasEventDispatcher())) {
|
|
||||||
|
auto thisThreadData = d->threadData.loadRelaxed();
|
||||||
|
if (Q_UNLIKELY(!thisThreadData->hasEventDispatcher())) {
|
||||||
qWarning("QObject::startTimer: Timers can only be used with threads started with QThread");
|
qWarning("QObject::startTimer: Timers can only be used with threads started with QThread");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1732,7 +1739,7 @@ int QObject::startTimer(int interval, Qt::TimerType timerType)
|
|||||||
qWarning("QObject::startTimer: Timers cannot be started from another thread");
|
qWarning("QObject::startTimer: Timers cannot be started from another thread");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int timerId = d->threadData->eventDispatcher.loadRelaxed()->registerTimer(interval, timerType, this);
|
int timerId = thisThreadData->eventDispatcher.loadRelaxed()->registerTimer(interval, timerType, this);
|
||||||
if (!d->extraData)
|
if (!d->extraData)
|
||||||
d->extraData = new QObjectPrivate::ExtraData;
|
d->extraData = new QObjectPrivate::ExtraData;
|
||||||
d->extraData->runningTimers.append(timerId);
|
d->extraData->runningTimers.append(timerId);
|
||||||
@ -1806,8 +1813,9 @@ void QObject::killTimer(int id)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (d->threadData->hasEventDispatcher())
|
auto thisThreadData = d->threadData.loadRelaxed();
|
||||||
d->threadData->eventDispatcher.loadRelaxed()->unregisterTimer(id);
|
if (thisThreadData->hasEventDispatcher())
|
||||||
|
thisThreadData->eventDispatcher.loadRelaxed()->unregisterTimer(id);
|
||||||
|
|
||||||
d->extraData->runningTimers.remove(at);
|
d->extraData->runningTimers.remove(at);
|
||||||
QAbstractEventDispatcherPrivate::releaseTimerId(id);
|
QAbstractEventDispatcherPrivate::releaseTimerId(id);
|
||||||
@ -3774,7 +3782,7 @@ void doActivate(QObject *sender, int signal_index, void **argv)
|
|||||||
list = &signalVector->at(-1);
|
list = &signalVector->at(-1);
|
||||||
|
|
||||||
Qt::HANDLE currentThreadId = QThread::currentThreadId();
|
Qt::HANDLE currentThreadId = QThread::currentThreadId();
|
||||||
bool inSenderThread = currentThreadId == QObjectPrivate::get(sender)->threadData->threadId.loadRelaxed();
|
bool inSenderThread = currentThreadId == QObjectPrivate::get(sender)->threadData.loadRelaxed()->threadId.loadRelaxed();
|
||||||
|
|
||||||
// We need to check against the highest connection id to ensure that signals added
|
// We need to check against the highest connection id to ensure that signals added
|
||||||
// during the signal emission are not emitted in this emission.
|
// during the signal emission are not emitted in this emission.
|
||||||
|
@ -374,8 +374,13 @@ public:
|
|||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
ExtraData *extraData; // extra data set by the user
|
ExtraData *extraData; // extra data set by the user
|
||||||
QThreadData *getThreadData() const { return threadData; }
|
QThreadData *getThreadData() const { return threadData.loadAcquire(); }
|
||||||
QThreadData *threadData; // id of the thread that owns the object
|
// This atomic requires acquire/release semantics in a few places,
|
||||||
|
// e.g. QObject::moveToThread must synchronize with QCoreApplication::postEvent,
|
||||||
|
// because postEvent is thread-safe.
|
||||||
|
// However, most of the code paths involving QObject are only reentrant and
|
||||||
|
// not thread-safe, so synchronization should not be necessary there.
|
||||||
|
QAtomicPointer<QThreadData> threadData; // id of the thread that owns the object
|
||||||
|
|
||||||
using ConnectionDataPointer = QExplicitlySharedDataPointer<ConnectionData>;
|
using ConnectionDataPointer = QExplicitlySharedDataPointer<ConnectionData>;
|
||||||
QAtomicPointer<ConnectionData> connections;
|
QAtomicPointer<ConnectionData> connections;
|
||||||
|
@ -147,12 +147,14 @@ QSocketNotifier::QSocketNotifier(qintptr socket, Type type, QObject *parent)
|
|||||||
d->sntype = type;
|
d->sntype = type;
|
||||||
d->snenabled = true;
|
d->snenabled = true;
|
||||||
|
|
||||||
|
auto thisThreadData = d->threadData.loadRelaxed();
|
||||||
|
|
||||||
if (socket < 0)
|
if (socket < 0)
|
||||||
qWarning("QSocketNotifier: Invalid socket specified");
|
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");
|
qWarning("QSocketNotifier: Can only be used with threads started with QThread");
|
||||||
else
|
else
|
||||||
d->threadData->eventDispatcher.loadRelaxed()->registerSocketNotifier(this);
|
thisThreadData->eventDispatcher.loadRelaxed()->registerSocketNotifier(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -234,16 +236,19 @@ void QSocketNotifier::setEnabled(bool enable)
|
|||||||
return;
|
return;
|
||||||
d->snenabled = enable;
|
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;
|
return;
|
||||||
if (Q_UNLIKELY(thread() != QThread::currentThread())) {
|
if (Q_UNLIKELY(thread() != QThread::currentThread())) {
|
||||||
qWarning("QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread");
|
qWarning("QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (d->snenabled)
|
if (d->snenabled)
|
||||||
d->threadData->eventDispatcher.loadRelaxed()->registerSocketNotifier(this);
|
thisThreadData->eventDispatcher.loadRelaxed()->registerSocketNotifier(this);
|
||||||
else
|
else
|
||||||
d->threadData->eventDispatcher.loadRelaxed()->unregisterSocketNotifier(this);
|
thisThreadData->eventDispatcher.loadRelaxed()->unregisterSocketNotifier(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ QWinEventNotifier::QWinEventNotifier(HANDLE hEvent, QObject *parent)
|
|||||||
: QObject(*new QWinEventNotifierPrivate(hEvent, false), parent)
|
: QObject(*new QWinEventNotifierPrivate(hEvent, false), parent)
|
||||||
{
|
{
|
||||||
Q_D(QWinEventNotifier);
|
Q_D(QWinEventNotifier);
|
||||||
QAbstractEventDispatcher *eventDispatcher = d->threadData->eventDispatcher.loadRelaxed();
|
QAbstractEventDispatcher *eventDispatcher = d->threadData.loadRelaxed()->eventDispatcher.loadRelaxed();
|
||||||
if (Q_UNLIKELY(!eventDispatcher)) {
|
if (Q_UNLIKELY(!eventDispatcher)) {
|
||||||
qWarning("QWinEventNotifier: Can only be used with threads started with QThread");
|
qWarning("QWinEventNotifier: Can only be used with threads started with QThread");
|
||||||
return;
|
return;
|
||||||
@ -197,7 +197,7 @@ void QWinEventNotifier::setEnabled(bool enable)
|
|||||||
return;
|
return;
|
||||||
d->enabled = enable;
|
d->enabled = enable;
|
||||||
|
|
||||||
QAbstractEventDispatcher *eventDispatcher = d->threadData->eventDispatcher.loadRelaxed();
|
QAbstractEventDispatcher *eventDispatcher = d->threadData.loadRelaxed()->eventDispatcher.loadRelaxed();
|
||||||
if (!eventDispatcher) { // perhaps application is shutting down
|
if (!eventDispatcher) { // perhaps application is shutting down
|
||||||
if (!enable && d->waitHandle != nullptr)
|
if (!enable && d->waitHandle != nullptr)
|
||||||
d->unregisterWaitObject();
|
d->unregisterWaitObject();
|
||||||
@ -256,7 +256,7 @@ void QWinEventNotifierPrivate::unregisterWaitObject()
|
|||||||
static void CALLBACK wfsoCallback(void *context, BOOLEAN /*ignore*/)
|
static void CALLBACK wfsoCallback(void *context, BOOLEAN /*ignore*/)
|
||||||
{
|
{
|
||||||
QWinEventNotifierPrivate *nd = reinterpret_cast<QWinEventNotifierPrivate *>(context);
|
QWinEventNotifierPrivate *nd = reinterpret_cast<QWinEventNotifierPrivate *>(context);
|
||||||
QAbstractEventDispatcher *eventDispatcher = nd->threadData->eventDispatcher.loadRelaxed();
|
QAbstractEventDispatcher *eventDispatcher = nd->threadData.loadRelaxed()->eventDispatcher.loadRelaxed();
|
||||||
|
|
||||||
// Happens when Q(Core)Application is destroyed before QWinEventNotifier.
|
// Happens when Q(Core)Application is destroyed before QWinEventNotifier.
|
||||||
// https://bugreports.qt.io/browse/QTBUG-70214
|
// https://bugreports.qt.io/browse/QTBUG-70214
|
||||||
|
@ -116,7 +116,7 @@ public:
|
|||||||
static QAbstractEventDispatcher *qt_qpa_core_dispatcher()
|
static QAbstractEventDispatcher *qt_qpa_core_dispatcher()
|
||||||
{
|
{
|
||||||
if (QCoreApplication::instance())
|
if (QCoreApplication::instance())
|
||||||
return QCoreApplication::instance()->d_func()->threadData->eventDispatcher.loadRelaxed();
|
return QCoreApplication::instance()->d_func()->threadData.loadRelaxed()->eventDispatcher.loadRelaxed();
|
||||||
else
|
else
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -659,7 +659,7 @@ bool QAbstractSocketPrivate::initSocketLayer(QAbstractSocket::NetworkLayerProtoc
|
|||||||
|
|
||||||
configureCreatedSocket();
|
configureCreatedSocket();
|
||||||
|
|
||||||
if (threadData->hasEventDispatcher())
|
if (threadData.loadRelaxed()->hasEventDispatcher())
|
||||||
socketEngine->setReceiver(this);
|
socketEngine->setReceiver(this);
|
||||||
|
|
||||||
#if defined (QABSTRACTSOCKET_DEBUG)
|
#if defined (QABSTRACTSOCKET_DEBUG)
|
||||||
@ -1138,7 +1138,7 @@ void QAbstractSocketPrivate::_q_connectToNextAddress()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start the connect timer.
|
// Start the connect timer.
|
||||||
if (threadData->hasEventDispatcher()) {
|
if (threadData.loadRelaxed()->hasEventDispatcher()) {
|
||||||
if (!connectTimer) {
|
if (!connectTimer) {
|
||||||
connectTimer = new QTimer(q);
|
connectTimer = new QTimer(q);
|
||||||
QObject::connect(connectTimer, SIGNAL(timeout()),
|
QObject::connect(connectTimer, SIGNAL(timeout()),
|
||||||
@ -1740,7 +1740,7 @@ void QAbstractSocket::connectToHost(const QString &hostName, quint16 port,
|
|||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
if (d->threadData->hasEventDispatcher()) {
|
if (d->threadData.loadRelaxed()->hasEventDispatcher()) {
|
||||||
// this internal API for QHostInfo either immediately gives us the desired
|
// this internal API for QHostInfo either immediately gives us the desired
|
||||||
// QHostInfo from cache or later calls the _q_startConnecting slot.
|
// QHostInfo from cache or later calls the _q_startConnecting slot.
|
||||||
bool immediateResultValid = false;
|
bool immediateResultValid = false;
|
||||||
@ -1953,7 +1953,7 @@ bool QAbstractSocket::setSocketDescriptor(qintptr socketDescriptor, SocketState
|
|||||||
|
|
||||||
// Sync up with error string, which open() shall clear.
|
// Sync up with error string, which open() shall clear.
|
||||||
d->socketError = UnknownSocketError;
|
d->socketError = UnknownSocketError;
|
||||||
if (d->threadData->hasEventDispatcher())
|
if (d->threadData.loadRelaxed()->hasEventDispatcher())
|
||||||
d->socketEngine->setReceiver(d);
|
d->socketEngine->setReceiver(d);
|
||||||
|
|
||||||
QIODevice::open(openMode);
|
QIODevice::open(openMode);
|
||||||
|
@ -1341,7 +1341,7 @@ void QNativeSocketEngine::setReadNotificationEnabled(bool enable)
|
|||||||
Q_D(QNativeSocketEngine);
|
Q_D(QNativeSocketEngine);
|
||||||
if (d->readNotifier) {
|
if (d->readNotifier) {
|
||||||
d->readNotifier->setEnabled(enable);
|
d->readNotifier->setEnabled(enable);
|
||||||
} else if (enable && d->threadData->hasEventDispatcher()) {
|
} else if (enable && d->threadData.loadRelaxed()->hasEventDispatcher()) {
|
||||||
d->readNotifier = new QReadNotifier(d->socketDescriptor, this);
|
d->readNotifier = new QReadNotifier(d->socketDescriptor, this);
|
||||||
d->readNotifier->setEnabled(true);
|
d->readNotifier->setEnabled(true);
|
||||||
}
|
}
|
||||||
@ -1358,7 +1358,7 @@ void QNativeSocketEngine::setWriteNotificationEnabled(bool enable)
|
|||||||
Q_D(QNativeSocketEngine);
|
Q_D(QNativeSocketEngine);
|
||||||
if (d->writeNotifier) {
|
if (d->writeNotifier) {
|
||||||
d->writeNotifier->setEnabled(enable);
|
d->writeNotifier->setEnabled(enable);
|
||||||
} else if (enable && d->threadData->hasEventDispatcher()) {
|
} else if (enable && d->threadData.loadRelaxed()->hasEventDispatcher()) {
|
||||||
d->writeNotifier = new QWriteNotifier(d->socketDescriptor, this);
|
d->writeNotifier = new QWriteNotifier(d->socketDescriptor, this);
|
||||||
d->writeNotifier->setEnabled(true);
|
d->writeNotifier->setEnabled(true);
|
||||||
}
|
}
|
||||||
@ -1375,7 +1375,7 @@ void QNativeSocketEngine::setExceptionNotificationEnabled(bool enable)
|
|||||||
Q_D(QNativeSocketEngine);
|
Q_D(QNativeSocketEngine);
|
||||||
if (d->exceptNotifier) {
|
if (d->exceptNotifier) {
|
||||||
d->exceptNotifier->setEnabled(enable);
|
d->exceptNotifier->setEnabled(enable);
|
||||||
} else if (enable && d->threadData->hasEventDispatcher()) {
|
} else if (enable && d->threadData.loadRelaxed()->hasEventDispatcher()) {
|
||||||
d->exceptNotifier = new QExceptionNotifier(d->socketDescriptor, this);
|
d->exceptNotifier = new QExceptionNotifier(d->socketDescriptor, this);
|
||||||
d->exceptNotifier->setEnabled(true);
|
d->exceptNotifier->setEnabled(true);
|
||||||
}
|
}
|
||||||
|
@ -149,7 +149,7 @@ QT_USE_NAMESPACE
|
|||||||
if ([reflectionDelegate respondsToSelector:_cmd])
|
if ([reflectionDelegate respondsToSelector:_cmd])
|
||||||
return [reflectionDelegate applicationShouldTerminate:sender];
|
return [reflectionDelegate applicationShouldTerminate:sender];
|
||||||
|
|
||||||
if (QGuiApplicationPrivate::instance()->threadData->eventLoops.isEmpty()) {
|
if (QGuiApplicationPrivate::instance()->threadData.loadRelaxed()->eventLoops.isEmpty()) {
|
||||||
// No event loop is executing. This probably means that Qt is used as a plugin,
|
// No event loop is executing. This probably means that Qt is used as a plugin,
|
||||||
// or as a part of a native Cocoa application. In any case it should be fine to
|
// or as a part of a native Cocoa application. In any case it should be fine to
|
||||||
// terminate now.
|
// terminate now.
|
||||||
@ -359,7 +359,7 @@ QT_USE_NAMESPACE
|
|||||||
if (!platformItem || platformItem->menu())
|
if (!platformItem || platformItem->menu())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QScopedScopeLevelCounter scopeLevelCounter(QGuiApplicationPrivate::instance()->threadData);
|
QScopedScopeLevelCounter scopeLevelCounter(QGuiApplicationPrivate::instance()->threadData.loadRelaxed());
|
||||||
QGuiApplicationPrivate::modifier_buttons = [QNSView convertKeyModifiers:[NSEvent modifierFlags]];
|
QGuiApplicationPrivate::modifier_buttons = [QNSView convertKeyModifiers:[NSEvent modifierFlags]];
|
||||||
|
|
||||||
static QMetaMethod activatedSignal = QMetaMethod::fromSignal(&QCocoaMenuItem::activated);
|
static QMetaMethod activatedSignal = QMetaMethod::fromSignal(&QCocoaMenuItem::activated);
|
||||||
|
@ -511,7 +511,7 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
|
|||||||
if (hadModalSession && !d->currentModalSessionCached)
|
if (hadModalSession && !d->currentModalSessionCached)
|
||||||
interruptLater = true;
|
interruptLater = true;
|
||||||
}
|
}
|
||||||
bool canWait = (d->threadData->canWait
|
bool canWait = (d->threadData.loadRelaxed()->canWait
|
||||||
&& !retVal
|
&& !retVal
|
||||||
&& !d->interrupt
|
&& !d->interrupt
|
||||||
&& (d->processEventsFlags & QEventLoop::WaitForMoreEvents));
|
&& (d->processEventsFlags & QEventLoop::WaitForMoreEvents));
|
||||||
@ -878,7 +878,7 @@ void QCocoaEventDispatcherPrivate::processPostedEvents()
|
|||||||
}
|
}
|
||||||
|
|
||||||
int serial = serialNumber.loadRelaxed();
|
int serial = serialNumber.loadRelaxed();
|
||||||
if (!threadData->canWait || (serial != lastSerial)) {
|
if (!threadData.loadRelaxed()->canWait || (serial != lastSerial)) {
|
||||||
lastSerial = serial;
|
lastSerial = serial;
|
||||||
QCoreApplication::sendPostedEvents();
|
QCoreApplication::sendPostedEvents();
|
||||||
QWindowSystemInterface::sendWindowSystemEvents(QEventLoop::AllEvents);
|
QWindowSystemInterface::sendWindowSystemEvents(QEventLoop::AllEvents);
|
||||||
|
@ -3660,7 +3660,7 @@ bool QApplicationPrivate::notify_helper(QObject *receiver, QEvent * e)
|
|||||||
|
|
||||||
// send to all application event filters
|
// send to all application event filters
|
||||||
if (threadRequiresCoreApplication()
|
if (threadRequiresCoreApplication()
|
||||||
&& receiver->d_func()->threadData->thread.loadAcquire() == mainThread()
|
&& receiver->d_func()->threadData.loadRelaxed()->thread.loadAcquire() == mainThread()
|
||||||
&& sendThroughApplicationEventFilters(receiver, e)) {
|
&& sendThroughApplicationEventFilters(receiver, e)) {
|
||||||
filtered = true;
|
filtered = true;
|
||||||
return filtered;
|
return filtered;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user