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 <eskil.abrahamsen-blomfeldt@theqtcompany.com>
This commit is contained in:
Erik Verbruggen 2015-05-12 13:06:46 +02:00
parent 009b11c300
commit 67d255f183
2 changed files with 49 additions and 16 deletions

View File

@ -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;
}

View File

@ -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"