diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index b8ff7f772f..bab14dd3de 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -121,6 +121,8 @@ namespace OpenSim.Region.Framework.Scenes
///
/// TODO: For some reason, we effectively have a list both here and in Appearance. Need to work out if this is
/// necessary.
+ /// NOTE: To avoid deadlocks, do not lock m_attachments and then perform other tasks under that lock. Take a copy
+ /// of the list and act on that instead.
///
private List m_attachments = new List();
@@ -971,19 +973,27 @@ namespace OpenSim.Region.Framework.Scenes
// and CHANGED_REGION) when the attachments have been rezzed in the new region. This cannot currently
// be done in AttachmentsModule.CopyAttachments(AgentData ad, IScenePresence sp) itself since we are
// not transporting the required data.
- lock (m_attachments)
- {
- if (HasAttachments())
- {
- m_log.DebugFormat(
- "[SCENE PRESENCE]: Restarting scripts in attachments for {0} in {1}", Name, Scene.Name);
+ //
+ // We must take a copy of the attachments list here (rather than locking) to avoid a deadlock where a script in one of
+ // the attachments may start processing an event (which locks ScriptInstance.m_Script) that then calls a method here
+ // which needs to lock m_attachments. ResumeScripts() needs to take a ScriptInstance.m_Script lock to try to unset the Suspend status.
+ //
+ // FIXME: In theory, this deadlock should not arise since scripts should not be processing events until ResumeScripts().
+ // But XEngine starts all scripts unsuspended. Starting them suspended will not currently work because script rezzing
+ // is placed in an asynchronous queue in XEngine and so the ResumeScripts() call will almost certainly execute before the
+ // script is rezzed. This means the ResumeScripts() does absolutely nothing when using XEngine.
+ List attachments = GetAttachments();
- // Resume scripts
- foreach (SceneObjectGroup sog in m_attachments)
- {
- sog.RootPart.ParentGroup.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, GetStateSource());
- sog.ResumeScripts();
- }
+ if (attachments.Count > 0)
+ {
+ m_log.DebugFormat(
+ "[SCENE PRESENCE]: Restarting scripts in attachments for {0} in {1}", Name, Scene.Name);
+
+ // Resume scripts
+ foreach (SceneObjectGroup sog in attachments)
+ {
+ sog.RootPart.ParentGroup.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, GetStateSource());
+ sog.ResumeScripts();
}
}
}