summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2015-04-16 17:21:37 -0700
committerThiago Macieira <thiago.macieira@intel.com>2015-07-18 02:24:59 +0000
commit10c529b08de7cd55b4c3e3654464119246498273 (patch)
treeb2ebe0a8bc1cef7767817b20cf88cda41d6df6c2 /src/corelib/kernel
parent9d98584a835962ca7ad870bbede8f6ab7f66b6bf (diff)
Add a way for auxiliary threads to handle events without CoreApp
Long-lived threads started by Qt itself can now receive events even if QCoreApplication hasn't been created. This is required in all threads we start that will handle events, unless we're sure that the thread will exit before the global application object begins destruction. Otherwise, those threads will have race conditions dealing with the event delivery system trying to call the QCoreApplication::notify() virtual while the object is being destroyed. Change-Id: I27eaacb532114dd188c4ffff13d4ad2a4bb443e6 Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
Diffstat (limited to 'src/corelib/kernel')
-rw-r--r--src/corelib/kernel/qcoreapplication.cpp28
-rw-r--r--src/corelib/kernel/qcoreapplication_p.h2
-rw-r--r--src/corelib/kernel/qeventloop.cpp2
3 files changed, 28 insertions, 4 deletions
diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
index e47dc0dff2..9ad7970807 100644
--- a/src/corelib/kernel/qcoreapplication.cpp
+++ b/src/corelib/kernel/qcoreapplication.cpp
@@ -538,6 +538,14 @@ QThread *QCoreApplicationPrivate::mainThread()
return theMainThread;
}
+bool QCoreApplicationPrivate::threadRequiresCoreApplication()
+{
+ QThreadData *data = QThreadData::current(false);
+ if (!data)
+ return true; // default setting
+ return data->requiresCoreApplication;
+}
+
void QCoreApplicationPrivate::checkReceiverThread(QObject *receiver)
{
QThread *currentThread = QThread::currentThread();
@@ -926,6 +934,8 @@ bool QCoreApplication::isQuitLockEnabled()
return quitLockRefEnabled;
}
+static bool doNotify(QObject *, QEvent *);
+
/*!
Enables the ability of the QEventLoopLocker feature to quit
the application.
@@ -960,7 +970,8 @@ bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event)
*/
bool QCoreApplication::notifyInternal2(QObject *receiver, QEvent *event)
{
- if (!self)
+ bool selfRequired = QCoreApplicationPrivate::threadRequiresCoreApplication();
+ if (!self && selfRequired)
return false;
// Make it possible for Qt Script to hook into events even
@@ -978,6 +989,8 @@ bool QCoreApplication::notifyInternal2(QObject *receiver, QEvent *event)
QObjectPrivate *d = receiver->d_func();
QThreadData *threadData = d->threadData;
QScopedLoopLevelCounter loopLevelCounter(threadData);
+ if (!selfRequired)
+ return doNotify(receiver, event);
return self->notify(receiver, event);
}
@@ -1039,7 +1052,11 @@ bool QCoreApplication::notify(QObject *receiver, QEvent *event)
// no events are delivered after ~QCoreApplication() has started
if (QCoreApplicationPrivate::is_app_closing)
return true;
+ return doNotify(receiver, event);
+}
+static bool doNotify(QObject *receiver, QEvent *event)
+{
if (receiver == 0) { // serious error
qWarning("QCoreApplication::notify: Unexpected null receiver");
return true;
@@ -1054,7 +1071,10 @@ bool QCoreApplication::notify(QObject *receiver, QEvent *event)
bool QCoreApplicationPrivate::sendThroughApplicationEventFilters(QObject *receiver, QEvent *event)
{
- if (receiver->d_func()->threadData == this->threadData && extraData) {
+ // We can't access the application event filters outside of the main thread (race conditions)
+ Q_ASSERT(receiver->d_func()->threadData->thread == mainThread());
+
+ if (extraData) {
// application event filters are only called for objects in the GUI thread
for (int i = 0; i < extraData->eventFilters.size(); ++i) {
QObject *obj = extraData->eventFilters.at(i);
@@ -1097,7 +1117,9 @@ bool QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject *receiver, Q
bool QCoreApplicationPrivate::notify_helper(QObject *receiver, QEvent * event)
{
// send to all application event filters (only does anything in the main thread)
- if (QCoreApplication::self->d_func()->sendThroughApplicationEventFilters(receiver, event))
+ if (QCoreApplication::self
+ && receiver->d_func()->threadData->thread == mainThread()
+ && QCoreApplication::self->d_func()->sendThroughApplicationEventFilters(receiver, event))
return true;
// send to all receiver event filters
if (sendThroughObjectEventFilters(receiver, event))
diff --git a/src/corelib/kernel/qcoreapplication_p.h b/src/corelib/kernel/qcoreapplication_p.h
index 5fed850c2b..21f59d8197 100644
--- a/src/corelib/kernel/qcoreapplication_p.h
+++ b/src/corelib/kernel/qcoreapplication_p.h
@@ -107,6 +107,8 @@ public:
static QThread *theMainThread;
static QThread *mainThread();
+ static bool threadRequiresCoreApplication();
+
static void sendPostedEvents(QObject *receiver, int event_type, QThreadData *data);
static void checkReceiverThread(QObject *receiver);
diff --git a/src/corelib/kernel/qeventloop.cpp b/src/corelib/kernel/qeventloop.cpp
index 1723db0ab9..dca25ce968 100644
--- a/src/corelib/kernel/qeventloop.cpp
+++ b/src/corelib/kernel/qeventloop.cpp
@@ -93,7 +93,7 @@ QEventLoop::QEventLoop(QObject *parent)
: QObject(*new QEventLoopPrivate, parent)
{
Q_D(QEventLoop);
- if (!QCoreApplication::instance()) {
+ if (!QCoreApplication::instance() && QCoreApplicationPrivate::threadRequiresCoreApplication()) {
qWarning("QEventLoop: Cannot be used without QApplication");
} else if (!d->threadData->eventDispatcher.load()) {
QThreadPrivate::createEventDispatcher(d->threadData);