summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJarek Kobus <jaroslaw.kobus@theqtcompany.com>2015-10-28 13:25:17 +0100
committerErik Verbruggen <erik.verbruggen@theqtcompany.com>2015-10-30 10:54:34 +0000
commitedbe5301ec1789081ce17d853e176e7c7fb90014 (patch)
treecfc210888fd7c32d5d4d0dd4b4eff5d66d78bd67
parent4d4ac9d4415fe056888b3ff31fb7917d7786cacc (diff)
Fix routing delayed events
Change-Id: Ic872c6ede523eea1b8c5d5aab70b4bbeb5ceccaa Reviewed-by: Erik Verbruggen <erik.verbruggen@theqtcompany.com>
-rw-r--r--src/scxml/qscxmlexecutablecontent.cpp2
-rw-r--r--src/scxml/qscxmlinvokableservice.cpp4
-rw-r--r--src/scxml/qscxmlinvokableservice.h4
-rw-r--r--src/scxml/qscxmlstatemachine.cpp133
-rw-r--r--src/scxml/qscxmlstatemachine.h3
-rw-r--r--src/scxml/qscxmlstatemachine_p.h3
-rw-r--r--tests/auto/scion/tst_scion.cpp6
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.