Merge "QEventDispatcher(Win): Always honor interrupted status to avoid races"
This commit is contained in:
commit
d76c0e3224
@ -53,7 +53,7 @@
|
||||
{
|
||||
QDeadlineTimer deadline(msecs);
|
||||
do {
|
||||
if (readFromDevice(deadline.remainingTime())
|
||||
if (readFromDevice(deadline.remainingTime()))
|
||||
break;
|
||||
waitForReadyRead(deadline);
|
||||
} while (!deadline.hasExpired());
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user