mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 19:59:28 +02:00
Merge pull request #6473 from ZappoMan/waitForScriptThreads
change the ScriptEngine::waitTillDoneRunning() to wait for the script thread to complete
This commit is contained in:
commit
762709748d
3 changed files with 31 additions and 25 deletions
|
@ -122,7 +122,7 @@ void EntityTreeRenderer::init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityTreeRenderer::shutdown() {
|
void EntityTreeRenderer::shutdown() {
|
||||||
_entitiesScriptEngine->disconnect(); // disconnect all slots/signals from the script engine
|
_entitiesScriptEngine->disconnectNonEssentialSignals(); // disconnect all slots/signals from the script engine, except essential
|
||||||
_shuttingDown = true;
|
_shuttingDown = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,14 +124,9 @@ static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName
|
||||||
|
|
||||||
ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString, bool wantSignals) :
|
ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString, bool wantSignals) :
|
||||||
_scriptContents(scriptContents),
|
_scriptContents(scriptContents),
|
||||||
_isFinished(false),
|
|
||||||
_isRunning(false),
|
|
||||||
_isInitialized(false),
|
|
||||||
_timerFunctionMap(),
|
_timerFunctionMap(),
|
||||||
_wantSignals(wantSignals),
|
_wantSignals(wantSignals),
|
||||||
_fileNameString(fileNameString),
|
_fileNameString(fileNameString),
|
||||||
_isUserLoaded(false),
|
|
||||||
_isReloading(false),
|
|
||||||
_arrayBufferClass(new ArrayBufferClass(this))
|
_arrayBufferClass(new ArrayBufferClass(this))
|
||||||
{
|
{
|
||||||
_allScriptsMutex.lock();
|
_allScriptsMutex.lock();
|
||||||
|
@ -140,6 +135,8 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptEngine::~ScriptEngine() {
|
ScriptEngine::~ScriptEngine() {
|
||||||
|
qCDebug(scriptengine) << "Script Engine shutting down (destructor) for script:" << getFilename();
|
||||||
|
|
||||||
// If we're not already in the middle of stopping all scripts, then we should remove ourselves
|
// If we're not already in the middle of stopping all scripts, then we should remove ourselves
|
||||||
// from the list of running scripts. We don't do this if we're in the process of stopping all scripts
|
// from the list of running scripts. We don't do this if we're in the process of stopping all scripts
|
||||||
// because that method removes scripts from its list as it iterates them
|
// because that method removes scripts from its list as it iterates them
|
||||||
|
@ -150,11 +147,21 @@ ScriptEngine::~ScriptEngine() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScriptEngine::disconnectNonEssentialSignals() {
|
||||||
|
disconnect();
|
||||||
|
connect(this, &ScriptEngine::doneRunning, thread(), &QThread::quit);
|
||||||
|
}
|
||||||
|
|
||||||
void ScriptEngine::runInThread() {
|
void ScriptEngine::runInThread() {
|
||||||
|
_isThreaded = true;
|
||||||
QThread* workerThread = new QThread(); // thread is not owned, so we need to manage the delete
|
QThread* workerThread = new QThread(); // thread is not owned, so we need to manage the delete
|
||||||
QString scriptEngineName = QString("Script Thread:") + getFilename();
|
QString scriptEngineName = QString("Script Thread:") + getFilename();
|
||||||
workerThread->setObjectName(scriptEngineName);
|
workerThread->setObjectName(scriptEngineName);
|
||||||
|
|
||||||
|
// NOTE: If you connect any essential signals for proper shutdown or cleanup of
|
||||||
|
// the script engine, make sure to add code to "reconnect" them to the
|
||||||
|
// disconnectNonEssentialSignals() method
|
||||||
|
|
||||||
// when the worker thread is started, call our engine's run..
|
// when the worker thread is started, call our engine's run..
|
||||||
connect(workerThread, &QThread::started, this, &ScriptEngine::run);
|
connect(workerThread, &QThread::started, this, &ScriptEngine::run);
|
||||||
|
|
||||||
|
@ -176,12 +183,13 @@ void ScriptEngine::runInThread() {
|
||||||
QSet<ScriptEngine*> ScriptEngine::_allKnownScriptEngines;
|
QSet<ScriptEngine*> ScriptEngine::_allKnownScriptEngines;
|
||||||
QMutex ScriptEngine::_allScriptsMutex;
|
QMutex ScriptEngine::_allScriptsMutex;
|
||||||
bool ScriptEngine::_stoppingAllScripts = false;
|
bool ScriptEngine::_stoppingAllScripts = false;
|
||||||
bool ScriptEngine::_doneRunningThisScript = false;
|
|
||||||
|
|
||||||
void ScriptEngine::stopAllScripts(QObject* application) {
|
void ScriptEngine::stopAllScripts(QObject* application) {
|
||||||
_allScriptsMutex.lock();
|
_allScriptsMutex.lock();
|
||||||
_stoppingAllScripts = true;
|
_stoppingAllScripts = true;
|
||||||
|
|
||||||
|
qCDebug(scriptengine) << "Stopping all scripts.... currently known scripts:" << _allKnownScriptEngines.size();
|
||||||
|
|
||||||
QMutableSetIterator<ScriptEngine*> i(_allKnownScriptEngines);
|
QMutableSetIterator<ScriptEngine*> i(_allKnownScriptEngines);
|
||||||
while (i.hasNext()) {
|
while (i.hasNext()) {
|
||||||
ScriptEngine* scriptEngine = i.next();
|
ScriptEngine* scriptEngine = i.next();
|
||||||
|
@ -219,7 +227,9 @@ void ScriptEngine::stopAllScripts(QObject* application) {
|
||||||
// We need to wait for the engine to be done running before we proceed, because we don't
|
// We need to wait for the engine to be done running before we proceed, because we don't
|
||||||
// want any of the scripts final "scriptEnding()" or pending "update()" methods from accessing
|
// want any of the scripts final "scriptEnding()" or pending "update()" methods from accessing
|
||||||
// any application state after we leave this stopAllScripts() method
|
// any application state after we leave this stopAllScripts() method
|
||||||
|
qCDebug(scriptengine) << "waiting on script:" << scriptName;
|
||||||
scriptEngine->waitTillDoneRunning();
|
scriptEngine->waitTillDoneRunning();
|
||||||
|
qCDebug(scriptengine) << "done waiting on script:" << scriptName;
|
||||||
|
|
||||||
// If the script is stopped, we can remove it from our set
|
// If the script is stopped, we can remove it from our set
|
||||||
i.remove();
|
i.remove();
|
||||||
|
@ -227,21 +237,19 @@ void ScriptEngine::stopAllScripts(QObject* application) {
|
||||||
}
|
}
|
||||||
_stoppingAllScripts = false;
|
_stoppingAllScripts = false;
|
||||||
_allScriptsMutex.unlock();
|
_allScriptsMutex.unlock();
|
||||||
|
qCDebug(scriptengine) << "DONE Stopping all scripts....";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ScriptEngine::waitTillDoneRunning() {
|
void ScriptEngine::waitTillDoneRunning() {
|
||||||
// If the script never started running or finished running before we got here, we don't need to wait for it
|
// If the script never started running or finished running before we got here, we don't need to wait for it
|
||||||
if (_isRunning) {
|
if (_isRunning && _isThreaded) {
|
||||||
|
|
||||||
_doneRunningThisScript = false; // NOTE: this is static, we serialize our waiting for scripts to finish
|
|
||||||
|
|
||||||
// NOTE: waitTillDoneRunning() will be called on the main Application thread, inside of stopAllScripts()
|
// NOTE: waitTillDoneRunning() will be called on the main Application thread, inside of stopAllScripts()
|
||||||
// we want the application thread to continue to process events, because the scripts will likely need to
|
// we want the application thread to continue to process events, because the scripts will likely need to
|
||||||
// marshall messages across to the main thread. For example if they access Settings or Meny in any of their
|
// marshall messages across to the main thread. For example if they access Settings or Meny in any of their
|
||||||
// shutdown code.
|
// shutdown code.
|
||||||
while (!_doneRunningThisScript) {
|
while (thread()->isRunning()) {
|
||||||
|
|
||||||
// process events for the main application thread, allowing invokeMethod calls to pass between threads
|
// process events for the main application thread, allowing invokeMethod calls to pass between threads
|
||||||
QCoreApplication::processEvents();
|
QCoreApplication::processEvents();
|
||||||
}
|
}
|
||||||
|
@ -752,8 +760,6 @@ void ScriptEngine::run() {
|
||||||
emit runningStateChanged();
|
emit runningStateChanged();
|
||||||
emit doneRunning();
|
emit doneRunning();
|
||||||
}
|
}
|
||||||
|
|
||||||
_doneRunningThisScript = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: This is private because it must be called on the same thread that created the timers, which is why
|
// NOTE: This is private because it must be called on the same thread that created the timers, which is why
|
||||||
|
@ -1168,7 +1174,7 @@ void ScriptEngine::refreshFileScript(const EntityItemID& entityID) {
|
||||||
QString filePath = QUrl(details.scriptText).toLocalFile();
|
QString filePath = QUrl(details.scriptText).toLocalFile();
|
||||||
auto lastModified = QFileInfo(filePath).lastModified().toMSecsSinceEpoch();
|
auto lastModified = QFileInfo(filePath).lastModified().toMSecsSinceEpoch();
|
||||||
if (lastModified > details.lastModified) {
|
if (lastModified > details.lastModified) {
|
||||||
qDebug() << "Reloading modified script " << details.scriptText;
|
qCDebug(scriptengine) << "Reloading modified script " << details.scriptText;
|
||||||
|
|
||||||
QFile file(filePath);
|
QFile file(filePath);
|
||||||
file.open(QIODevice::ReadOnly);
|
file.open(QIODevice::ReadOnly);
|
||||||
|
|
|
@ -128,6 +128,7 @@ public:
|
||||||
bool isFinished() const { return _isFinished; } // used by Application and ScriptWidget
|
bool isFinished() const { return _isFinished; } // used by Application and ScriptWidget
|
||||||
bool isRunning() const { return _isRunning; } // used by ScriptWidget
|
bool isRunning() const { return _isRunning; } // used by ScriptWidget
|
||||||
|
|
||||||
|
void disconnectNonEssentialSignals();
|
||||||
static void stopAllScripts(QObject* application); // used by Application on shutdown
|
static void stopAllScripts(QObject* application); // used by Application on shutdown
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -165,15 +166,16 @@ signals:
|
||||||
protected:
|
protected:
|
||||||
QString _scriptContents;
|
QString _scriptContents;
|
||||||
QString _parentURL;
|
QString _parentURL;
|
||||||
bool _isFinished;
|
bool _isFinished { false };
|
||||||
bool _isRunning;
|
bool _isRunning { false };
|
||||||
int _evaluatesPending = 0;
|
int _evaluatesPending { 0 };
|
||||||
bool _isInitialized;
|
bool _isInitialized { false };
|
||||||
QHash<QTimer*, QScriptValue> _timerFunctionMap;
|
QHash<QTimer*, QScriptValue> _timerFunctionMap;
|
||||||
QSet<QUrl> _includedURLs;
|
QSet<QUrl> _includedURLs;
|
||||||
bool _wantSignals = true;
|
bool _wantSignals { true };
|
||||||
QHash<EntityItemID, EntityScriptDetails> _entityScripts;
|
QHash<EntityItemID, EntityScriptDetails> _entityScripts;
|
||||||
private:
|
bool _isThreaded { false };
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
QString getFilename() const;
|
QString getFilename() const;
|
||||||
void waitTillDoneRunning();
|
void waitTillDoneRunning();
|
||||||
|
@ -191,8 +193,8 @@ private:
|
||||||
Quat _quatLibrary;
|
Quat _quatLibrary;
|
||||||
Vec3 _vec3Library;
|
Vec3 _vec3Library;
|
||||||
ScriptUUID _uuidLibrary;
|
ScriptUUID _uuidLibrary;
|
||||||
bool _isUserLoaded;
|
bool _isUserLoaded { false };
|
||||||
bool _isReloading;
|
bool _isReloading { false };
|
||||||
|
|
||||||
ArrayBufferClass* _arrayBufferClass;
|
ArrayBufferClass* _arrayBufferClass;
|
||||||
|
|
||||||
|
@ -205,8 +207,6 @@ private:
|
||||||
static QSet<ScriptEngine*> _allKnownScriptEngines;
|
static QSet<ScriptEngine*> _allKnownScriptEngines;
|
||||||
static QMutex _allScriptsMutex;
|
static QMutex _allScriptsMutex;
|
||||||
static bool _stoppingAllScripts;
|
static bool _stoppingAllScripts;
|
||||||
static bool _doneRunningThisScript;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_ScriptEngine_h
|
#endif // hifi_ScriptEngine_h
|
||||||
|
|
Loading…
Reference in a new issue