summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
-rw-r--r--src/corelib/thread/qthread.cpp27
-rw-r--r--src/corelib/thread/qthread_p.h10
-rw-r--r--src/network/access/qnetworkreplyhttpimpl.cpp2
-rw-r--r--src/network/bearer/qnetworkconfigmanager_p.cpp3
-rw-r--r--src/platformsupport/input/evdevtablet/qevdevtablet.cpp2
-rw-r--r--src/platformsupport/input/evdevtablet/qevdevtablet_p.h3
-rw-r--r--src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp2
-rw-r--r--src/platformsupport/input/evdevtouch/qevdevtouchhandler_p.h3
-rw-r--r--src/widgets/kernel/qapplication.cpp4
-rw-r--r--tests/auto/corelib/kernel/qcoreapplication/qcoreapplication.pro1
-rw-r--r--tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp50
-rw-r--r--tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.h2
15 files changed, 129 insertions, 12 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);
diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp
index 0c009db930..590479d68c 100644
--- a/src/corelib/thread/qthread.cpp
+++ b/src/corelib/thread/qthread.cpp
@@ -50,7 +50,8 @@ QT_BEGIN_NAMESPACE
QThreadData::QThreadData(int initialRefCount)
: _ref(initialRefCount), loopLevel(0), thread(0), threadId(0),
- eventDispatcher(0), quitNow(false), canWait(true), isAdopted(false)
+ eventDispatcher(0),
+ quitNow(false), canWait(true), isAdopted(false), requiresCoreApplication(true)
{
// fprintf(stderr, "QThreadData %p created\n", this);
}
@@ -867,4 +868,28 @@ bool QThread::isInterruptionRequested() const
return d->interruptionRequested;
}
+/*!
+ \class QDaemonThread
+ \since 5.5
+ \brief The QDaemonThread provides a class to manage threads that outlive QCoreApplication
+ \internal
+
+ Note: don't try to deliver events from the started() signal.
+*/
+static void setThreadDoesNotRequireCoreApplication()
+{
+ QThreadData::current()->requiresCoreApplication = false;
+}
+
+QDaemonThread::QDaemonThread(QObject *parent)
+ : QThread(parent)
+{
+ // QThread::started() is emitted from the thread we start
+ connect(this, &QThread::started, setThreadDoesNotRequireCoreApplication);
+}
+
+QDaemonThread::~QDaemonThread()
+{
+}
+
QT_END_NAMESPACE
diff --git a/src/corelib/thread/qthread_p.h b/src/corelib/thread/qthread_p.h
index 1ecd682ad1..ffefe0b1d1 100644
--- a/src/corelib/thread/qthread_p.h
+++ b/src/corelib/thread/qthread_p.h
@@ -135,6 +135,13 @@ private:
#ifndef QT_NO_THREAD
+class Q_CORE_EXPORT QDaemonThread : public QThread
+{
+public:
+ QDaemonThread(QObject *parent = 0);
+ ~QDaemonThread();
+};
+
class QThreadPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QThread)
@@ -224,7 +231,7 @@ public:
QThreadData(int initialRefCount = 1);
~QThreadData();
- static QThreadData *current(bool createIfNecessary = true);
+ static Q_AUTOTEST_EXPORT QThreadData *current(bool createIfNecessary = true);
static void clearCurrentThreadData();
static QThreadData *get2(QThread *thread)
{ Q_ASSERT_X(thread != 0, "QThread", "internal error"); return thread->d_func()->data; }
@@ -278,6 +285,7 @@ public:
bool quitNow;
bool canWait;
bool isAdopted;
+ bool requiresCoreApplication;
};
class QScopedLoopLevelCounter
diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp
index c08648c47b..8c0c098147 100644
--- a/src/network/access/qnetworkreplyhttpimpl.cpp
+++ b/src/network/access/qnetworkreplyhttpimpl.cpp
@@ -49,6 +49,8 @@
#include "qthread.h"
#include "QtCore/qcoreapplication.h"
+#include <QtCore/private/qthread_p.h>
+
#include "qnetworkcookiejar.h"
#ifndef QT_NO_HTTP
diff --git a/src/network/bearer/qnetworkconfigmanager_p.cpp b/src/network/bearer/qnetworkconfigmanager_p.cpp
index c1e837de7b..78d4970ca1 100644
--- a/src/network/bearer/qnetworkconfigmanager_p.cpp
+++ b/src/network/bearer/qnetworkconfigmanager_p.cpp
@@ -41,6 +41,7 @@
#include <QtCore/qstringlist.h>
#include <QtCore/qthread.h>
#include <QtCore/private/qcoreapplication_p.h>
+#include <QtCore/private/qthread_p.h>
#ifndef QT_NO_BEARERMANAGEMENT
@@ -61,7 +62,7 @@ QNetworkConfigurationManagerPrivate::QNetworkConfigurationManagerPrivate()
void QNetworkConfigurationManagerPrivate::initialize()
{
//Two stage construction, because we only want to do this heavyweight work for the winner of the Q_GLOBAL_STATIC race.
- bearerThread = new QThread();
+ bearerThread = new QDaemonThread();
bearerThread->setObjectName(QStringLiteral("Qt bearer thread"));
bearerThread->moveToThread(QCoreApplicationPrivate::mainThread()); // because cleanup() is called in main thread context.
diff --git a/src/platformsupport/input/evdevtablet/qevdevtablet.cpp b/src/platformsupport/input/evdevtablet/qevdevtablet.cpp
index c59f0f390a..c6f952c64d 100644
--- a/src/platformsupport/input/evdevtablet/qevdevtablet.cpp
+++ b/src/platformsupport/input/evdevtablet/qevdevtablet.cpp
@@ -292,7 +292,7 @@ void QEvdevTabletHandler::readData()
QEvdevTabletHandlerThread::QEvdevTabletHandlerThread(const QString &spec, QObject *parent)
- : QThread(parent), m_spec(spec), m_handler(0)
+ : QDaemonThread(parent), m_spec(spec), m_handler(0)
{
start();
}
diff --git a/src/platformsupport/input/evdevtablet/qevdevtablet_p.h b/src/platformsupport/input/evdevtablet/qevdevtablet_p.h
index f9682290d9..f546f9a88a 100644
--- a/src/platformsupport/input/evdevtablet/qevdevtablet_p.h
+++ b/src/platformsupport/input/evdevtablet/qevdevtablet_p.h
@@ -48,6 +48,7 @@
#include <QObject>
#include <QString>
#include <QThread>
+#include <QtCore/private/qthread_p.h>
QT_BEGIN_NAMESPACE
@@ -68,7 +69,7 @@ private:
QEvdevTabletData *d;
};
-class QEvdevTabletHandlerThread : public QThread
+class QEvdevTabletHandlerThread : public QDaemonThread
{
public:
explicit QEvdevTabletHandlerThread(const QString &spec, QObject *parent = 0);
diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp b/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp
index 1556be5cc1..1ca95074b9 100644
--- a/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp
+++ b/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp
@@ -642,7 +642,7 @@ void QEvdevTouchScreenData::reportPoints()
QEvdevTouchScreenHandlerThread::QEvdevTouchScreenHandlerThread(const QString &device, const QString &spec, QObject *parent)
- : QThread(parent), m_device(device), m_spec(spec), m_handler(0)
+ : QDaemonThread(parent), m_device(device), m_spec(spec), m_handler(0)
{
start();
}
diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchhandler_p.h b/src/platformsupport/input/evdevtouch/qevdevtouchhandler_p.h
index a6d3a860f5..8e7dfe59bb 100644
--- a/src/platformsupport/input/evdevtouch/qevdevtouchhandler_p.h
+++ b/src/platformsupport/input/evdevtouch/qevdevtouchhandler_p.h
@@ -49,6 +49,7 @@
#include <QString>
#include <QList>
#include <QThread>
+#include <QtCore/private/qthread_p.h>
#include <qpa/qwindowsysteminterface.h>
#if !defined(QT_NO_MTDEV)
@@ -80,7 +81,7 @@ private:
#endif
};
-class QEvdevTouchScreenHandlerThread : public QThread
+class QEvdevTouchScreenHandlerThread : public QDaemonThread
{
public:
explicit QEvdevTouchScreenHandlerThread(const QString &device, const QString &spec, QObject *parent = 0);
diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp
index 504932dc53..f82fac836a 100644
--- a/src/widgets/kernel/qapplication.cpp
+++ b/src/widgets/kernel/qapplication.cpp
@@ -3688,7 +3688,9 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
bool QApplicationPrivate::notify_helper(QObject *receiver, QEvent * e)
{
// send to all application event filters
- if (sendThroughApplicationEventFilters(receiver, e))
+ if (threadRequiresCoreApplication()
+ && receiver->d_func()->threadData->thread == mainThread()
+ && sendThroughApplicationEventFilters(receiver, e))
return true;
if (receiver->isWidgetType()) {
diff --git a/tests/auto/corelib/kernel/qcoreapplication/qcoreapplication.pro b/tests/auto/corelib/kernel/qcoreapplication/qcoreapplication.pro
index 0602b9fc38..1039f2c08d 100644
--- a/tests/auto/corelib/kernel/qcoreapplication/qcoreapplication.pro
+++ b/tests/auto/corelib/kernel/qcoreapplication/qcoreapplication.pro
@@ -3,3 +3,4 @@ TARGET = tst_qcoreapplication
QT = core testlib core-private
SOURCES = tst_qcoreapplication.cpp
HEADERS = tst_qcoreapplication.h
+requires(contains(QT_CONFIG,private_tests))
diff --git a/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp b/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp
index efecf31d66..696a1c4722 100644
--- a/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp
+++ b/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp
@@ -78,6 +78,21 @@ public:
}
};
+class Thread : public QDaemonThread
+{
+ void run() Q_DECL_OVERRIDE
+ {
+ QThreadData *data = QThreadData::current();
+ QVERIFY(!data->requiresCoreApplication); // daemon thread
+ data->requiresCoreApplication = requiresCoreApplication;
+ QThread::run();
+ }
+
+public:
+ Thread() : requiresCoreApplication(true) {}
+ bool requiresCoreApplication;
+};
+
void tst_QCoreApplication::sendEventsOnProcessEvents()
{
int argc = 1;
@@ -853,6 +868,41 @@ void tst_QCoreApplication::applicationEventFilters_auxThread()
QVERIFY(!spy.recordedEvents.contains(QEvent::User + 1));
}
+void tst_QCoreApplication::threadedEventDelivery_data()
+{
+ QTest::addColumn<bool>("requiresCoreApplication");
+ QTest::addColumn<bool>("createCoreApplication");
+ QTest::addColumn<bool>("eventsReceived");
+
+ // invalid combination:
+ //QTest::newRow("default-without-coreapp") << true << false << false;
+ QTest::newRow("default") << true << true << true;
+ QTest::newRow("independent-without-coreapp") << false << false << true;
+ QTest::newRow("independent-with-coreapp") << false << true << true;
+}
+
+// posts the event before the QCoreApplication is destroyed, starts thread after
+void tst_QCoreApplication::threadedEventDelivery()
+{
+ QFETCH(bool, requiresCoreApplication);
+ QFETCH(bool, createCoreApplication);
+ QFETCH(bool, eventsReceived);
+
+ int argc = 1;
+ char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
+ QScopedPointer<TestApplication> app(createCoreApplication ? new TestApplication(argc, argv) : 0);
+
+ Thread thread;
+ thread.requiresCoreApplication = requiresCoreApplication;
+ ThreadedEventReceiver receiver;
+ receiver.moveToThread(&thread);
+ QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User + 1)));
+
+ thread.start();
+ QVERIFY(thread.wait(1000));
+ QCOMPARE(receiver.recordedEvents.contains(QEvent::User + 1), eventsReceived);
+}
+
static void createQObjectOnDestruction()
{
// Make sure that we can create a QObject after the last QObject has been
diff --git a/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.h b/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.h
index 09e15723ac..8efe374a2b 100644
--- a/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.h
+++ b/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.h
@@ -61,6 +61,8 @@ private slots:
void QTBUG31606_QEventDestructorDeadLock();
void applicationEventFilters_mainThread();
void applicationEventFilters_auxThread();
+ void threadedEventDelivery_data();
+ void threadedEventDelivery();
};
#endif // TST_QCOREAPPLICATION_H