Prevent a race condition between the script engine backup thread and script removal by locking on the script's EventQueue and only proceeding if it's flagged as still running.
Relates to http://opensimulator.org/mantis/view.php?id=74070.8.1-post-fixes
parent
8d724e90de
commit
faaf47a86f
|
@ -178,8 +178,9 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
|
||||||
/// <param name="timeout"></param>
|
/// <param name="timeout"></param>
|
||||||
/// How many milliseconds we will wait for an existing script event to finish before
|
/// How many milliseconds we will wait for an existing script event to finish before
|
||||||
/// forcibly aborting that event.
|
/// forcibly aborting that event.
|
||||||
|
/// <param name="clearEventQueue">If true then the event queue is also cleared</param>
|
||||||
/// <returns>true if the script was successfully stopped, false otherwise</returns>
|
/// <returns>true if the script was successfully stopped, false otherwise</returns>
|
||||||
bool Stop(int timeout);
|
bool Stop(int timeout, bool clearEventQueue = false);
|
||||||
|
|
||||||
void SetState(string state);
|
void SetState(string state);
|
||||||
|
|
||||||
|
|
|
@ -564,7 +564,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Stop(int timeout)
|
public bool Stop(int timeout, bool clearEventQueue = false)
|
||||||
{
|
{
|
||||||
if (DebugLevel >= 1)
|
if (DebugLevel >= 1)
|
||||||
m_log.DebugFormat(
|
m_log.DebugFormat(
|
||||||
|
@ -575,6 +575,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
|
||||||
|
|
||||||
lock (EventQueue)
|
lock (EventQueue)
|
||||||
{
|
{
|
||||||
|
if (clearEventQueue)
|
||||||
|
ClearQueue();
|
||||||
|
|
||||||
if (!Running)
|
if (!Running)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -1065,45 +1068,52 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
|
||||||
|
|
||||||
public void SaveState()
|
public void SaveState()
|
||||||
{
|
{
|
||||||
// If we're currently in an event, just tell it to save upon return
|
// We need to lock here to avoid any race with a thread that is removing this script.
|
||||||
//
|
lock (EventQueue)
|
||||||
if (m_InEvent)
|
|
||||||
{
|
{
|
||||||
m_SaveState = true;
|
if (!Running)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
// m_log.DebugFormat(
|
// If we're currently in an event, just tell it to save upon return
|
||||||
// "[SCRIPT INSTANCE]: Saving state for script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}",
|
//
|
||||||
// ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name);
|
if (m_InEvent)
|
||||||
|
|
||||||
PluginData = AsyncCommandManager.GetSerializationData(Engine, ItemID);
|
|
||||||
|
|
||||||
string xml = ScriptSerializer.Serialize(this);
|
|
||||||
|
|
||||||
// Compare hash of the state we just just created with the state last written to disk
|
|
||||||
// If the state is different, update the disk file.
|
|
||||||
UUID hash = UUID.Parse(Utils.MD5String(xml));
|
|
||||||
|
|
||||||
if (hash != m_CurrentStateHash)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
using (FileStream fs = File.Create(Path.Combine(m_dataPath, ItemID.ToString() + ".state")))
|
m_SaveState = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// m_log.DebugFormat(
|
||||||
|
// "[SCRIPT INSTANCE]: Saving state for script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}",
|
||||||
|
// ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name);
|
||||||
|
|
||||||
|
PluginData = AsyncCommandManager.GetSerializationData(Engine, ItemID);
|
||||||
|
|
||||||
|
string xml = ScriptSerializer.Serialize(this);
|
||||||
|
|
||||||
|
// Compare hash of the state we just just created with the state last written to disk
|
||||||
|
// If the state is different, update the disk file.
|
||||||
|
UUID hash = UUID.Parse(Utils.MD5String(xml));
|
||||||
|
|
||||||
|
if (hash != m_CurrentStateHash)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
Byte[] buf = Util.UTF8NoBomEncoding.GetBytes(xml);
|
using (FileStream fs = File.Create(Path.Combine(m_dataPath, ItemID.ToString() + ".state")))
|
||||||
fs.Write(buf, 0, buf.Length);
|
{
|
||||||
|
Byte[] buf = Util.UTF8NoBomEncoding.GetBytes(xml);
|
||||||
|
fs.Write(buf, 0, buf.Length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
catch(Exception)
|
||||||
|
{
|
||||||
|
// m_log.Error("Unable to save xml\n"+e.ToString());
|
||||||
|
}
|
||||||
|
//if (!File.Exists(Path.Combine(Path.GetDirectoryName(assembly), ItemID.ToString() + ".state")))
|
||||||
|
//{
|
||||||
|
// throw new Exception("Completed persistence save, but no file was created");
|
||||||
|
//}
|
||||||
|
m_CurrentStateHash = hash;
|
||||||
}
|
}
|
||||||
catch(Exception)
|
|
||||||
{
|
|
||||||
// m_log.Error("Unable to save xml\n"+e.ToString());
|
|
||||||
}
|
|
||||||
//if (!File.Exists(Path.Combine(Path.GetDirectoryName(assembly), ItemID.ToString() + ".state")))
|
|
||||||
//{
|
|
||||||
// throw new Exception("Completed persistence save, but no file was created");
|
|
||||||
//}
|
|
||||||
m_CurrentStateHash = hash;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -732,8 +732,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||||
|
|
||||||
// Clear the event queue and abort the instance thread
|
// Clear the event queue and abort the instance thread
|
||||||
//
|
//
|
||||||
instance.ClearQueue();
|
instance.Stop(0, true);
|
||||||
instance.Stop(0);
|
|
||||||
|
|
||||||
// Release events, timer, etc
|
// Release events, timer, etc
|
||||||
//
|
//
|
||||||
|
@ -859,8 +858,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
instances.Clear();
|
|
||||||
|
|
||||||
if (saveTime > 0)
|
if (saveTime > 0)
|
||||||
m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoBackup),
|
m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoBackup),
|
||||||
new Object[] { saveTime });
|
new Object[] { saveTime });
|
||||||
|
@ -1443,6 +1440,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||||
m_Scripts.Remove(itemID);
|
m_Scripts.Remove(itemID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
instance.ClearQueue();
|
instance.ClearQueue();
|
||||||
|
|
||||||
instance.Stop(m_WaitForEventCompletionOnScriptStop);
|
instance.Stop(m_WaitForEventCompletionOnScriptStop);
|
||||||
|
|
Loading…
Reference in New Issue