summaryrefslogtreecommitdiffstats
path: root/src/uscxml/interpreter
diff options
context:
space:
mode:
Diffstat (limited to 'src/uscxml/interpreter')
-rw-r--r--src/uscxml/interpreter/BasicContentExecutor.cpp47
-rw-r--r--src/uscxml/interpreter/BasicEventQueue.cpp25
-rw-r--r--src/uscxml/interpreter/FastMicroStep.cpp60
-rw-r--r--src/uscxml/interpreter/FastMicroStep.h13
-rw-r--r--src/uscxml/interpreter/InterpreterImpl.cpp35
5 files changed, 124 insertions, 56 deletions
diff --git a/src/uscxml/interpreter/BasicContentExecutor.cpp b/src/uscxml/interpreter/BasicContentExecutor.cpp
index c1eb8f6..366c4bd 100644
--- a/src/uscxml/interpreter/BasicContentExecutor.cpp
+++ b/src/uscxml/interpreter/BasicContentExecutor.cpp
@@ -209,13 +209,7 @@ void BasicContentExecutor::processCancel(XERCESC_NS::DOMElement* content) {
void BasicContentExecutor::processIf(XERCESC_NS::DOMElement* content) {
bool blockIsTrue = _callbacks->isTrue(ATTR(content, "cond"));
- DOMNodeList* children = content->getChildNodes();
- for (unsigned int i = 0; i < children->getLength(); i++) {
- if (children->item(i)->getNodeType() != DOMNode::ELEMENT_NODE)
- continue;
-
- DOMElement* childElem = dynamic_cast<DOMElement*>(children->item(i));
-
+ for (auto childElem = content->getFirstElementChild(); childElem; childElem = childElem->getNextElementSibling()) {
if (iequals(TAGNAME(childElem), XML_PREFIX(content).str() + "elseif")) {
if (blockIsTrue) {
// last block was true, break here
@@ -257,11 +251,8 @@ void BasicContentExecutor::processForeach(XERCESC_NS::DOMElement* content) {
for (uint32_t iteration = 0; iteration < iterations; iteration++) {
_callbacks->setForeach(item, array, index, iteration);
- DOMNodeList* children = content->getChildNodes();
- for (unsigned int i = 0; i < children->getLength(); i++) {
- if (children->item(i)->getNodeType() != DOMNode::ELEMENT_NODE)
- continue;
- process(dynamic_cast<DOMElement*>(children->item(i)), XML_PREFIX(content));
+ for (auto childElem = content->getFirstElementChild(); childElem; childElem = childElem->getNextElementSibling()) {
+ process(childElem, XML_PREFIX(content));
}
}
}
@@ -292,13 +283,10 @@ void BasicContentExecutor::process(XERCESC_NS::DOMElement* block, const X& xmlPr
iequals(tagName, xmlPrefix.str() + "onexit") ||
iequals(tagName, xmlPrefix.str() + "transition")) {
- DOMNodeList* children = block->getChildNodes();
try {
- for(auto i = 0; i < children->getLength(); i++) {
- if (children->item(i)->getNodeType() != DOMNode::ELEMENT_NODE)
- continue;
+ for (auto childElem = block->getFirstElementChild(); childElem; childElem = childElem->getNextElementSibling()) {
// process any child eleents
- process(dynamic_cast<DOMElement*>(children->item(i)), xmlPrefix);
+ process(childElem, xmlPrefix);
}
} catch (Event e) {
// there has been an error in an executable content block
@@ -415,6 +403,7 @@ void BasicContentExecutor::invoke(XERCESC_NS::DOMElement* element) {
_callbacks->assign(ATTR(element, "idlocation"), Data(invokeEvent.invokeid, Data::VERBATIM));
}
}
+
// we need the invokeid to uninvoke - TODO: This is leaking!
char* invokeId = (char*)malloc(invokeEvent.invokeid.size() + 1);
memcpy(invokeId, invokeEvent.invokeid.c_str(), invokeEvent.invokeid.size());
@@ -488,6 +477,7 @@ void BasicContentExecutor::uninvoke(XERCESC_NS::DOMElement* invoke) {
_callbacks->uninvoke(invokeId);
USCXML_MONITOR_CALLBACK2(_callbacks->getMonitor(), afterUninvoking, invoke, invokeId);
+ invoke->setUserData(X("invokeid"), NULL, NULL);
free(invokeId);
}
@@ -589,25 +579,26 @@ Data BasicContentExecutor::elementAsData(XERCESC_NS::DOMElement* element) {
std::string content = url.getInContent();
// make an attempt to parse as XML
- try {
- XERCESC_NS::XercesDOMParser* parser = new XERCESC_NS::XercesDOMParser();
- parser->setValidationScheme(XERCESC_NS::XercesDOMParser::Val_Always);
- parser->setDoNamespaces(true);
- parser->useScanner(XERCESC_NS::XMLUni::fgWFXMLScanner);
+ try {
+ XERCESC_NS::XercesDOMParser parser;
+ parser.setValidationScheme(XERCESC_NS::XercesDOMParser::Val_Never);
+ parser.setDoNamespaces(true);
+ parser.useScanner(XERCESC_NS::XMLUni::fgWFXMLScanner);
- XERCESC_NS::ErrorHandler* errHandler = new XERCESC_NS::HandlerBase();
- parser->setErrorHandler(errHandler);
+ XERCESC_NS::HandlerBase errHandler;
+ parser.setErrorHandler(&errHandler);
std::string tmp = url;
XERCESC_NS::MemBufInputSource is((XMLByte*)content.c_str(), content.size(), X("fake"));
- parser->parse(is);
+ parser.parse(is);
Data d;
- XERCESC_NS::DOMDocument* doc = parser->adoptDocument();
+ XERCESC_NS::DOMDocument* doc = parser.adoptDocument();
d.adoptedDoc = std::make_shared<XERCESC_NS::DOMDocument*>(doc);
d.node = doc->getDocumentElement();
- return d;
+
+ return d;
} catch (...) {
// just ignore and return as an interpreted string below
@@ -646,7 +637,7 @@ Data BasicContentExecutor::elementAsData(XERCESC_NS::DOMElement* element) {
}
}
- LOG(WARNING) << "Element " << DOMUtils::xPathForNode(element) << " did not yield any data";
+// LOG(WARNING) << "Element " << DOMUtils::xPathForNode(element) << " did not yield any data";
return Data();
}
diff --git a/src/uscxml/interpreter/BasicEventQueue.cpp b/src/uscxml/interpreter/BasicEventQueue.cpp
index ee2346d..7309392 100644
--- a/src/uscxml/interpreter/BasicEventQueue.cpp
+++ b/src/uscxml/interpreter/BasicEventQueue.cpp
@@ -35,13 +35,26 @@ Event BasicEventQueue::dequeue(size_t blockMs) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
if (blockMs > 0) {
- // block for given milliseconds or until queue is filled
- std::chrono::time_point<std::chrono::system_clock> end, now;
- now = std::chrono::system_clock::now();
- end = now + std::chrono::milliseconds(blockMs);
- while (std::chrono::system_clock::now() < end && _queue.empty()) {
- _cond.wait_for(_mutex, std::chrono::system_clock::now() - end);
+ // block for given milliseconds or until queue is filled
+ std::chrono::time_point<std::chrono::system_clock> updated, now;
+ std::chrono::milliseconds remain;
+
+ if (blockMs > std::chrono::system_clock::duration::max().count()) {
+ blockMs = std::chrono::system_clock::duration::max().count();
+ }
+
+ updated = now = std::chrono::system_clock::now();
+ remain = std::chrono::milliseconds(blockMs);
+
+ while (remain.count() > 0 && _queue.empty()) {
+ _cond.wait_for(_mutex, remain);
+
+ now = std::chrono::system_clock::now();
+
+ auto elapsed = now - updated;
+ remain -= std::chrono::duration_cast<std::chrono::milliseconds>(elapsed);
+ updated = now;
}
}
diff --git a/src/uscxml/interpreter/FastMicroStep.cpp b/src/uscxml/interpreter/FastMicroStep.cpp
index 3ad5515..927fbbc 100644
--- a/src/uscxml/interpreter/FastMicroStep.cpp
+++ b/src/uscxml/interpreter/FastMicroStep.cpp
@@ -155,8 +155,35 @@ void FastMicroStep::resortStates(DOMNode* node, const X& xmlPrefix) {
}
}
-void FastMicroStep::init(XERCESC_NS::DOMElement* scxml) {
+std::list<XERCESC_NS::DOMElement*> FastMicroStep::getExitSetCached(const XERCESC_NS::DOMElement* transition,
+ const XERCESC_NS::DOMElement* root) {
+
+ if (_cache.exitSet.find(transition) == _cache.exitSet.end()) {
+ _cache.exitSet[transition] = getExitSet(transition, root);
+ }
+
+ return _cache.exitSet[transition];
+}
+
+bool FastMicroStep::conflictsCached(const DOMElement* t1, const DOMElement* t2, const DOMElement* root) {
+ if (getSourceState(t1) == getSourceState(t2))
+ return true;
+
+ if (DOMUtils::isDescendant(getSourceState(t1), getSourceState(t2)))
+ return true;
+ if (DOMUtils::isDescendant(getSourceState(t2), getSourceState(t1)))
+ return true;
+
+ if (DOMUtils::hasIntersection(getExitSetCached(t1, root), getExitSetCached(t2, root)))
+ return true;
+
+ return false;
+}
+
+
+void FastMicroStep::init(XERCESC_NS::DOMElement* scxml) {
+
_scxml = scxml;
_binding = (HAS_ATTR(_scxml, "binding") && iequals(ATTR(_scxml, "binding"), "late") ? LATE : EARLY);
_xmlPrefix = _scxml->getPrefix();
@@ -331,7 +358,9 @@ void FastMicroStep::init(XERCESC_NS::DOMElement* scxml) {
// establish the transitions' exit set
assert(_transitions[i]->element != NULL);
// std::cout << "i: " << i << std::endl << std::flush;
- std::list<DOMElement*> exitList = getExitSet(_transitions[i]->element, _scxml);
+ std::list<DOMElement*> exitList = getExitSetCached(_transitions[i]->element, _scxml);
+ _cache.exitSet[_transitions[i]->element] = exitList;
+
for (j = 0; j < _states.size(); j++) {
if (!exitList.empty() && _states[j]->element == exitList.front()) {
_transitions[i]->exitSet[j] = true;
@@ -343,14 +372,21 @@ void FastMicroStep::init(XERCESC_NS::DOMElement* scxml) {
assert(exitList.size() == 0);
// establish the transitions' conflict set
- for (j = 0; j < _transitions.size(); j++) {
- if (conflicts(_transitions[i]->element, _transitions[j]->element, _scxml)) {
+ for (j = i; j < _transitions.size(); j++) {
+ if (conflictsCached(_transitions[i]->element, _transitions[j]->element, _scxml)) {
_transitions[i]->conflicts[j] = true;
} else {
_transitions[i]->conflicts[j] = false;
}
+// std::cout << ".";
}
+
+ // conflicts matrix is symmetric
+ for (j = 0; j < i; j++) {
+ _transitions[i]->conflicts[j] = _transitions[j]->conflicts[i];
+ }
+
// establish the transitions' target set
std::list<std::string> targets = tokenize(ATTR(_transitions[i]->element, "target"));
for (auto tIter = targets.begin(); tIter != targets.end(); tIter++) {
@@ -387,8 +423,10 @@ void FastMicroStep::init(XERCESC_NS::DOMElement* scxml) {
// the transitions event and condition
- _transitions[i]->event = (HAS_ATTR(_transitions[i]->element, "event") ? ATTR(_transitions[i]->element, "event") : "");
- _transitions[i]->cond = (HAS_ATTR(_transitions[i]->element, "cond") ? ATTR(_transitions[i]->element, "cond") : "");
+ _transitions[i]->event = (HAS_ATTR(_transitions[i]->element, "event") ?
+ ATTR(_transitions[i]->element, "event") : "");
+ _transitions[i]->cond = (HAS_ATTR(_transitions[i]->element, "cond") ?
+ ATTR(_transitions[i]->element, "cond") : "");
// is there executable content?
if (_transitions[i]->element->getChildElementCount() > 0) {
@@ -396,6 +434,7 @@ void FastMicroStep::init(XERCESC_NS::DOMElement* scxml) {
}
}
+ _cache.exitSet.clear();
_isInitialized = true;
}
@@ -1030,12 +1069,9 @@ std::list<DOMElement*> FastMicroStep::getCompletion(const DOMElement* state) {
completion.push_back(initElems.front());
} else {
// first child state
- DOMNodeList* children = state->getChildNodes();
- for (size_t i = 0; i < children->getLength(); i++) {
- if (children->item(i)->getNodeType() != DOMNode::ELEMENT_NODE)
- continue;
- if (isState(dynamic_cast<DOMElement*>(children->item(i)))) {
- completion.push_back(dynamic_cast<DOMElement*>(children->item(i)));
+ for (auto childElem = state->getFirstElementChild(); childElem; childElem = childElem->getNextElementSibling()) {
+ if (isState(childElem)) {
+ completion.push_back(childElem);
break;
}
}
diff --git a/src/uscxml/interpreter/FastMicroStep.h b/src/uscxml/interpreter/FastMicroStep.h
index 023bb8f..b2477ee 100644
--- a/src/uscxml/interpreter/FastMicroStep.h
+++ b/src/uscxml/interpreter/FastMicroStep.h
@@ -26,6 +26,7 @@
#include "uscxml/util/DOM.h" // X
#include <vector>
+#include <map>
#include <set>
#include "MicroStepImpl.h"
@@ -89,6 +90,11 @@ protected:
unsigned char type;
};
+ class CachedPredicates {
+ public:
+ std::map<const XERCESC_NS::DOMElement*, std::list<XERCESC_NS::DOMElement*> > exitSet;
+ };
+
virtual void init(XERCESC_NS::DOMElement* scxml);
std::list<XERCESC_NS::DOMElement*> getCompletion(const XERCESC_NS::DOMElement* state);
@@ -120,7 +126,12 @@ private:
std::list<XERCESC_NS::DOMElement*> getHistoryCompletion(const XERCESC_NS::DOMElement* state);
void resortStates(XERCESC_NS::DOMNode* node, const X& xmlPrefix);
-// bool hasLegalConfiguration();
+ bool conflictsCached(const XERCESC_NS::DOMElement* t1, const XERCESC_NS::DOMElement* t2, const XERCESC_NS::DOMElement* root); ///< overrides implementation Predicates::conflicts for speed
+
+ std::list<XERCESC_NS::DOMElement*> getExitSetCached(const XERCESC_NS::DOMElement* transition,
+ const XERCESC_NS::DOMElement* root);
+
+ CachedPredicates _cache;
#ifdef USCXML_VERBOSE
void printStateNames(const boost::dynamic_bitset<>& bitset);
diff --git a/src/uscxml/interpreter/InterpreterImpl.cpp b/src/uscxml/interpreter/InterpreterImpl.cpp
index 3383411..0547f12 100644
--- a/src/uscxml/interpreter/InterpreterImpl.cpp
+++ b/src/uscxml/interpreter/InterpreterImpl.cpp
@@ -82,15 +82,31 @@ InterpreterImpl::InterpreterImpl() : _isInitialized(false), _document(NULL), _sc
InterpreterImpl::~InterpreterImpl() {
- if (_delayQueue)
- _delayQueue.cancelAllDelayed();
- if (_document)
- delete _document;
-
- {
- std::lock_guard<std::recursive_mutex> lock(_instanceMutex);
- _instances.erase(getSessionId());
- }
+
+ // make sure we deallocate all user-data in the DOM,
+ // this is neccesary if we were aborted early
+ std::list<DOMElement*> invokes = DOMUtils::filterChildElements(_xmlPrefix.str() + "invoke", _scxml, true);
+ for (auto invoke : invokes) {
+ char* invokeId = (char*)invoke->getUserData(X("invokeid"));
+ if (invokeId != NULL) {
+ free(invokeId);
+ invoke->setUserData(X("invokeid"), NULL, NULL);
+ }
+ }
+
+ if (_delayQueue)
+ _delayQueue.cancelAllDelayed();
+ if (_document)
+ delete _document;
+
+ {
+ std::lock_guard<std::recursive_mutex> lock(_instanceMutex);
+ _instances.erase(getSessionId());
+ }
+
+// assert(_invokers.size() == 0);
+// ::xercesc_3_1::XMLPlatformUtils::Terminate();
+
}
void InterpreterImpl::cancel() {
@@ -361,6 +377,7 @@ void InterpreterImpl::uninvoke(const std::string& invokeId) {
if (_invokers.find(invokeId) != _invokers.end()) {
_invokers[invokeId].uninvoke();
_autoForwarders.erase(invokeId);
+ _invokers.erase(invokeId);
}
}