History

Clean scripting thread deletion

Zach Pomerantz committed 10 years ago

Commit edf82c51 parent 13d60241 file · +30 −24Browse files

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

Unified · Split

libraries/script-engine/src/ScriptEngine.cpp+30−24
@@ -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
169void ScriptEngine::disconnectNonEssentialSignals() {167void ScriptEngine::disconnectNonEssentialSignals() {
170 disconnect();168 disconnect();
171 QThread* receiver;169 QThread* workerThread;
172 // Ensure the thread should be running, and does exist170 // 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 of277 // 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 the278 // the script engine, make sure to add code to "reconnect" them to the
277 // disconnectNonEssentialSignals() method279 // 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
291void ScriptEngine::waitTillDoneRunning() {287void ScriptEngine::waitTillDoneRunning() {
292 // If the script never started running or finished running before we got here, we don't need to wait for it288 // 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 evaluating308 // 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 quit315 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 wait325 // Avoid a pure busy wait
318 QThread::yieldCurrentThread();326 QThread::yieldCurrentThread();
319 }327 }
320
321 workerThread->deleteLater();
322 }328 }
323}329}
324 330