mirror of
https://github.com/overte-org/overte.git
synced 2025-08-04 07:43:35 +02:00
Merge pull request #7853 from zzmp/fix/shutdown
Fix hang on exit from dying scripts
This commit is contained in:
commit
166fbdece5
7 changed files with 33 additions and 38 deletions
|
@ -1156,10 +1156,16 @@ void Application::cleanupBeforeQuit() {
|
||||||
|
|
||||||
getEntities()->shutdown(); // tell the entities system we're shutting down, so it will stop running scripts
|
getEntities()->shutdown(); // tell the entities system we're shutting down, so it will stop running scripts
|
||||||
|
|
||||||
|
// Clear any queued processing (I/O, FBX/OBJ/Texture parsing)
|
||||||
|
QThreadPool::globalInstance()->clear();
|
||||||
|
|
||||||
DependencyManager::get<ScriptEngines>()->saveScripts();
|
DependencyManager::get<ScriptEngines>()->saveScripts();
|
||||||
DependencyManager::get<ScriptEngines>()->shutdownScripting(); // stop all currently running global scripts
|
DependencyManager::get<ScriptEngines>()->shutdownScripting(); // stop all currently running global scripts
|
||||||
DependencyManager::destroy<ScriptEngines>();
|
DependencyManager::destroy<ScriptEngines>();
|
||||||
|
|
||||||
|
// Cleanup all overlays after the scripts, as scripts might add more
|
||||||
|
_overlays.cleanupAllOverlays();
|
||||||
|
|
||||||
// first stop all timers directly or by invokeMethod
|
// first stop all timers directly or by invokeMethod
|
||||||
// depending on what thread they run in
|
// depending on what thread they run in
|
||||||
locationUpdateTimer.stop();
|
locationUpdateTimer.stop();
|
||||||
|
|
|
@ -36,15 +36,8 @@
|
||||||
#include <QtQuick/QQuickWindow>
|
#include <QtQuick/QQuickWindow>
|
||||||
|
|
||||||
|
|
||||||
Overlays::Overlays() : _nextOverlayID(1) {
|
Overlays::Overlays() :
|
||||||
connect(qApp, &Application::beforeAboutToQuit, [=] {
|
_nextOverlayID(1) {}
|
||||||
cleanupAllOverlays();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Overlays::~Overlays() {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Overlays::cleanupAllOverlays() {
|
void Overlays::cleanupAllOverlays() {
|
||||||
{
|
{
|
||||||
|
|
|
@ -62,7 +62,6 @@ class Overlays : public QObject {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Overlays();
|
Overlays();
|
||||||
~Overlays();
|
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
void update(float deltatime);
|
void update(float deltatime);
|
||||||
|
@ -73,6 +72,8 @@ public:
|
||||||
Overlay::Pointer getOverlay(unsigned int id) const;
|
Overlay::Pointer getOverlay(unsigned int id) const;
|
||||||
OverlayPanel::Pointer getPanel(unsigned int id) const { return _panels[id]; }
|
OverlayPanel::Pointer getPanel(unsigned int id) const { return _panels[id]; }
|
||||||
|
|
||||||
|
void cleanupAllOverlays();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
/// adds an overlay with the specific properties
|
/// adds an overlay with the specific properties
|
||||||
unsigned int addOverlay(const QString& type, const QVariant& properties);
|
unsigned int addOverlay(const QString& type, const QVariant& properties);
|
||||||
|
@ -145,7 +146,6 @@ signals:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void cleanupOverlaysToDelete();
|
void cleanupOverlaysToDelete();
|
||||||
void cleanupAllOverlays();
|
|
||||||
|
|
||||||
QMap<unsigned int, Overlay::Pointer> _overlaysHUD;
|
QMap<unsigned int, Overlay::Pointer> _overlaysHUD;
|
||||||
QMap<unsigned int, Overlay::Pointer> _overlaysWorld;
|
QMap<unsigned int, Overlay::Pointer> _overlaysWorld;
|
||||||
|
|
|
@ -62,8 +62,6 @@
|
||||||
|
|
||||||
#include "MIDIEvent.h"
|
#include "MIDIEvent.h"
|
||||||
|
|
||||||
std::atomic<bool> ScriptEngine::_stoppingAllScripts { false };
|
|
||||||
|
|
||||||
static const QString SCRIPT_EXCEPTION_FORMAT = "[UncaughtException] %1 in %2:%3";
|
static const QString SCRIPT_EXCEPTION_FORMAT = "[UncaughtException] %1 in %2:%3";
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(QScriptEngine::FunctionSignature)
|
Q_DECLARE_METATYPE(QScriptEngine::FunctionSignature)
|
||||||
|
@ -756,7 +754,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString&
|
||||||
|
|
||||||
|
|
||||||
QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fileName, int lineNumber) {
|
QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fileName, int lineNumber) {
|
||||||
if (_stoppingAllScripts) {
|
if (DependencyManager::get<ScriptEngines>()->isStopped()) {
|
||||||
return QScriptValue(); // bail early
|
return QScriptValue(); // bail early
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -792,7 +790,7 @@ QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fi
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngine::run() {
|
void ScriptEngine::run() {
|
||||||
if (_stoppingAllScripts) {
|
if (DependencyManager::get<ScriptEngines>()->isStopped()) {
|
||||||
return; // bail early - avoid setting state in init(), as evaluate() will bail too
|
return; // bail early - avoid setting state in init(), as evaluate() will bail too
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1025,7 +1023,7 @@ QObject* ScriptEngine::setupTimerWithInterval(const QScriptValue& function, int
|
||||||
}
|
}
|
||||||
|
|
||||||
QObject* ScriptEngine::setInterval(const QScriptValue& function, int intervalMS) {
|
QObject* ScriptEngine::setInterval(const QScriptValue& function, int intervalMS) {
|
||||||
if (_stoppingAllScripts) {
|
if (DependencyManager::get<ScriptEngines>()->isStopped()) {
|
||||||
qCDebug(scriptengine) << "Script.setInterval() while shutting down is ignored... parent script:" << getFilename();
|
qCDebug(scriptengine) << "Script.setInterval() while shutting down is ignored... parent script:" << getFilename();
|
||||||
return NULL; // bail early
|
return NULL; // bail early
|
||||||
}
|
}
|
||||||
|
@ -1034,7 +1032,7 @@ QObject* ScriptEngine::setInterval(const QScriptValue& function, int intervalMS)
|
||||||
}
|
}
|
||||||
|
|
||||||
QObject* ScriptEngine::setTimeout(const QScriptValue& function, int timeoutMS) {
|
QObject* ScriptEngine::setTimeout(const QScriptValue& function, int timeoutMS) {
|
||||||
if (_stoppingAllScripts) {
|
if (DependencyManager::get<ScriptEngines>()->isStopped()) {
|
||||||
qCDebug(scriptengine) << "Script.setTimeout() while shutting down is ignored... parent script:" << getFilename();
|
qCDebug(scriptengine) << "Script.setTimeout() while shutting down is ignored... parent script:" << getFilename();
|
||||||
return NULL; // bail early
|
return NULL; // bail early
|
||||||
}
|
}
|
||||||
|
@ -1086,7 +1084,7 @@ void ScriptEngine::print(const QString& message) {
|
||||||
// If no callback is specified, the included files will be loaded synchronously and will block execution until
|
// If no callback is specified, the included files will be loaded synchronously and will block execution until
|
||||||
// all of the files have finished loading.
|
// all of the files have finished loading.
|
||||||
void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callback) {
|
void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callback) {
|
||||||
if (_stoppingAllScripts) {
|
if (DependencyManager::get<ScriptEngines>()->isStopped()) {
|
||||||
qCDebug(scriptengine) << "Script.include() while shutting down is ignored..."
|
qCDebug(scriptengine) << "Script.include() while shutting down is ignored..."
|
||||||
<< "includeFiles:" << includeFiles << "parent script:" << getFilename();
|
<< "includeFiles:" << includeFiles << "parent script:" << getFilename();
|
||||||
return; // bail early
|
return; // bail early
|
||||||
|
@ -1184,7 +1182,7 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngine::include(const QString& includeFile, QScriptValue callback) {
|
void ScriptEngine::include(const QString& includeFile, QScriptValue callback) {
|
||||||
if (_stoppingAllScripts) {
|
if (DependencyManager::get<ScriptEngines>()->isStopped()) {
|
||||||
qCDebug(scriptengine) << "Script.include() while shutting down is ignored... "
|
qCDebug(scriptengine) << "Script.include() while shutting down is ignored... "
|
||||||
<< "includeFile:" << includeFile << "parent script:" << getFilename();
|
<< "includeFile:" << includeFile << "parent script:" << getFilename();
|
||||||
return; // bail early
|
return; // bail early
|
||||||
|
@ -1199,7 +1197,7 @@ void ScriptEngine::include(const QString& includeFile, QScriptValue callback) {
|
||||||
// as a stand-alone script. To accomplish this, the ScriptEngine class just emits a signal which
|
// as a stand-alone script. To accomplish this, the ScriptEngine class just emits a signal which
|
||||||
// the Application or other context will connect to in order to know to actually load the script
|
// the Application or other context will connect to in order to know to actually load the script
|
||||||
void ScriptEngine::load(const QString& loadFile) {
|
void ScriptEngine::load(const QString& loadFile) {
|
||||||
if (_stoppingAllScripts) {
|
if (DependencyManager::get<ScriptEngines>()->isStopped()) {
|
||||||
qCDebug(scriptengine) << "Script.load() while shutting down is ignored... "
|
qCDebug(scriptengine) << "Script.load() while shutting down is ignored... "
|
||||||
<< "loadFile:" << loadFile << "parent script:" << getFilename();
|
<< "loadFile:" << loadFile << "parent script:" << getFilename();
|
||||||
return; // bail early
|
return; // bail early
|
||||||
|
|
|
@ -83,6 +83,10 @@ public:
|
||||||
/// run the script in the callers thread, exit when stop() is called.
|
/// run the script in the callers thread, exit when stop() is called.
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
|
void waitTillDoneRunning();
|
||||||
|
|
||||||
|
QString getFilename() const;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// NOTE - these are NOT intended to be public interfaces available to scripts, the are only Q_INVOKABLE so we can
|
// NOTE - these are NOT intended to be public interfaces available to scripts, the are only Q_INVOKABLE so we can
|
||||||
// properly ensure they are only called on the correct thread
|
// properly ensure they are only called on the correct thread
|
||||||
|
@ -199,8 +203,6 @@ protected:
|
||||||
qint64 _lastUpdate;
|
qint64 _lastUpdate;
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
QString getFilename() const;
|
|
||||||
void waitTillDoneRunning();
|
|
||||||
bool evaluatePending() const { return _evaluatesPending > 0; }
|
bool evaluatePending() const { return _evaluatesPending > 0; }
|
||||||
void timerFired();
|
void timerFired();
|
||||||
void stopAllTimers();
|
void stopAllTimers();
|
||||||
|
@ -232,9 +234,6 @@ protected:
|
||||||
QUrl currentSandboxURL {}; // The toplevel url string for the entity script that loaded the code being executed, else empty.
|
QUrl currentSandboxURL {}; // The toplevel url string for the entity script that loaded the code being executed, else empty.
|
||||||
void doWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, std::function<void()> operation);
|
void doWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, std::function<void()> operation);
|
||||||
void callWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, QScriptValue function, QScriptValue thisObject, QScriptValueList args);
|
void callWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, QScriptValue function, QScriptValue thisObject, QScriptValueList args);
|
||||||
|
|
||||||
friend class ScriptEngines;
|
|
||||||
static std::atomic<bool> _stoppingAllScripts;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_ScriptEngine_h
|
#endif // hifi_ScriptEngine_h
|
||||||
|
|
|
@ -119,26 +119,27 @@ void ScriptEngines::registerScriptInitializer(ScriptInitializer initializer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngines::addScriptEngine(ScriptEngine* engine) {
|
void ScriptEngines::addScriptEngine(ScriptEngine* engine) {
|
||||||
_allScriptsMutex.lock();
|
if (_isStopped) {
|
||||||
|
engine->deleteLater();
|
||||||
|
} else {
|
||||||
|
QMutexLocker locker(&_allScriptsMutex);
|
||||||
_allKnownScriptEngines.insert(engine);
|
_allKnownScriptEngines.insert(engine);
|
||||||
_allScriptsMutex.unlock();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngines::removeScriptEngine(ScriptEngine* engine) {
|
void ScriptEngines::removeScriptEngine(ScriptEngine* engine) {
|
||||||
// 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
|
||||||
if (!_stoppingAllScripts) {
|
if (!_isStopped) {
|
||||||
_allScriptsMutex.lock();
|
QMutexLocker locker(&_allScriptsMutex);
|
||||||
_allKnownScriptEngines.remove(engine);
|
_allKnownScriptEngines.remove(engine);
|
||||||
_allScriptsMutex.unlock();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngines::shutdownScripting() {
|
void ScriptEngines::shutdownScripting() {
|
||||||
_allScriptsMutex.lock();
|
_isStopped = true;
|
||||||
_stoppingAllScripts = true;
|
QMutexLocker locker(&_allScriptsMutex);
|
||||||
ScriptEngine::_stoppingAllScripts = true;
|
|
||||||
qCDebug(scriptengine) << "Stopping all scripts.... currently known scripts:" << _allKnownScriptEngines.size();
|
qCDebug(scriptengine) << "Stopping all scripts.... currently known scripts:" << _allKnownScriptEngines.size();
|
||||||
|
|
||||||
QMutableSetIterator<ScriptEngine*> i(_allKnownScriptEngines);
|
QMutableSetIterator<ScriptEngine*> i(_allKnownScriptEngines);
|
||||||
|
@ -174,8 +175,6 @@ void ScriptEngines::shutdownScripting() {
|
||||||
i.remove();
|
i.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_stoppingAllScripts = false;
|
|
||||||
_allScriptsMutex.unlock();
|
|
||||||
qCDebug(scriptengine) << "DONE Stopping all scripts....";
|
qCDebug(scriptengine) << "DONE Stopping all scripts....";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -499,7 +498,6 @@ void ScriptEngines::launchScriptEngine(ScriptEngine* scriptEngine) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ScriptEngines::onScriptFinished(const QString& rawScriptURL, ScriptEngine* engine) {
|
void ScriptEngines::onScriptFinished(const QString& rawScriptURL, ScriptEngine* engine) {
|
||||||
bool removed = false;
|
bool removed = false;
|
||||||
{
|
{
|
||||||
|
|
|
@ -86,16 +86,17 @@ protected:
|
||||||
void onScriptEngineLoaded(const QString& scriptFilename);
|
void onScriptEngineLoaded(const QString& scriptFilename);
|
||||||
void onScriptEngineError(const QString& scriptFilename);
|
void onScriptEngineError(const QString& scriptFilename);
|
||||||
void launchScriptEngine(ScriptEngine* engine);
|
void launchScriptEngine(ScriptEngine* engine);
|
||||||
|
bool isStopped() const { return _isStopped; }
|
||||||
|
|
||||||
QReadWriteLock _scriptEnginesHashLock;
|
QReadWriteLock _scriptEnginesHashLock;
|
||||||
QHash<QUrl, ScriptEngine*> _scriptEnginesHash;
|
QHash<QUrl, ScriptEngine*> _scriptEnginesHash;
|
||||||
QSet<ScriptEngine*> _allKnownScriptEngines;
|
QSet<ScriptEngine*> _allKnownScriptEngines;
|
||||||
QMutex _allScriptsMutex;
|
QMutex _allScriptsMutex;
|
||||||
std::atomic<bool> _stoppingAllScripts { false };
|
|
||||||
std::list<ScriptInitializer> _scriptInitializers;
|
std::list<ScriptInitializer> _scriptInitializers;
|
||||||
mutable Setting::Handle<QString> _scriptsLocationHandle;
|
mutable Setting::Handle<QString> _scriptsLocationHandle;
|
||||||
ScriptsModel _scriptsModel;
|
ScriptsModel _scriptsModel;
|
||||||
ScriptsModelFilter _scriptsModelFilter;
|
ScriptsModelFilter _scriptsModelFilter;
|
||||||
|
std::atomic<bool> _isStopped { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
QUrl normalizeScriptURL(const QUrl& rawScriptURL);
|
QUrl normalizeScriptURL(const QUrl& rawScriptURL);
|
||||||
|
|
Loading…
Reference in a new issue