diff options
author | Jarek Kobus <jaroslaw.kobus@theqtcompany.com> | 2015-10-28 13:25:17 +0100 |
---|---|---|
committer | Erik Verbruggen <erik.verbruggen@theqtcompany.com> | 2015-10-30 10:54:34 +0000 |
commit | edbe5301ec1789081ce17d853e176e7c7fb90014 (patch) | |
tree | cfc210888fd7c32d5d4d0dd4b4eff5d66d78bd67 | |
parent | 4d4ac9d4415fe056888b3ff31fb7917d7786cacc (diff) |
Fix routing delayed events
Change-Id: Ic872c6ede523eea1b8c5d5aab70b4bbeb5ceccaa
Reviewed-by: Erik Verbruggen <erik.verbruggen@theqtcompany.com>
-rw-r--r-- | src/scxml/qscxmlexecutablecontent.cpp | 2 | ||||
-rw-r--r-- | src/scxml/qscxmlinvokableservice.cpp | 4 | ||||
-rw-r--r-- | src/scxml/qscxmlinvokableservice.h | 4 | ||||
-rw-r--r-- | src/scxml/qscxmlstatemachine.cpp | 133 | ||||
-rw-r--r-- | src/scxml/qscxmlstatemachine.h | 3 | ||||
-rw-r--r-- | src/scxml/qscxmlstatemachine_p.h | 3 | ||||
-rw-r--r-- | tests/auto/scion/tst_scion.cpp | 6 |
7 files changed, 100 insertions, 55 deletions
diff --git a/src/scxml/qscxmlexecutablecontent.cpp b/src/scxml/qscxmlexecutablecontent.cpp index 5779d8e..bbd9252 100644 --- a/src/scxml/qscxmlexecutablecontent.cpp +++ b/src/scxml/qscxmlexecutablecontent.cpp @@ -140,7 +140,7 @@ bool ExecutionEngine::step(Instructions &ip) } } - stateMachine->routeEvent(event); + stateMachine->submitEvent(event); return true; } diff --git a/src/scxml/qscxmlinvokableservice.cpp b/src/scxml/qscxmlinvokableservice.cpp index 8477d7f..9d1f5b8 100644 --- a/src/scxml/qscxmlinvokableservice.cpp +++ b/src/scxml/qscxmlinvokableservice.cpp @@ -243,9 +243,9 @@ QString QScxmlInvokableScxml::name() const return m_stateMachine->name(); } -void QScxmlInvokableScxml::submitEvent(QScxmlEvent *event) +void QScxmlInvokableScxml::postEvent(QScxmlEvent *event) { - m_stateMachine->submitEvent(event); + m_stateMachine->postEvent(event); } QScxmlStateMachine *QScxmlInvokableScxml::stateMachine() const diff --git a/src/scxml/qscxmlinvokableservice.h b/src/scxml/qscxmlinvokableservice.h index 5aa2ae5..f523a12 100644 --- a/src/scxml/qscxmlinvokableservice.h +++ b/src/scxml/qscxmlinvokableservice.h @@ -42,7 +42,7 @@ public: virtual bool start() = 0; virtual QString id() const = 0; virtual QString name() const = 0; - virtual void submitEvent(QScxmlEvent *event) = 0; + virtual void postEvent(QScxmlEvent *event) = 0; void finalize(); @@ -112,7 +112,7 @@ public: bool start() Q_DECL_OVERRIDE; QString id() const Q_DECL_OVERRIDE; QString name() const Q_DECL_OVERRIDE; - void submitEvent(QScxmlEvent *event) Q_DECL_OVERRIDE; + void postEvent(QScxmlEvent *event) Q_DECL_OVERRIDE; QScxmlStateMachine *stateMachine() const; diff --git a/src/scxml/qscxmlstatemachine.cpp b/src/scxml/qscxmlstatemachine.cpp index 6ad4d62..87f9be6 100644 --- a/src/scxml/qscxmlstatemachine.cpp +++ b/src/scxml/qscxmlstatemachine.cpp @@ -238,6 +238,39 @@ void QScxmlStateMachinePrivate::executeInitialSetup() m_executionEngine->execute(m_tableData->initialSetup()); } +void QScxmlStateMachinePrivate::routeEvent(QScxmlEvent *e) +{ + Q_Q(QScxmlStateMachine); + + if (!e) + return; + + QString origin = e->origin(); + if (origin == QStringLiteral("#_parent")) { + if (auto psm = q->parentStateMachine()) { + qCDebug(scxmlLog) << q << "routing event" << e->name() << "from" << q->name() << "to parent" << psm->name(); + psm->postEvent(e); + } else { + qCDebug(scxmlLog) << this << "is not invoked, so it cannot route a message to #_parent"; + delete e; + } + } else if (origin.startsWith(QStringLiteral("#_")) && origin != QStringLiteral("#_internal")) { + // route to children + auto originId = origin.midRef(2); + foreach (QScxmlInvokableService *service, m_invokedServices) { + if (service->id() == originId) { + qCDebug(scxmlLog) << q << "routing event" << e->name() + << "from" << q->name() + << "to parent" << service->id(); + service->postEvent(new QScxmlEvent(*e)); + } + } + delete e; + } else { + q->postEvent(e); + } +} + QScxmlStateMachine *QScxmlStateMachine::fromFile(const QString &fileName, QScxmlDataModel *dataModel) { QFile scxmlFile(fileName); @@ -457,7 +490,7 @@ void QScxmlInternal::WrappedQStateMachine::beginSelectTransitions(QEvent *event) if (service->autoforward()) { qCDebug(scxmlLog) << this << "auto-forwarding event" << scxmlEvent->name() << "from" << stateMachine()->name() << "to service" << service->id(); - service->submitEvent(new QScxmlEvent(*scxmlEvent)); + service->postEvent(new QScxmlEvent(*scxmlEvent)); } } @@ -493,6 +526,42 @@ void QScxmlInternal::WrappedQStateMachine::endMicrostep(QEvent *event) << "finished microstep in state (" << d->m_stateMachine->activeStates() << ")"; } +// This is a slightly modified copy of QStateMachinePrivate::event() +// Instead of postExternalEvent and processEvents +// we route event first to the appropriate state machine instance. +bool QScxmlInternal::WrappedQStateMachine::event(QEvent *e) +{ + Q_D(QScxmlInternal::WrappedQStateMachine); + if (e->type() == QEvent::Timer) { + QTimerEvent *te = static_cast<QTimerEvent*>(e); + int tid = te->timerId(); + if (d->state != QStateMachinePrivate::Running) { + // This event has been cancelled already + QMutexLocker locker(&d->delayedEventsMutex); + Q_ASSERT(!d->timerIdToDelayedEventId.contains(tid)); + return true; + } + d->delayedEventsMutex.lock(); + int id = d->timerIdToDelayedEventId.take(tid); + QStateMachinePrivate::DelayedEvent ee = d->delayedEvents.take(id); + if (ee.event != 0) { + Q_ASSERT(ee.timerId == tid); + killTimer(tid); + d->delayedEventIdFreeList.release(id); + d->delayedEventsMutex.unlock(); + // route here + if (ee.event->type() == QScxmlEvent::scxmlEventType) + QScxmlStateMachinePrivate::get(stateMachine())->routeEvent(static_cast<QScxmlEvent *>(ee.event)); +// d->postExternalEvent(ee.event); +// d->processEvents(QStateMachinePrivate::DirectProcessing); + return true; + } else { + d->delayedEventsMutex.unlock(); + } + } + return QState::event(e); +} + #if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) void QScxmlInternal::WrappedQStateMachinePrivate::noMicrostep() @@ -819,39 +888,6 @@ void QScxmlStateMachine::submitError(const QByteArray &type, const QString &msg, submitEvent(EventBuilder::errorEvent(this, type, sendid)); } -void QScxmlStateMachine::routeEvent(QScxmlEvent *e) -{ - Q_D(QScxmlStateMachine); - - if (!e) - return; - - QString origin = e->origin(); - if (origin == QStringLiteral("#_parent")) { - if (auto psm = parentStateMachine()) { - qCDebug(scxmlLog) << this << "routing event" << e->name() << "from" << name() << "to parent" << psm->name(); - psm->submitEvent(e); - } else { - qCDebug(scxmlLog) << this << "is not invoked, so it cannot route a message to #_parent"; - delete e; - } - } else if (origin.startsWith(QStringLiteral("#_")) && origin != QStringLiteral("#_internal")) { - // route to children - auto originId = origin.midRef(2); - foreach (QScxmlInvokableService *service, d->m_invokedServices) { - if (service->id() == originId) { - qCDebug(scxmlLog) << this << "routing event" << e->name() - << "from" << name() - << "to parent" << service->id(); - service->submitEvent(new QScxmlEvent(*e)); - } - } - delete e; - } else { - submitEvent(e); - } -} - void QScxmlStateMachine::submitEvent(QScxmlEvent *e) { Q_D(QScxmlStateMachine); @@ -869,17 +905,7 @@ void QScxmlStateMachine::submitEvent(QScxmlEvent *e) qCDebug(scxmlLog) << this << ": delayed event" << e->name() << "(" << e << ") got id:" << id; } else { - QStateMachine::EventPriority priority = - e->eventType() == QScxmlEvent::ExternalEvent ? QStateMachine::NormalPriority - : QStateMachine::HighPriority; - - if (d->m_qStateMachine->isRunning()) { - qCDebug(scxmlLog) << this << "posting event" << e->name(); - d->m_qStateMachine->postEvent(e, priority); - } else { - qCDebug(scxmlLog) << this << "queueing event" << e->name(); - d->m_qStateMachine->queueEvent(e, priority); - } + d->routeEvent(e); } } @@ -996,4 +1022,21 @@ void QScxmlStateMachine::setService(const QString &id, QScxmlInvokableService *s Q_UNUSED(service); } +void QScxmlStateMachine::postEvent(QScxmlEvent *e) +{ + Q_D(QScxmlStateMachine); + + QStateMachine::EventPriority priority = + e->eventType() == QScxmlEvent::ExternalEvent ? QStateMachine::NormalPriority + : QStateMachine::HighPriority; + + if (d->m_qStateMachine->isRunning()) { + qCDebug(scxmlLog) << this << "posting event" << e->name(); + d->m_qStateMachine->postEvent(e, priority); + } else { + qCDebug(scxmlLog) << this << "queueing event" << e->name(); + d->m_qStateMachine->queueEvent(e, priority); + } +} + QT_END_NAMESPACE diff --git a/src/scxml/qscxmlstatemachine.h b/src/scxml/qscxmlstatemachine.h index d205bc6..bf71489 100644 --- a/src/scxml/qscxmlstatemachine.h +++ b/src/scxml/qscxmlstatemachine.h @@ -108,7 +108,7 @@ public: Q_INVOKABLE void submitError(const QByteArray &type, const QString &msg, const QByteArray &sendid); - Q_INVOKABLE void routeEvent(QScxmlEvent *e); + void postEvent(QScxmlEvent *e); Q_INVOKABLE void submitEvent(QScxmlEvent *e); Q_INVOKABLE void submitEvent(const QByteArray &event); Q_INVOKABLE void submitEvent(const QByteArray &event, const QVariant &data); @@ -131,6 +131,7 @@ private Q_SLOTS: protected: void setDataBinding(BindingMethod bindingMethod); virtual void setService(const QString &id, QScxmlInvokableService *service); + }; QT_END_NAMESPACE diff --git a/src/scxml/qscxmlstatemachine_p.h b/src/scxml/qscxmlstatemachine_p.h index 9697e43..c2b27f6 100644 --- a/src/scxml/qscxmlstatemachine_p.h +++ b/src/scxml/qscxmlstatemachine_p.h @@ -61,6 +61,7 @@ protected: void beginSelectTransitions(QEvent *event) Q_DECL_OVERRIDE; void beginMicrostep(QEvent *event) Q_DECL_OVERRIDE; void endMicrostep(QEvent *event) Q_DECL_OVERRIDE; + bool event(QEvent *e) Q_DECL_OVERRIDE; private: QScxmlStateMachinePrivate *stateMachinePrivate(); @@ -108,6 +109,8 @@ public: void executeInitialSetup(); + void routeEvent(QScxmlEvent *e); + public: // types & data fields: QString m_sessionId; bool m_isInvoked; diff --git a/tests/auto/scion/tst_scion.cpp b/tests/auto/scion/tst_scion.cpp index 724f0e0..242a496 100644 --- a/tests/auto/scion/tst_scion.cpp +++ b/tests/auto/scion/tst_scion.cpp @@ -31,7 +31,7 @@ Q_DECLARE_METATYPE(std::function<QScxmlStateMachine *()>); -enum { SpyWaitTime = 8000 }; +enum { SpyWaitTime = 12000 }; static QSet<QString> weFailOnThese = QSet<QString>() // The following test needs manual inspection of the result. However, note that we do not support multiple identical keys for event data. @@ -47,8 +47,6 @@ static QSet<QString> weFailOnThese = QSet<QString>() // Currently we do not support loading data as XML content inside the <data> tag. << QLatin1String("w3c-ecma/test557.txml") - // A nested state machine is used, which we do not support. - << QLatin1String("w3c-ecma/test187.txml") // The following test uses the undocumented "exmode" attribute. << QLatin1String("w3c-ecma/test441a.txml") // The following test needs manual inspection of the result. However, note that we do not support the undocumented "exmode" attribute. @@ -64,9 +62,9 @@ static QSet<QString> differentSemantics = QSet<QString>() << QLatin1String("w3c-ecma/test329.txml") // Qt does not support forcing initial states that are not marked as such. << QLatin1String("w3c-ecma/test413.txml") // FIXME: verify initial state setting... + << QLatin1String("w3c-ecma/test576.txml") // FIXME: verify initial state setting... // Scion apparently sets <data> values without a src/expr attribute to 0. We set it to undefined, as specified in B.2.1. << QLatin1String("w3c-ecma/test456.txml") // replaced by modified_test456 - << QLatin1String("w3c-ecma/test576.txml") // FIXME: qscxmlc fails on improper scxml file, currently no way of testing it properly for compiled case << QLatin1String("w3c-ecma/test301.txml") // FIXME: Currently we do not support loading scripts from a srcexpr. |