summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMÃ¥rten Nordheim <marten.nordheim@qt.io>2021-03-05 14:33:01 +0100
committerQt CI Bot <qt_ci_bot@qt-project.org>2021-03-11 13:31:17 +0000
commitd76c0e3224e5945e68f5e41b5346aed48e70850b (patch)
tree7d3b83819db6fada3a033828e4596bca58828418
parent3102d611bded33a5c15f63ece9e6f2eeb5940818 (diff)
parentf274f91cebb0a4fd2ebe37bb3a605c47d6acd404 (diff)
Merge "QEventDispatcher(Win): Always honor interrupted status to avoid races"
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_kernel_qdeadlinetimer.cpp2
-rw-r--r--src/corelib/kernel/qeventdispatcher_win.cpp6
-rw-r--r--tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp27
-rw-r--r--tests/auto/gui/kernel/qshortcut/tst_qshortcut.cpp1
-rw-r--r--tests/auto/gui/qopengl/tst_qopengl.cpp3
-rw-r--r--tests/auto/widgets/dialogs/qdialog/tst_qdialog.cpp3
6 files changed, 39 insertions, 3 deletions
diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qdeadlinetimer.cpp b/src/corelib/doc/snippets/code/src_corelib_kernel_qdeadlinetimer.cpp
index 35c06f842e..5858b6a78d 100644
--- a/src/corelib/doc/snippets/code/src_corelib_kernel_qdeadlinetimer.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qdeadlinetimer.cpp
@@ -53,7 +53,7 @@
{
QDeadlineTimer deadline(msecs);
do {
- if (readFromDevice(deadline.remainingTime())
+ if (readFromDevice(deadline.remainingTime()))
break;
waitForReadyRead(deadline);
} while (!deadline.hasExpired());
diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp
index 19604de32f..80297feef1 100644
--- a/src/corelib/kernel/qeventdispatcher_win.cpp
+++ b/src/corelib/kernel/qeventdispatcher_win.cpp
@@ -475,13 +475,17 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
{
Q_D(QEventDispatcherWin32);
- d->interrupt.storeRelaxed(false);
+ // We don't know _when_ the interrupt occurred so we have to honor it.
+ const bool wasInterrupted = d->interrupt.fetchAndStoreRelaxed(false);
emit awake();
// To prevent livelocks, send posted events once per iteration.
// QCoreApplication::sendPostedEvents() takes care about recursions.
sendPostedEvents();
+ if (wasInterrupted)
+ return false;
+
auto threadData = d->threadData.loadRelaxed();
bool canWait;
bool retVal = false;
diff --git a/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp b/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp
index 8d69314fa5..21aee94e5d 100644
--- a/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp
+++ b/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp
@@ -71,6 +71,7 @@ private slots:
void processEventsOnlySendsQueuedEvents();
void postedEventsPingPong();
void eventLoopExit();
+ void interruptTrampling();
};
bool tst_QEventDispatcher::event(QEvent *e)
@@ -421,5 +422,31 @@ void tst_QEventDispatcher::eventLoopExit()
QVERIFY(!timeoutObserved);
}
+// Based on QTBUG-91539: In the event dispatcher on Windows we overwrite the
+// interrupt once we start processing events (this pattern is also in the 'unix' dispatcher)
+// which would lead the dispatcher to accidentally ignore certain interrupts and,
+// as in the bug report, would not quit, leaving the thread alive and running.
+void tst_QEventDispatcher::interruptTrampling()
+{
+ class WorkerThread : public QThread
+ {
+ void run() override {
+ auto dispatcher = eventDispatcher();
+ QVERIFY(dispatcher);
+ dispatcher->processEvents(QEventLoop::AllEvents);
+ QTimer::singleShot(0, [dispatcher]() {
+ dispatcher->wakeUp();
+ });
+ dispatcher->processEvents(QEventLoop::WaitForMoreEvents);
+ dispatcher->interrupt();
+ dispatcher->processEvents(QEventLoop::WaitForMoreEvents);
+ }
+ };
+ WorkerThread thread;
+ thread.start();
+ QVERIFY(thread.wait(1000));
+ QVERIFY(thread.isFinished());
+}
+
QTEST_MAIN(tst_QEventDispatcher)
#include "tst_qeventdispatcher.moc"
diff --git a/tests/auto/gui/kernel/qshortcut/tst_qshortcut.cpp b/tests/auto/gui/kernel/qshortcut/tst_qshortcut.cpp
index fc230f98e2..777f486263 100644
--- a/tests/auto/gui/kernel/qshortcut/tst_qshortcut.cpp
+++ b/tests/auto/gui/kernel/qshortcut/tst_qshortcut.cpp
@@ -74,6 +74,7 @@ void tst_QShortcut::trigger()
new QShortcut(Qt::CTRL | Qt::Key_Q, &w, SLOT(close()));
w.show();
QVERIFY(QTest::qWaitForWindowExposed(&w));
+ QTRY_VERIFY(QGuiApplication::applicationState() == Qt::ApplicationActive);
sendKey(&w, Qt::Key_Q, 'q', Qt::ControlModifier);
QTRY_VERIFY(!w.isVisible());
}
diff --git a/tests/auto/gui/qopengl/tst_qopengl.cpp b/tests/auto/gui/qopengl/tst_qopengl.cpp
index 9e66ec9a43..e2e7f153a0 100644
--- a/tests/auto/gui/qopengl/tst_qopengl.cpp
+++ b/tests/auto/gui/qopengl/tst_qopengl.cpp
@@ -1480,6 +1480,9 @@ void tst_QOpenGL::glxContextWrap()
if (QGuiApplication::platformName().startsWith(QLatin1String("offscreen"), Qt::CaseInsensitive))
QSKIP("Offscreen: This fails.");
+ if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
+ QSKIP("Fails on Wayland.");
+
QWindow *window = new QWindow;
window->setSurfaceType(QWindow::OpenGLSurface);
window->setGeometry(0, 0, 10, 10);
diff --git a/tests/auto/widgets/dialogs/qdialog/tst_qdialog.cpp b/tests/auto/widgets/dialogs/qdialog/tst_qdialog.cpp
index 53c33255bf..6a59edca10 100644
--- a/tests/auto/widgets/dialogs/qdialog/tst_qdialog.cpp
+++ b/tests/auto/widgets/dialogs/qdialog/tst_qdialog.cpp
@@ -552,10 +552,11 @@ void tst_QDialog::keepPositionOnClose()
dialog.setWindowTitle(QTest::currentTestFunction());
const QRect availableGeometry = QGuiApplication::primaryScreen()->availableGeometry();
dialog.resize(availableGeometry.size() / 4);
- const QPoint pos = availableGeometry.topLeft() + QPoint(100, 100);
+ QPoint pos = availableGeometry.topLeft() + QPoint(100, 100);
dialog.move(pos);
dialog.show();
QVERIFY(QTest::qWaitForWindowExposed(&dialog));
+ pos = dialog.pos();
dialog.close();
dialog.windowHandle()->destroy(); // Emulate a click on close by destroying the window.
QTest::qWait(50);