Avoid a possible race condition by serializing plugin data outside the EventQueue lock in ScriptInstance.SaveState()

This takes the AsyncCommandHandler.staticLock.
However, AsyncCommandHandler.DoOneCmdHandlerPass() already holds staticLock and may attempt to take the EventQueue lock via ScriptInstance.PostEvent() in XEngine.CheckListeners()
This is a regression from faaf47a (Fri Jan 16 2015) but not simply reverting that commit since it will reintroduce a race between script removal, backup and event queue manipulating code.
0.8.1-post-fixes
Justin Clark-Casey (justincc) 2015-01-29 17:55:08 +00:00
parent cf0087e87c
commit b4e955d1c1
1 changed files with 9 additions and 2 deletions

View File

@ -1022,9 +1022,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
public void SaveState()
{
if (!Running)
return;
// We cannot call this inside the EventQueue lock since it will currently take AsyncCommandManager.staticLock.
// This may already be held by AsyncCommandManager.DoOneCmdHandlerPass() which in turn can take EventQueue
// lock via ScriptInstance.PostEvent().
PluginData = AsyncCommandManager.GetSerializationData(Engine, ItemID);
// We need to lock here to avoid any race with a thread that is removing this script.
lock (EventQueue)
{
// Check again to avoid a race with a thread in Stop()
if (!Running)
return;
@ -1040,8 +1049,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
// "[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