Showing the changes to libraries/script-engine/src/ScriptEngine.cpp (1 of 20 files). Show all
Unified · Split
| @@ -46,11 +46,13 @@ · 45 unmodified lines | |||
| 46 | #include "TypedArrays.h" | 46 | #include "TypedArrays.h" |
| 47 | #include "XMLHttpRequestClass.h" | 47 | #include "XMLHttpRequestClass.h" |
| 48 | #include "WebSocketClass.h" | 48 | #include "WebSocketClass.h" |
| 49 | |||
| 50 | #include "RecordingScriptingInterface.h" | 49 | #include "RecordingScriptingInterface.h" |
| 50 | #include "ScriptEngines.h" | ||
| 51 | 51 | ||
| 52 | #include "MIDIEvent.h" | 52 | #include "MIDIEvent.h" |
| 53 | 53 | ||
| 54 | std::atomic<bool> ScriptEngine::_stoppingAllScripts { false }; | ||
| 55 | |||
| 54 | static const QString SCRIPT_EXCEPTION_FORMAT = "[UncaughtException] %1 in %2:%3"; | 56 | static const QString SCRIPT_EXCEPTION_FORMAT = "[UncaughtException] %1 in %2:%3"; |
| 55 | 57 | ||
| 56 | Q_DECLARE_METATYPE(QScriptEngine::FunctionSignature) | 58 | Q_DECLARE_METATYPE(QScriptEngine::FunctionSignature) |
| @@ -132,9 +134,7 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam · 75 unmodified lines | |||
| 132 | _fileNameString(fileNameString), | 134 | _fileNameString(fileNameString), |
| 133 | _arrayBufferClass(new ArrayBufferClass(this)) | 135 | _arrayBufferClass(new ArrayBufferClass(this)) |
| 134 | { | 136 | { |
| 135 | _allScriptsMutex.lock(); | 137 | DependencyManager::get<ScriptEngines>()->addScriptEngine(this); |
| 136 | _allKnownScriptEngines.insert(this); | ||
| 137 | _allScriptsMutex.unlock(); | ||
| 138 | 138 | ||
| 139 | connect(this, &QScriptEngine::signalHandlerException, this, [this](const QScriptValue& exception) { | 139 | connect(this, &QScriptEngine::signalHandlerException, this, [this](const QScriptValue& exception) { |
| 140 | hadUncaughtExceptions(*this, _fileNameString); | 140 | hadUncaughtExceptions(*this, _fileNameString); |
| @@ -144,14 +144,7 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam · 3 unmodified lines | |||
| 144 | ScriptEngine::~ScriptEngine() { | 144 | ScriptEngine::~ScriptEngine() { |
| 145 | qCDebug(scriptengine) << "Script Engine shutting down (destructor) for script:" << getFilename(); | 145 | qCDebug(scriptengine) << "Script Engine shutting down (destructor) for script:" << getFilename(); |
| 146 | 146 | ||
| 147 | // If we're not already in the middle of stopping all scripts, then we should remove ourselves | 147 | DependencyManager::get<ScriptEngines>()->removeScriptEngine(this); |
| 148 | // from the list of running scripts. We don't do this if we're in the process of stopping all scripts | ||
| 149 | // because that method removes scripts from its list as it iterates them | ||
| 150 | if (!_stoppingAllScripts) { | ||
| 151 | _allScriptsMutex.lock(); | ||
| 152 | _allKnownScriptEngines.remove(this); | ||
| 153 | _allScriptsMutex.unlock(); | ||
| 154 | } | ||
| 155 | } | 148 | } |
| 156 | 149 | ||
| 157 | void ScriptEngine::disconnectNonEssentialSignals() { | 150 | void ScriptEngine::disconnectNonEssentialSignals() { |
| @@ -187,67 +180,6 @@ void ScriptEngine::runInThread() { · 29 unmodified lines | |||
| 187 | workerThread->start(); | 180 | workerThread->start(); |
| 188 | } | 181 | } |
| 189 | 182 | ||
| 190 | QSet<ScriptEngine*> ScriptEngine::_allKnownScriptEngines; | ||
| 191 | QMutex ScriptEngine::_allScriptsMutex; | ||
| 192 | std::atomic<bool> ScriptEngine::_stoppingAllScripts { false }; | ||
| 193 | |||
| 194 | void ScriptEngine::stopAllScripts(QObject* application) { | ||
| 195 | _allScriptsMutex.lock(); | ||
| 196 | _stoppingAllScripts = true; | ||
| 197 | |||
| 198 | qCDebug(scriptengine) << "Stopping all scripts.... currently known scripts:" << _allKnownScriptEngines.size(); | ||
| 199 | |||
| 200 | QMutableSetIterator<ScriptEngine*> i(_allKnownScriptEngines); | ||
| 201 | while (i.hasNext()) { | ||
| 202 | ScriptEngine* scriptEngine = i.next(); | ||
| 203 | |||
| 204 | QString scriptName = scriptEngine->getFilename(); | ||
| 205 | |||
| 206 | // NOTE: typically all script engines are running. But there's at least one known exception to this, the | ||
| 207 | // "entities sandbox" which is only used to evaluate entities scripts to test their validity before using | ||
| 208 | // them. We don't need to stop scripts that aren't running. | ||
| 209 | if (scriptEngine->isRunning()) { | ||
| 210 | |||
| 211 | // If the script is running, but still evaluating then we need to wait for its evaluation step to | ||
| 212 | // complete. After that we can handle the stop process appropriately | ||
| 213 | if (scriptEngine->evaluatePending()) { | ||
| 214 | while (scriptEngine->evaluatePending()) { | ||
| 215 | |||
| 216 | // This event loop allows any started, but not yet finished evaluate() calls to complete | ||
| 217 | // we need to let these complete so that we can be guaranteed that the script engine isn't | ||
| 218 | // in a partially setup state, which can confuse our shutdown unwinding. | ||
| 219 | QEventLoop loop; | ||
| 220 | QObject::connect(scriptEngine, &ScriptEngine::evaluationFinished, &loop, &QEventLoop::quit); | ||
| 221 | loop.exec(); | ||
| 222 | } | ||
| 223 | } | ||
| 224 | |||
| 225 | // We disconnect any script engine signals from the application because we don't want to do any | ||
| 226 | // extra stopScript/loadScript processing that the Application normally does when scripts start | ||
| 227 | // and stop. We can safely short circuit this because we know we're in the "quitting" process | ||
| 228 | scriptEngine->disconnect(application); | ||
| 229 | |||
| 230 | // Calling stop on the script engine will set it's internal _isFinished state to true, and result | ||
| 231 | // in the ScriptEngine gracefully ending it's run() method. | ||
| 232 | scriptEngine->stop(); | ||
| 233 | |||
| 234 | // We need to wait for the engine to be done running before we proceed, because we don't | ||
| 235 | // want any of the scripts final "scriptEnding()" or pending "update()" methods from accessing | ||
| 236 | // any application state after we leave this stopAllScripts() method | ||
| 237 | qCDebug(scriptengine) << "waiting on script:" << scriptName; | ||
| 238 | scriptEngine->waitTillDoneRunning(); | ||
| 239 | qCDebug(scriptengine) << "done waiting on script:" << scriptName; | ||
| 240 | |||
| 241 | // If the script is stopped, we can remove it from our set | ||
| 242 | i.remove(); | ||
| 243 | } | ||
| 244 | } | ||
| 245 | _stoppingAllScripts = false; | ||
| 246 | _allScriptsMutex.unlock(); | ||
| 247 | qCDebug(scriptengine) << "DONE Stopping all scripts...."; | ||
| 248 | } | ||
| 249 | |||
| 250 | |||
| 251 | void ScriptEngine::waitTillDoneRunning() { | 183 | void ScriptEngine::waitTillDoneRunning() { |
| 252 | // If the script never started running or finished running before we got here, we don't need to wait for it | 184 | // If the script never started running or finished running before we got here, we don't need to wait for it |
| 253 | if (_isRunning && _isThreaded) { | 185 | if (_isRunning && _isThreaded) { |