first cut at shutting down scripts ahead of other cleanup

This commit is contained in:
ZappoMan 2015-02-20 15:28:25 -08:00
parent 70400f7f8c
commit 0b607fa390
5 changed files with 270 additions and 148 deletions

View file

@ -527,12 +527,22 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
}
void Application::aboutToQuit() {
qDebug() << "Application::aboutToQuit()";
_aboutToQuit = true;
cleanupBeforeQuit();
}
void Application::cleanupBeforeQuit() {
qDebug() << "Application::cleanupBeforeQuit() ------------ START -----------------";
// stop entities running scripts
_entities.shutdown();
// stop all running scripts
ScriptEngine::gracefullyStopAllScripts();
// first stop all timers directly or by invokeMethod
// depending on what thread they run in
locationUpdateTimer->stop();
@ -572,6 +582,8 @@ void Application::cleanupBeforeQuit() {
// destroy the AudioClient so it and its thread have a chance to go down safely
DependencyManager::destroy<AudioClient>();
qDebug() << "Application::cleanupBeforeQuit() ------------ DONE -----------------";
}
Application::~Application() {
@ -3432,6 +3444,7 @@ void Application::clearScriptsBeforeRunning() {
}
void Application::saveScripts() {
qDebug() << "Application::saveScripts()";
// Saves all currently running user-loaded scripts
Settings settings;
settings.beginWriteArray(SETTINGS_KEY);
@ -3525,7 +3538,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
#endif
QThread* workerThread = new QThread(this);
workerThread->setObjectName("Script Engine Thread");
QString scriptEngineName = QString("Script Thread:") + scriptEngine->getFilename();
workerThread->setObjectName(scriptEngineName);
// when the worker thread is started, call our engine's run..
connect(workerThread, &QThread::started, scriptEngine, &ScriptEngine::run);
@ -3599,6 +3613,7 @@ void Application::handleScriptLoadError(const QString& scriptFilename) {
}
void Application::scriptFinished(const QString& scriptName) {
qDebug() << "Application::scriptFinished(), scriptName:" << scriptName;
const QString& scriptURLString = QUrl(scriptName).toString();
QHash<QString, ScriptEngine*>::iterator it = _scriptEnginesHash.find(scriptURLString);
if (it != _scriptEnginesHash.end()) {
@ -3609,6 +3624,7 @@ void Application::scriptFinished(const QString& scriptName) {
}
void Application::stopAllScripts(bool restart) {
qDebug() << "Application::stopAllScripts()... restart:" << restart;
// stops all current running scripts
for (QHash<QString, ScriptEngine*>::const_iterator it = _scriptEnginesHash.constBegin();
it != _scriptEnginesHash.constEnd(); it++) {

View file

@ -97,6 +97,27 @@ void EntityTreeRenderer::init() {
connect(entityTree, &EntityTree::changingEntityID, this, &EntityTreeRenderer::changingEntityID);
}
void EntityTreeRenderer::shutdown() {
_shuttingDown = true;
/*
if (_entitiesScriptEngine) {
_entitiesScriptEngine->stop();
QEventLoop loop;
QObject::connect(_entitiesScriptEngine, &ScriptEngine::doneRunning, &loop, &QEventLoop::quit);
_entitiesScriptEngine->stop();
qDebug() << "waiting on Entities sandbox script to stop... ";
loop.exec();
qDebug() << "done waiting... ";
}
*/
}
QScriptValue EntityTreeRenderer::loadEntityScript(const EntityItemID& entityItemID) {
EntityItem* entity = static_cast<EntityTree*>(_tree)->findEntityByEntityItemID(entityItemID);
return loadEntityScript(entity);
@ -156,6 +177,10 @@ QString EntityTreeRenderer::loadScriptContents(const QString& scriptMaybeURLorTe
QScriptValue EntityTreeRenderer::loadEntityScript(EntityItem* entity) {
if (_shuttingDown) {
return QScriptValue(); // no entity...
}
if (!entity) {
return QScriptValue(); // no entity...
}
@ -235,7 +260,7 @@ void EntityTreeRenderer::setTree(Octree* newTree) {
}
void EntityTreeRenderer::update() {
if (_tree) {
if (_tree && !_shuttingDown) {
EntityTree* tree = static_cast<EntityTree*>(_tree);
tree->update();
@ -258,7 +283,7 @@ void EntityTreeRenderer::update() {
}
void EntityTreeRenderer::checkEnterLeaveEntities() {
if (_tree) {
if (_tree && !_shuttingDown) {
_tree->lockForWrite(); // so that our scripts can do edits if they want
glm::vec3 avatarPosition = _viewState->getAvatarPosition() / (float) TREE_SCALE;
@ -309,7 +334,7 @@ void EntityTreeRenderer::checkEnterLeaveEntities() {
}
void EntityTreeRenderer::leaveAllEntities() {
if (_tree) {
if (_tree && !_shuttingDown) {
_tree->lockForWrite(); // so that our scripts can do edits if they want
// for all of our previous containing entities, if they are no longer containing then send them a leave event
@ -330,7 +355,7 @@ void EntityTreeRenderer::leaveAllEntities() {
}
}
void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, RenderArgs::RenderSide renderSide) {
if (_tree) {
if (_tree && !_shuttingDown) {
Model::startScene(renderSide);
RenderArgs args = { this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode, renderSide,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
@ -700,6 +725,7 @@ QScriptValueList EntityTreeRenderer::createEntityArgs(const EntityItemID& entity
}
void EntityTreeRenderer::mousePressEvent(QMouseEvent* event, unsigned int deviceID) {
if (_tree && !_shuttingDown) {
PerformanceTimer perfTimer("EntityTreeRenderer::mousePressEvent");
PickRay ray = _viewState->computePickRay(event->x(), event->y());
@ -724,8 +750,10 @@ void EntityTreeRenderer::mousePressEvent(QMouseEvent* event, unsigned int device
_lastMouseEvent = MouseEvent(*event, deviceID);
_lastMouseEventValid = true;
}
}
void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) {
if (_tree && !_shuttingDown) {
PerformanceTimer perfTimer("EntityTreeRenderer::mouseReleaseEvent");
PickRay ray = _viewState->computePickRay(event->x(), event->y());
bool precisionPicking = !_dontDoPrecisionPicking;
@ -758,8 +786,10 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event, unsigned int devi
_lastMouseEvent = MouseEvent(*event, deviceID);
_lastMouseEventValid = true;
}
}
void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) {
if (_tree && !_shuttingDown) {
PerformanceTimer perfTimer("EntityTreeRenderer::mouseMoveEvent");
PickRay ray = _viewState->computePickRay(event->x(), event->y());
@ -848,18 +878,24 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceI
_lastMouseEvent = MouseEvent(*event, deviceID);
_lastMouseEventValid = true;
}
}
void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) {
if (_tree && !_shuttingDown) {
checkAndCallUnload(entityID);
}
_entityScripts.remove(entityID);
}
void EntityTreeRenderer::entitySciptChanging(const EntityItemID& entityID) {
if (_tree && !_shuttingDown) {
checkAndCallUnload(entityID);
}
checkAndCallPreload(entityID);
}
void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID) {
if (_tree && !_shuttingDown) {
// load the entity script if needed...
QScriptValue entityScript = loadEntityScript(entityID);
if (entityScript.property("preload").isValid()) {
@ -867,14 +903,17 @@ void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID) {
entityScript.property("preload").call(entityScript, entityArgs);
}
}
}
void EntityTreeRenderer::checkAndCallUnload(const EntityItemID& entityID) {
if (_tree && !_shuttingDown) {
QScriptValue entityScript = getPreviouslyLoadedEntityScript(entityID);
if (entityScript.property("unload").isValid()) {
QScriptValueList entityArgs = createEntityArgs(entityID);
entityScript.property("unload").call(entityScript, entityArgs);
}
}
}
void EntityTreeRenderer::changingEntityID(const EntityItemID& oldEntityID, const EntityItemID& newEntityID) {
@ -887,6 +926,7 @@ void EntityTreeRenderer::changingEntityID(const EntityItemID& oldEntityID, const
void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB,
const Collision& collision) {
if (_tree && !_shuttingDown) {
QScriptValue entityScriptA = loadEntityScript(idA);
if (entityScriptA.property("collisionWithEntity").isValid()) {
QScriptValueList args;
@ -905,4 +945,5 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons
entityScriptB.property("collisionWithEntity").call(entityScriptA, args);
}
}
}

View file

@ -46,6 +46,7 @@ public:
virtual int getBoundaryLevelAdjust() const;
virtual void setTree(Octree* newTree);
void shutdown();
void update();
EntityTree* getTree() { return static_cast<EntityTree*>(_tree); }
@ -154,6 +155,8 @@ private:
bool _displayModelElementProxy;
bool _dontDoPrecisionPicking;
bool _shuttingDown = false;
};
#endif // hifi_EntityTreeRenderer_h

View file

@ -94,8 +94,45 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam
_isUserLoaded(false),
_arrayBufferClass(new ArrayBufferClass(this))
{
_allKnownScriptEngines.insert(this);
}
ScriptEngine::~ScriptEngine() {
qDebug() << "[" << QThread::currentThread() << "]" << "ScriptEngine::~ScriptEngine() " << getFilename();
_allKnownScriptEngines.remove(this);
}
QSet<ScriptEngine*> ScriptEngine::_allKnownScriptEngines;
void ScriptEngine::gracefullyStopAllScripts() {
qDebug() << "[" << QThread::currentThread() << "]" << "ScriptEngine::gracefullyStopAllScripts() ----------- START ------------------";
foreach(ScriptEngine* scriptEngine, _allKnownScriptEngines) {
if (scriptEngine->isRunning()) {
qDebug() << "scriptEngine still alive:" << scriptEngine->getFilename() << "[" << scriptEngine << "]";
QEventLoop loop;
QObject::connect(scriptEngine, &ScriptEngine::doneRunning, &loop, &QEventLoop::quit);
scriptEngine->stop();
qDebug() << "waiting on script to stop... ";
loop.exec();
qDebug() << "done waiting... ";
}
}
qDebug() << "[" << QThread::currentThread() << "]" << "ScriptEngine::gracefullyStopAllScripts() ----------- DONE ------------------";
}
QString ScriptEngine::getFilename() const {
QStringList fileNameParts = _fileNameString.split("/");
QString lastPart;
if (!fileNameParts.isEmpty()) {
lastPart = fileNameParts.last();
}
return lastPart;
}
void ScriptEngine::setIsAvatar(bool isAvatar) {
_isAvatar = isAvatar;
@ -364,16 +401,18 @@ void ScriptEngine::run() {
}
if (_isFinished) {
qDebug() << "ScriptEngine::run()... while() about to break " << getFilename();
break;
}
QCoreApplication::processEvents();
if (_isFinished) {
qDebug() << "ScriptEngine::run()... while() about to break " << getFilename();
break;
}
if (_entityScriptingInterface.getEntityPacketSender()->serversExist()) {
if (!_isFinished && _entityScriptingInterface.getEntityPacketSender()->serversExist()) {
// release the queue of edit entity messages.
_entityScriptingInterface.getEntityPacketSender()->releaseQueuedMessages();
@ -383,7 +422,7 @@ void ScriptEngine::run() {
}
}
if (_isAvatar && _avatarData) {
if (!_isFinished && _isAvatar && _avatarData) {
const int SCRIPT_AUDIO_BUFFER_SAMPLES = floor(((SCRIPT_DATA_CALLBACK_USECS * AudioConstants::SAMPLE_RATE)
/ (1000 * 1000)) + 0.5);
@ -493,9 +532,13 @@ void ScriptEngine::run() {
clearExceptions();
}
if (!_isFinished) {
//qDebug() << "ScriptEngine::run()... about to emit update() _scriptName:" << _scriptName << "_fileNameString:" << _fileNameString << "_isFinished:" << _isFinished;
emit update(deltaTime);
}
lastUpdate = now;
}
qDebug() << "ScriptEngine::run()... about to emit scriptEnding() " << getFilename();
emit scriptEnding();
// kill the avatar identity timer
@ -513,16 +556,25 @@ void ScriptEngine::run() {
// If we were on a thread, then wait till it's done
if (thread()) {
qDebug() << "ScriptEngine::run()... about to call thread()->quit() " << getFilename();
thread()->quit();
}
qDebug() << "ScriptEngine::run()... about to emit finished() " << getFilename();
emit finished(_fileNameString);
_isRunning = false;
qDebug() << "ScriptEngine::run()... about to emit runningStateChanged() " << getFilename();
emit runningStateChanged();
qDebug() << "ScriptEngine::run()... about to emit doneRunning() " << getFilename();
emit doneRunning();
qDebug() << "ScriptEngine::run()... DONE WITH run()... " << getFilename();
}
void ScriptEngine::stop() {
qDebug() << "ScriptEngine::stop()... " << getFilename();
_isFinished = true;
emit runningStateChanged();
}

View file

@ -43,6 +43,8 @@ public:
const QString& fileNameString = QString(""),
AbstractControllerScriptingInterface* controllerScriptingInterface = NULL);
~ScriptEngine();
/// Access the EntityScriptingInterface in order to initialize it with a custom packet sender and jurisdiction listener
static EntityScriptingInterface* getEntityScriptingInterface() { return &_entityScriptingInterface; }
@ -89,6 +91,10 @@ public:
void setParentURL(const QString& parentURL) { _parentURL = parentURL; }
QString getFilename() const;
static void gracefullyStopAllScripts();
public slots:
void loadURL(const QUrl& scriptURL);
void stop();
@ -118,6 +124,7 @@ signals:
void runningStateChanged();
void evaluationFinished(QScriptValue result, bool isException);
void loadScript(const QString& scriptName, bool isUserLoaded);
void doneRunning();
protected:
QString _scriptContents;
@ -156,6 +163,9 @@ private:
QHash<QUuid, quint16> _outgoingScriptAudioSequenceNumbers;
private slots:
void handleScriptDownload();
private:
static QSet<ScriptEngine*> _allKnownScriptEngines;
};
#endif // hifi_ScriptEngine_h