From 67d255f18343d74bbc9a0eec460995ca615473be Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 12 May 2015 13:06:46 +0200 Subject: [PATCH] QStateMachine: empty the whole internal queue before external queue If the internal queue contained multiple events, but the first one did not select any transitions, the external event queue would be checked before the remaining events in the internal queue. Change-Id: I1a7f49afdefaaf2b4330bf13b079b61344385ea0 Task-number: QTBUG-46059 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/corelib/statemachine/qstatemachine.cpp | 26 +++++-------- .../qstatemachine/tst_qstatemachine.cpp | 39 +++++++++++++++++++ 2 files changed, 49 insertions(+), 16 deletions(-) diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index bea6822ecc..e5d019dc8b 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -1925,7 +1925,7 @@ void QStateMachinePrivate::_q_process() delete e; e = 0; } - if (enabledTransitions.isEmpty() && ((e = dequeueInternalEvent()) != 0)) { + while (enabledTransitions.isEmpty() && ((e = dequeueInternalEvent()) != 0)) { #ifdef QSTATEMACHINE_DEBUG qDebug() << q << ": dequeued internal event" << e << "of type" << e->type(); #endif @@ -1935,8 +1935,7 @@ void QStateMachinePrivate::_q_process() e = 0; } } - if (enabledTransitions.isEmpty()) { - if ((e = dequeueExternalEvent()) != 0) { + while (enabledTransitions.isEmpty() && ((e = dequeueExternalEvent()) != 0)) { #ifdef QSTATEMACHINE_DEBUG qDebug() << q << ": dequeued external event" << e << "of type" << e->type(); #endif @@ -1945,24 +1944,19 @@ void QStateMachinePrivate::_q_process() delete e; e = 0; } - } else { - if (isInternalEventQueueEmpty()) { - processing = false; - stopProcessingReason = EventQueueEmpty; - } - } } - if (!enabledTransitions.isEmpty()) { - didChange = true; - q->beginMicrostep(e); - microstep(e, enabledTransitions, &calculationCache); - q->endMicrostep(e); - } - else { + if (enabledTransitions.isEmpty()) { + processing = false; + stopProcessingReason = EventQueueEmpty; noMicrostep(); #ifdef QSTATEMACHINE_DEBUG qDebug() << q << ": no transitions enabled"; #endif + } else { + didChange = true; + q->beginMicrostep(e); + microstep(e, enabledTransitions, &calculationCache); + q->endMicrostep(e); } delete e; } diff --git a/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp b/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp index 3718b07b33..1292c3b98f 100644 --- a/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp +++ b/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp @@ -249,6 +249,7 @@ private slots: void qtbug_44783(); void internalTransition(); void conflictingTransition(); + void qtbug_46059(); }; class TestState : public QState @@ -6446,5 +6447,43 @@ void tst_QStateMachine::conflictingTransition() QVERIFY(machine.isRunning()); } +void tst_QStateMachine::qtbug_46059() +{ + QStateMachine machine; + QState a(&machine); + QState b(&a); + QState c(&a); + QState success(&a); + QState failure(&machine); + + machine.setInitialState(&a); + a.setInitialState(&b); + b.addTransition(new EventTransition(QEvent::Type(QEvent::User + 1), &c)); + c.addTransition(new EventTransition(QEvent::Type(QEvent::User + 2), &success)); + b.addTransition(new EventTransition(QEvent::Type(QEvent::User + 2), &failure)); + + machine.start(); + QCoreApplication::processEvents(); + + QTRY_COMPARE(machine.configuration().contains(&a), true); + QTRY_COMPARE(machine.configuration().contains(&b), true); + QTRY_COMPARE(machine.configuration().contains(&c), false); + QTRY_COMPARE(machine.configuration().contains(&failure), false); + QTRY_COMPARE(machine.configuration().contains(&success), false); + + machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 0)), QStateMachine::HighPriority); + machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 1)), QStateMachine::HighPriority); + machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 2)), QStateMachine::NormalPriority); + QCoreApplication::processEvents(); + + QTRY_COMPARE(machine.configuration().contains(&a), true); + QTRY_COMPARE(machine.configuration().contains(&b), false); + QTRY_COMPARE(machine.configuration().contains(&c), false); + QTRY_COMPARE(machine.configuration().contains(&failure), false); + QTRY_COMPARE(machine.configuration().contains(&success), true); + + QVERIFY(machine.isRunning()); +} + QTEST_MAIN(tst_QStateMachine) #include "tst_qstatemachine.moc"