Showing the changes to libraries/script-engine/src/ScriptEngine.cpp (1 of 1 file). Show all
Unified · Split
| @@ -162,16 +162,15 @@ ScriptEngine::~ScriptEngine() { · 161 unmodified lines | |||
| 162 | } else { | 162 | } else { |
| 163 | qCWarning(scriptengine) << "Script destroyed after ScriptEngines!"; | 163 | qCWarning(scriptengine) << "Script destroyed after ScriptEngines!"; |
| 164 | } | 164 | } |
| 165 | |||
| 166 | waitTillDoneRunning(); | ||
| 167 | } | 165 | } |
| 168 | 166 | ||
| 169 | void ScriptEngine::disconnectNonEssentialSignals() { | 167 | void ScriptEngine::disconnectNonEssentialSignals() { |
| 170 | disconnect(); | 168 | disconnect(); |
| 171 | QThread* receiver; | 169 | QThread* workerThread; |
| 172 | // Ensure the thread should be running, and does exist | 170 | // Ensure the thread should be running, and does exist |
| 173 | if (_isRunning && _isThreaded && (receiver = thread())) { | 171 | if (_isRunning && _isThreaded && (workerThread = thread())) { |
| 174 | connect(this, &ScriptEngine::doneRunning, receiver, &QThread::quit); | 172 | connect(this, &ScriptEngine::doneRunning, workerThread, &QThread::quit); |
| 173 | connect(workerThread, &QThread::finished, workerThread, &QObject::deleteLater); | ||
| 175 | } | 174 | } |
| 176 | } | 175 | } |
| 177 | 176 | ||
| @@ -268,30 +267,33 @@ void ScriptEngine::runInThread() { · 90 unmodified lines | |||
| 268 | } | 267 | } |
| 269 | 268 | ||
| 270 | _isThreaded = true; | 269 | _isThreaded = true; |
| 271 | QThread* workerThread = new QThread(); | ||
| 272 | QString scriptEngineName = QString("Script Thread:") + getFilename(); | ||
| 273 | workerThread->setObjectName(scriptEngineName); | ||
| 274 | 270 | ||
| 271 | // The thread interface cannot live on itself, and we want to move this into the thread, so | ||
| 272 | // the thread cannot have this as a parent. | ||
| 273 | QThread* workerThread = new QThread(); | ||
| 274 | workerThread->setObjectName(QString("Script Thread:") + getFilename()); | ||
| 275 | moveToThread(workerThread); | ||
| 276 | |||
| 275 | // NOTE: If you connect any essential signals for proper shutdown or cleanup of | 277 | // NOTE: If you connect any essential signals for proper shutdown or cleanup of |
| 276 | // the script engine, make sure to add code to "reconnect" them to the | 278 | // the script engine, make sure to add code to "reconnect" them to the |
| 277 | // disconnectNonEssentialSignals() method | 279 | // disconnectNonEssentialSignals() method |
| 278 | |||
| 279 | // when the worker thread is started, call our engine's run.. | ||
| 280 | connect(workerThread, &QThread::started, this, &ScriptEngine::run); | 280 | connect(workerThread, &QThread::started, this, &ScriptEngine::run); |
| 281 | |||
| 282 | // tell the thread to stop when the script engine is done | ||
| 283 | connect(this, &ScriptEngine::doneRunning, workerThread, &QThread::quit); | 281 | connect(this, &ScriptEngine::doneRunning, workerThread, &QThread::quit); |
| 282 | connect(workerThread, &QThread::finished, workerThread, &QObject::deleteLater); | ||
| 284 | 283 | ||
| 285 | moveToThread(workerThread); | ||
| 286 | |||
| 287 | // Starts an event loop, and emits workerThread->started() | ||
| 288 | workerThread->start(); | 284 | workerThread->start(); |
| 289 | } | 285 | } |
| 290 | 286 | ||
| 291 | void ScriptEngine::waitTillDoneRunning() { | 287 | void ScriptEngine::waitTillDoneRunning() { |
| 292 | // If the script never started running or finished running before we got here, we don't need to wait for it | 288 | // If the script never started running or finished running before we got here, we don't need to wait for it |
| 293 | auto workerThread = thread(); | 289 | auto workerThread = thread(); |
| 290 | |||
| 294 | if (_isThreaded && workerThread) { | 291 | if (_isThreaded && workerThread) { |
| 292 | // We should never be waiting (blocking) on our own thread | ||
| 293 | assert(workerThread != QThread::currentThread()); | ||
| 294 | |||
| 295 | stop(); | ||
| 296 | |||
| 295 | QString scriptName = getFilename(); | 297 | QString scriptName = getFilename(); |
| 296 | auto startedWaiting = usecTimestampNow(); | 298 | auto startedWaiting = usecTimestampNow(); |
| 297 | 299 | ||
| @@ -301,24 +303,28 @@ void ScriptEngine::waitTillDoneRunning() { · 3 unmodified lines | |||
| 301 | // the scripts will likely need to marshall messages across to the main thread, e.g. | 303 | // the scripts will likely need to marshall messages across to the main thread, e.g. |
| 302 | // if they access Settings or Menu in any of their shutdown code. So: | 304 | // if they access Settings or Menu in any of their shutdown code. So: |
| 303 | // Process events for the main application thread, allowing invokeMethod calls to pass between threads. | 305 | // Process events for the main application thread, allowing invokeMethod calls to pass between threads. |
| 304 | QCoreApplication::processEvents(); // thread-safe :) | 306 | QCoreApplication::processEvents(); |
| 305 | 307 | ||
| 306 | // If we've been waiting a second or more, then tell the script engine to stop evaluating | 308 | // If the final evaluation takes too long, then tell the script engine to stop evaluating |
| 307 | static const auto MAX_SCRIPT_EVALUATION_TIME = USECS_PER_SECOND; | 309 | static const auto MAX_SCRIPT_EVALUATION_TIME = USECS_PER_SECOND; |
| 310 | static const auto MAX_SCRIPT_QUITTING_TIME = 0.5 * MAX_SCRIPT_EVALUATION_TIME; | ||
| 308 | auto elapsedUsecs = usecTimestampNow() - startedWaiting; | 311 | auto elapsedUsecs = usecTimestampNow() - startedWaiting; |
| 309 | if (elapsedUsecs > MAX_SCRIPT_EVALUATION_TIME) { | 312 | if (elapsedUsecs > MAX_SCRIPT_EVALUATION_TIME) { |
| 310 | qCDebug(scriptengine) << | 313 | qCDebug(scriptengine).nospace() << |
| 311 | "Script " << scriptName << " has been running too long [" << elapsedUsecs << " usecs] quitting."; | 314 | "Script " << scriptName << " has been running too long [" << elapsedUsecs << "usecs] quitting."; |
| 312 | abortEvaluation(); // to allow the thread to quit | 315 | abortEvaluation(); // break out of current evaluation |
| 313 | workerThread->quit(); | 316 | |
| 314 | break; | 317 | // Wait for the scripting thread to stop running |
| 318 | if (!workerThread->wait(MAX_SCRIPT_QUITTING_TIME)) { | ||
| 319 | qCWarning(scriptengine).nospace() << | ||
| 320 | "Script " << scriptName << " has been quitting too long [" << elapsedUsecs << "usecs] terminating."; | ||
| 321 | workerThread->terminate(); | ||
| 322 | } | ||
| 315 | } | 323 | } |
| 316 | 324 | ||
| 317 | // Avoid a pure busy wait | 325 | // Avoid a pure busy wait |
| 318 | QThread::yieldCurrentThread(); | 326 | QThread::yieldCurrentThread(); |
| 319 | } | 327 | } |
| 320 | |||
| 321 | workerThread->deleteLater(); | ||
| 322 | } | 328 | } |
| 323 | } | 329 | } |
| 324 | 330 | ||