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.
0.6.3-post-fixes
Dr Scofield 2009-01-28 09:52:09 +00:00
parent a3ac702941
commit ce1e1854b1
3 changed files with 61 additions and 41 deletions

View File

@ -73,6 +73,7 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
void RemoveState(); void RemoveState();
void Init();
void Start(); void Start();
bool Stop(int timeout); bool Stop(int timeout);
void SetState(string state); void SetState(string state);

View File

@ -88,6 +88,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
private double m_minEventDelay = 0; private double m_minEventDelay = 0;
private long m_eventDelayTicks = 0; private long m_eventDelayTicks = 0;
private long m_nextEventTimeTicks = 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 ISponsor m_ScriptSponsor;
private Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> private Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>
@ -224,6 +228,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
m_Assembly = assembly; m_Assembly = assembly;
m_StartParam = startParam; m_StartParam = startParam;
m_MaxScriptQueue = maxScriptQueue; m_MaxScriptQueue = maxScriptQueue;
m_stateSource = stateSource;
m_postOnRez = postOnRez;
if (part != null && part.TaskInventory.ContainsKey(m_ItemID)) if (part != null && part.TaskInventory.ContainsKey(m_ItemID))
{ {
@ -313,10 +319,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
if (m_RunEvents && (!m_ShuttingDown)) if (m_RunEvents && (!m_ShuttingDown))
{ {
m_RunEvents = false; m_RunEvents = false;
Start(); }
if (postOnRez) else
PostEvent(new EventParams("on_rez", {
new Object[] {new LSL_Types.LSLInteger(startParam)}, new DetectParams[0])); m_RunEvents = false;
m_startOnInit = false;
} }
// we get new rez events on sim restart, too // 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 // We loaded state, don't force a re-save
m_SaveState = false; 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 else
{ {
m_Engine.Log.Error("[Script] Unable to load script state: Memory limit exceeded"); 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) catch (Exception e)
{ {
m_Engine.Log.ErrorFormat("[Script] Unable to load script state from xml: {0}\n"+e.ToString(), xml); 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 else
@ -371,13 +354,46 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
presence.ControllingClient.SendAgentAlertMessage("Compile successful", false); presence.ControllingClient.SendAgentAlertMessage("Compile successful", false);
// m_Engine.Log.ErrorFormat("[Script] Unable to load script state, file not found"); // 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(); Start();
PostEvent(new EventParams("state_entry", PostEvent(new EventParams("state_entry",
new Object[0], new DetectParams[0])); new Object[0], new DetectParams[0]));
if (m_postOnRez)
if (postOnRez) {
PostEvent(new EventParams("on_rez", 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]));
}
} }
} }

View File

@ -544,6 +544,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
lock (m_Scripts) lock (m_Scripts)
{ {
ScriptInstance instance = null;
// Create the object record // Create the object record
if ((!m_Scripts.ContainsKey(itemID)) || if ((!m_Scripts.ContainsKey(itemID)) ||
@ -596,13 +597,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine
} }
m_DomainScripts[appDomain].Add(itemID); m_DomainScripts[appDomain].Add(itemID);
ScriptInstance instance = instance = new ScriptInstance(this, part,
new ScriptInstance(this, part, itemID, assetID, assembly,
itemID, assetID, assembly, m_AppDomains[appDomain],
m_AppDomains[appDomain], part.ParentGroup.RootPart.Name,
part.ParentGroup.RootPart.Name, item.Name, startParam, postOnRez,
item.Name, startParam, postOnRez, stateSource, m_MaxScriptQueue);
stateSource, m_MaxScriptQueue);
m_log.DebugFormat("[XEngine] Loaded script {0}.{1}", m_log.DebugFormat("[XEngine] Loaded script {0}.{1}",
part.ParentGroup.RootPart.Name, item.Name); part.ParentGroup.RootPart.Name, item.Name);
@ -625,6 +625,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine
if (!m_Assemblies.ContainsKey(assetID)) if (!m_Assemblies.ContainsKey(assetID))
m_Assemblies[assetID] = assembly; m_Assemblies[assetID] = assembly;
if (instance!=null)
instance.Init();
} }
return true; return true;
} }