From b4e955d1c107784ccf17a739cd83b2603f665d0c Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 29 Jan 2015 17:55:08 +0000 Subject: [PATCH] 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. --- .../ScriptEngine/Shared/Instance/ScriptInstance.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index 5ff56a1dd9..d28b151dd3 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -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