Showing the changes to libraries/script-engine/src/ScriptEngine.cpp (1 of 1 file). Show all
Unified · Split
| @@ -146,12 +146,15 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam · 145 unmodified lines | |||
| 146 | 146 | ||
| 147 | ScriptEngine::~ScriptEngine() { | 147 | ScriptEngine::~ScriptEngine() { |
| 148 | qCDebug(scriptengine) << "Script Engine shutting down (destructor) for script:" << getFilename(); | 148 | qCDebug(scriptengine) << "Script Engine shutting down (destructor) for script:" << getFilename(); |
| 149 | |||
| 149 | auto scriptEngines = DependencyManager::get<ScriptEngines>(); | 150 | auto scriptEngines = DependencyManager::get<ScriptEngines>(); |
| 150 | if (scriptEngines) { | 151 | if (scriptEngines) { |
| 151 | scriptEngines->removeScriptEngine(this); | 152 | scriptEngines->removeScriptEngine(this); |
| 152 | } else { | 153 | } else { |
| 153 | qCWarning(scriptengine) << "Script destroyed after ScriptEngines!"; | 154 | qCWarning(scriptengine) << "Script destroyed after ScriptEngines!"; |
| 154 | } | 155 | } |
| 156 | |||
| 157 | waitTillDoneRunning(); | ||
| 155 | } | 158 | } |
| 156 | 159 | ||
| 157 | void ScriptEngine::disconnectNonEssentialSignals() { | 160 | void ScriptEngine::disconnectNonEssentialSignals() { |
| @@ -172,7 +175,7 @@ void ScriptEngine::runInThread() { · 14 unmodified lines | |||
| 172 | } | 175 | } |
| 173 | 176 | ||
| 174 | _isThreaded = true; | 177 | _isThreaded = true; |
| 175 | QThread* workerThread = new QThread(this); // thread is not owned, so we need to manage the delete | 178 | QThread* workerThread = new QThread(); |
| 176 | QString scriptEngineName = QString("Script Thread:") + getFilename(); | 179 | QString scriptEngineName = QString("Script Thread:") + getFilename(); |
| 177 | workerThread->setObjectName(scriptEngineName); | 180 | workerThread->setObjectName(scriptEngineName); |
| 178 | 181 | ||
| @@ -194,35 +197,34 @@ void ScriptEngine::runInThread() { · 15 unmodified lines | |||
| 194 | 197 | ||
| 195 | void ScriptEngine::waitTillDoneRunning() { | 198 | void ScriptEngine::waitTillDoneRunning() { |
| 196 | // If the script never started running or finished running before we got here, we don't need to wait for it | 199 | // If the script never started running or finished running before we got here, we don't need to wait for it |
| 197 | if (_isRunning && _isThreaded) { | 200 | auto workerThread = thread(); |
| 198 | 201 | if (_isThreaded && workerThread) { | |
| 199 | // NOTE: waitTillDoneRunning() will be called on the main Application thread, inside of stopAllScripts() | ||
| 200 | // we want the application thread to continue to process events, because the scripts will likely need to | ||
| 201 | // marshall messages across to the main thread. For example if they access Settings or Menu in any of their | ||
| 202 | // shutdown code. | ||
| 203 | QString scriptName = getFilename(); | 202 | QString scriptName = getFilename(); |
| 204 | |||
| 205 | auto startedWaiting = usecTimestampNow(); | 203 | auto startedWaiting = usecTimestampNow(); |
| 206 | while (thread()->isRunning()) { | ||
| 207 | // process events for the main application thread, allowing invokeMethod calls to pass between threads | ||
| 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 | 204 | ||
| 216 | // if we've been waiting for more than 5 seconds then we should be more aggessive about stopping | 205 | while (workerThread->isRunning()) { |
| 217 | if (elapsedUsecs > WAITING_TOO_LONG) { | 206 | // NOTE: This will be called on the main application thread from stopAllScripts. |
| 218 | qCDebug(scriptengine) << "Script " << scriptName << " has been running too long [" << elapsedUsecs << " usecs] quitting."; | 207 | // The application thread will need to continue to process events, because |
| 219 | thread()->quit(); | 208 | // the scripts will likely need to marshall messages across to the main thread, e.g. |
| 209 | // if they access Settings or Menu in any of their shutdown code. So: | ||
| 210 | // Process events for the main application thread, allowing invokeMethod calls to pass between threads. | ||
| 211 | QCoreApplication::processEvents(); // thread-safe :) | ||
| 212 | |||
| 213 | // If we've been waiting a second or more, then tell the script engine to stop evaluating | ||
| 214 | static const auto MAX_SCRIPT_EVALUATION_TIME = USECS_PER_SECOND; | ||
| 215 | auto elapsedUsecs = usecTimestampNow() - startedWaiting; | ||
| 216 | if (elapsedUsecs > MAX_SCRIPT_EVALUATION_TIME) { | ||
| 217 | qCDebug(scriptengine) << | ||
| 218 | "Script " << scriptName << " has been running too long [" << elapsedUsecs << " usecs] quitting."; | ||
| 219 | workerThread->quit(); | ||
| 220 | break; | 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 | } | 221 | } |
| 222 | |||
| 223 | // Avoid a pure busy wait | ||
| 224 | QThread::yieldCurrentThread(); | ||
| 225 | } | 225 | } |
| 226 | |||
| 227 | workerThread->deleteLater(); | ||
| 226 | } | 228 | } |
| 227 | } | 229 | } |
| 228 | 230 | ||