From ce1e1854b129c2e223b399857b2e0c1a842c7186 Mon Sep 17 00:00:00 2001
From: Dr Scofield
Date: Wed, 28 Jan 2009 09:52:09 +0000
Subject: From: Christopher Yeoh <yeohc@au1.ibm.com>

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.


---
 .../ScriptEngine/Interfaces/IScriptInstance.cs     |  1 +
 .../ScriptEngine/Shared/Instance/ScriptInstance.cs | 82 +++++++++++++---------
 OpenSim/Region/ScriptEngine/XEngine/XEngine.cs     | 19 ++---
 3 files changed, 61 insertions(+), 41 deletions(-)

(limited to 'OpenSim')

diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
index 3367b77..017a6ba 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 8d6966f..f808f12 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<int, int>, KeyValuePair<int, int>>
@@ -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();
-                PostEvent(new EventParams("state_entry",
-                                           new Object[0], new DetectParams[0]));
+                if (m_postOnRez) 
+                {
+                    PostEvent(new EventParams("on_rez",
+                        new Object[] {new LSL_Types.LSLInteger(m_StartParam)}, new DetectParams[0]));
+                }
 
-                if (postOnRez)
+                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 (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 fc76d0b..a0a0037 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;
         }
-- 
cgit v1.1