History

Merge pull request #7769 from ZappoMan/abortForInfiniteLoops

add support to abort evaluation of long running scripts on shutdown

Brad Hefta-Gaub committed 10 years ago

Commit ad285ff2 parents 2b54813 b98419e2 files · +22 −20Browse files

Showing the changes to libraries/script-engine/src/ScriptEngine.cpp (1 of 2 files). Show all

Unified · Split

libraries/script-engine/src/ScriptEngine.cpp+21−6
@@ -140,6 +140,8 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam · 139 unmodified lines
140 connect(this, &QScriptEngine::signalHandlerException, this, [this](const QScriptValue& exception) {140 connect(this, &QScriptEngine::signalHandlerException, this, [this](const QScriptValue& exception) {
141 hadUncaughtExceptions(*this, _fileNameString);141 hadUncaughtExceptions(*this, _fileNameString);
142 });142 });
143
144 setProcessEventsInterval(MSECS_PER_SECOND);
143}145}
144 146
145ScriptEngine::~ScriptEngine() {147ScriptEngine::~ScriptEngine() {
@@ -198,9 +200,28 @@ void ScriptEngine::waitTillDoneRunning() { · 52 unmodified lines
198 // we want the application thread to continue to process events, because the scripts will likely need to200 // we want the application thread to continue to process events, because the scripts will likely need to
199 // marshall messages across to the main thread. For example if they access Settings or Menu in any of their201 // marshall messages across to the main thread. For example if they access Settings or Menu in any of their
200 // shutdown code.202 // shutdown code.
203 QString scriptName = getFilename();
204
205 auto startedWaiting = usecTimestampNow();
201 while (thread()->isRunning()) {206 while (thread()->isRunning()) {
202 // process events for the main application thread, allowing invokeMethod calls to pass between threads207 // process events for the main application thread, allowing invokeMethod calls to pass between threads
203 QCoreApplication::processEvents();208 QCoreApplication::processEvents();
209 auto stillWaiting = usecTimestampNow();
210 auto elapsedUsecs = stillWaiting - startedWaiting;
211
212 // if we've been waiting a second or more, then tell the script engine to stop evaluating
213 static const auto MAX_SCRIPT_EVALUATION_TIME = USECS_PER_SECOND;
214 static const auto WAITING_TOO_LONG = MAX_SCRIPT_EVALUATION_TIME * 5;
215
216 // if we've been waiting for more than 5 seconds then we should be more aggessive about stopping
217 if (elapsedUsecs > WAITING_TOO_LONG) {
218 qCDebug(scriptengine) << "Script " << scriptName << " has been running too long [" << elapsedUsecs << " usecs] quitting.";
219 thread()->quit();
220 break;
221 } else if (elapsedUsecs > MAX_SCRIPT_EVALUATION_TIME) {
222 qCDebug(scriptengine) << "Script " << scriptName << " has been running too long [" << elapsedUsecs << " usecs] aborting evaluation.";
223 QMetaObject::invokeMethod(this, "abortEvaluation");
224 }
204 }225 }
205 }226 }
206}227}
@@ -411,7 +432,6 @@ void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) { · 204 unmodified lines
411 if (partsToGo > 0) {432 if (partsToGo > 0) {
412 //QObject *object = new QObject;433 //QObject *object = new QObject;
413 QScriptValue partValue = newArray(); //newQObject(object, QScriptEngine::ScriptOwnership);434 QScriptValue partValue = newArray(); //newQObject(object, QScriptEngine::ScriptOwnership);
414 qDebug() << "partValue[" << pathPart<<"].isArray() :" << partValue.isArray();
415 partObject.setProperty(pathPart, partValue);435 partObject.setProperty(pathPart, partValue);
416 } else {436 } else {
417 partObject.setProperty(pathPart, value);437 partObject.setProperty(pathPart, value);
@@ -1110,11 +1130,6 @@ void ScriptEngine::loadEntityScript(QWeakPointer<ScriptEngine> theEngine, const · 692 unmodified lines
1110 << QThread::currentThread() << "] expected thread [" << strongEngine->thread() << "]";1130 << QThread::currentThread() << "] expected thread [" << strongEngine->thread() << "]";
1111#endif1131#endif
1112 strongEngine->entityScriptContentAvailable(entityID, scriptOrURL, contents, isURL, success);1132 strongEngine->entityScriptContentAvailable(entityID, scriptOrURL, contents, isURL, success);
1113 } else {
1114 // FIXME - I'm leaving this in for testing, so that QA can confirm that sometimes the script contents
1115 // returns after the ScriptEngine has been deleted, we can remove this after QA verifies the
1116 // repro case.
1117 qDebug() << "ScriptCache::getScriptContents() returned after our ScriptEngine was deleted... script:" << scriptOrURL;
1118 }1133 }
1119 }, forceRedownload);1134 }, forceRedownload);
1120}1135}