diff options
Diffstat (limited to 'src/uscxml/interpreter')
-rw-r--r-- | src/uscxml/interpreter/BasicContentExecutor.cpp | 47 | ||||
-rw-r--r-- | src/uscxml/interpreter/BasicEventQueue.cpp | 25 | ||||
-rw-r--r-- | src/uscxml/interpreter/FastMicroStep.cpp | 60 | ||||
-rw-r--r-- | src/uscxml/interpreter/FastMicroStep.h | 13 | ||||
-rw-r--r-- | src/uscxml/interpreter/InterpreterImpl.cpp | 35 |
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); } } |