From ce1e1854b129c2e223b399857b2e0c1a842c7186 Mon Sep 17 00:00:00 2001 From: Dr Scofield Date: Wed, 28 Jan 2009 09:52:09 +0000 Subject: [PATCH] From: Christopher Yeoh This changeset fixes a race condition where a script (XEngine run) can startup before a reference is added to it in all of the required places in the XEngine class. The effect of this is that a script can sometimes on startup miss script events. For example a script which starts up and initialises itself from a notecard may never receive the dataserver event containing the notecard information. The patch isn't as clean as I'd like - I've split the constructor of ScriptInstance up so it does everything it did before except call Startup and post events like state_entry and on_rez. An Init function has been added which is called after the ScriptInstance object has been added to the necessary data structures in XEngine. Happy to rework it if someone suggests a better way of doing it. --- .../Interfaces/IScriptInstance.cs | 1 + .../Shared/Instance/ScriptInstance.cs | 82 +++++++++++-------- .../Region/ScriptEngine/XEngine/XEngine.cs | 19 +++-- 3 files changed, 61 insertions(+), 41 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs index 3367b7703c..017a6babad 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs @@ -73,6 +73,7 @@ namespace OpenSim.Region.ScriptEngine.Interfaces void RemoveState(); + void Init(); void Start(); bool Stop(int timeout); void SetState(string state); diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index 8d6966ff2a..f808f12df7 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -88,6 +88,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance private double m_minEventDelay = 0; private long m_eventDelayTicks = 0; private long m_nextEventTimeTicks = 0; + private bool m_startOnInit = true; + private StateSource m_stateSource; + private bool m_postOnRez; + private bool m_startedFromSavedState = false; //private ISponsor m_ScriptSponsor; private Dictionary, KeyValuePair> @@ -224,6 +228,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance m_Assembly = assembly; m_StartParam = startParam; m_MaxScriptQueue = maxScriptQueue; + m_stateSource = stateSource; + m_postOnRez = postOnRez; if (part != null && part.TaskInventory.ContainsKey(m_ItemID)) { @@ -313,10 +319,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance if (m_RunEvents && (!m_ShuttingDown)) { m_RunEvents = false; - Start(); - if (postOnRez) - PostEvent(new EventParams("on_rez", - new Object[] {new LSL_Types.LSLInteger(startParam)}, new DetectParams[0])); + } + else + { + m_RunEvents = false; + m_startOnInit = false; } // we get new rez events on sim restart, too @@ -325,42 +332,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance // We loaded state, don't force a re-save m_SaveState = false; + m_startedFromSavedState = true; - if (stateSource == StateSource.NewRez) - { -// m_Engine.Log.Debug("[Script] Posted changed(CHANGED_REGION_RESTART) to script"); - PostEvent(new EventParams("changed", - new Object[] {new LSL_Types.LSLInteger(256)}, new DetectParams[0])); - } - else if (stateSource == StateSource.PrimCrossing) - { - // CHANGED_REGION - PostEvent(new EventParams("changed", - new Object[] {new LSL_Types.LSLInteger(512)}, new DetectParams[0])); - } } } else { m_Engine.Log.Error("[Script] Unable to load script state: Memory limit exceeded"); - Start(); - PostEvent(new EventParams("state_entry", - new Object[0], new DetectParams[0])); - if (postOnRez) - PostEvent(new EventParams("on_rez", - new Object[] {new LSL_Types.LSLInteger(startParam)}, new DetectParams[0])); - } } catch (Exception e) { m_Engine.Log.ErrorFormat("[Script] Unable to load script state from xml: {0}\n"+e.ToString(), xml); - Start(); - PostEvent(new EventParams("state_entry", - new Object[0], new DetectParams[0])); - if (postOnRez) - PostEvent(new EventParams("on_rez", - new Object[] {new LSL_Types.LSLInteger(startParam)}, new DetectParams[0])); } } else @@ -371,13 +354,46 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance presence.ControllingClient.SendAgentAlertMessage("Compile successful", false); // m_Engine.Log.ErrorFormat("[Script] Unable to load script state, file not found"); + } + } + + public void Init() + { + if (!m_startOnInit) return; + + if (m_startedFromSavedState) + { + Start(); + if (m_postOnRez) + { + PostEvent(new EventParams("on_rez", + new Object[] {new LSL_Types.LSLInteger(m_StartParam)}, new DetectParams[0])); + } + + if (m_stateSource == StateSource.NewRez) + { +// m_Engine.Log.Debug("[Script] Posted changed(CHANGED_REGION_RESTART) to script"); + PostEvent(new EventParams("changed", + new Object[] {new LSL_Types.LSLInteger(256)}, new DetectParams[0])); + } + else if (m_stateSource == StateSource.PrimCrossing) + { + // CHANGED_REGION + PostEvent(new EventParams("changed", + new Object[] {new LSL_Types.LSLInteger(512)}, new DetectParams[0])); + } + } + else + { Start(); PostEvent(new EventParams("state_entry", - new Object[0], new DetectParams[0])); - - if (postOnRez) + new Object[0], new DetectParams[0])); + if (m_postOnRez) + { PostEvent(new EventParams("on_rez", - new Object[] {new LSL_Types.LSLInteger(startParam)}, new DetectParams[0])); + new Object[] {new LSL_Types.LSLInteger(m_StartParam)}, new DetectParams[0])); + } + } } diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index fc76d0b297..a0a00370f3 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -544,6 +544,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine lock (m_Scripts) { + ScriptInstance instance = null; // Create the object record if ((!m_Scripts.ContainsKey(itemID)) || @@ -596,14 +597,13 @@ namespace OpenSim.Region.ScriptEngine.XEngine } m_DomainScripts[appDomain].Add(itemID); - ScriptInstance instance = - new ScriptInstance(this, part, - itemID, assetID, assembly, - m_AppDomains[appDomain], - part.ParentGroup.RootPart.Name, - item.Name, startParam, postOnRez, - stateSource, m_MaxScriptQueue); - + instance = new ScriptInstance(this, part, + itemID, assetID, assembly, + m_AppDomains[appDomain], + part.ParentGroup.RootPart.Name, + item.Name, startParam, postOnRez, + stateSource, m_MaxScriptQueue); + m_log.DebugFormat("[XEngine] Loaded script {0}.{1}", part.ParentGroup.RootPart.Name, item.Name); @@ -625,6 +625,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine if (!m_Assemblies.ContainsKey(assetID)) m_Assemblies[assetID] = assembly; + + if (instance!=null) + instance.Init(); } return true; }