diff options
author | MÃ¥rten Nordheim <marten.nordheim@qt.io> | 2021-03-05 14:33:01 +0100 |
---|---|---|
committer | Qt CI Bot <qt_ci_bot@qt-project.org> | 2021-03-11 13:31:17 +0000 |
commit | d76c0e3224e5945e68f5e41b5346aed48e70850b (patch) | |
tree | 7d3b83819db6fada3a033828e4596bca58828418 | |
parent | 3102d611bded33a5c15f63ece9e6f2eeb5940818 (diff) | |
parent | f274f91cebb0a4fd2ebe37bb3a605c47d6acd404 (diff) |
Merge "QEventDispatcher(Win): Always honor interrupted status to avoid races"
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); |