From 8031f8ec09df4f654c86a9c7bc498664f7b9d9dc Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 26 Aug 2010 00:08:53 +0100 Subject: Improve consistency of locking for SOG.m_parts in order to avoid race conditions in linking and unlinking --- OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | 21 ++-- .../Framework/Scenes/Scene.PacketHandlers.cs | 38 +++--- OpenSim/Region/Framework/Scenes/Scene.cs | 35 +++--- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 111 ++++++++++------- .../Region/Framework/Scenes/SceneObjectGroup.cs | 131 +++++++++++++-------- .../Framework/Scenes/SceneObjectPartInventory.cs | 5 +- 6 files changed, 205 insertions(+), 136 deletions(-) (limited to 'OpenSim/Region/Framework') diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 9fef8f4..379128a 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -1974,7 +1974,7 @@ namespace OpenSim.Region.Framework.Scenes if (null == group) return null; - if (!Permissions.CanRezObject(group.Children.Count, item.OwnerID, pos)) + if (!Permissions.CanRezObject(group.PrimCount, item.OwnerID, pos)) return null; if (!Permissions.BypassPermissions()) @@ -2051,8 +2051,11 @@ namespace OpenSim.Region.Framework.Scenes sog.SetGroup(groupID, remoteClient); sog.ScheduleGroupForFullUpdate(); - foreach (SceneObjectPart child in sog.Children.Values) - child.Inventory.ChangeInventoryOwner(ownerID); + lock (sog.Children) + { + foreach (SceneObjectPart child in sog.Children.Values) + child.Inventory.ChangeInventoryOwner(ownerID); + } } else { @@ -2062,16 +2065,18 @@ namespace OpenSim.Region.Framework.Scenes if (sog.GroupID != groupID) continue; - foreach (SceneObjectPart child in sog.Children.Values) + lock (sog.Children) { - child.LastOwnerID = child.OwnerID; - child.Inventory.ChangeInventoryOwner(groupID); + foreach (SceneObjectPart child in sog.Children.Values) + { + child.LastOwnerID = child.OwnerID; + child.Inventory.ChangeInventoryOwner(groupID); + } } sog.SetOwnerId(groupID); sog.ApplyNextOwnerPermissions(); - } - + } } foreach (uint localID in localIDs) diff --git a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs index e25b1f1..9f1575d 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs @@ -156,21 +156,29 @@ namespace OpenSim.Region.Framework.Scenes } break; } - else - { - // We also need to check the children of this prim as they - // can be selected as well and send property information - bool foundPrim = false; - foreach (KeyValuePair child in ((SceneObjectGroup) ent).Children) - { - if (child.Value.LocalId == primLocalID) - { - child.Value.GetProperties(remoteClient); - foundPrim = true; - break; - } - } - if (foundPrim) break; + else + { + // We also need to check the children of this prim as they + // can be selected as well and send property information + bool foundPrim = false; + + SceneObjectGroup sog = ent as SceneObjectGroup; + + lock (sog.Children) + { + foreach (KeyValuePair child in (sog.Children)) + { + if (child.Value.LocalId == primLocalID) + { + child.Value.GetProperties(remoteClient); + foundPrim = true; + break; + } + } + } + + if (foundPrim) + break; } } } diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index b808c6d..8556105 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -1756,8 +1756,9 @@ namespace OpenSim.Region.Framework.Scenes if (group.RootPart == null) { - m_log.ErrorFormat("[SCENE]: Found a SceneObjectGroup with m_rootPart == null and {0} children", - group.Children == null ? 0 : group.Children.Count); + m_log.ErrorFormat( + "[SCENE]: Found a SceneObjectGroup with m_rootPart == null and {0} children", + group.Children == null ? 0 : group.PrimCount); } AddRestoredSceneObject(group, true, true); @@ -2064,18 +2065,22 @@ namespace OpenSim.Region.Framework.Scenes group.RemoveScriptInstances(true); } - foreach (SceneObjectPart part in group.Children.Values) + lock (group.Children) { - if (part.IsJoint() && ((part.Flags & PrimFlags.Physics) != 0)) + foreach (SceneObjectPart part in group.Children.Values) { - PhysicsScene.RequestJointDeletion(part.Name); // FIXME: what if the name changed? - } - else if (part.PhysActor != null) - { - PhysicsScene.RemovePrim(part.PhysActor); - part.PhysActor = null; + if (part.IsJoint() && ((part.Flags & PrimFlags.Physics) != 0)) + { + PhysicsScene.RequestJointDeletion(part.Name); // FIXME: what if the name changed? + } + else if (part.PhysActor != null) + { + PhysicsScene.RemovePrim(part.PhysActor); + part.PhysActor = null; + } } } + // if (rootPart.PhysActor != null) // { // PhysicsScene.RemovePrim(rootPart.PhysActor); @@ -2426,14 +2431,16 @@ namespace OpenSim.Region.Framework.Scenes // Force allocation of new LocalId // - foreach (SceneObjectPart p in sceneObject.Children.Values) - p.LocalId = 0; + lock (sceneObject.Children) + { + foreach (SceneObjectPart p in sceneObject.Children.Values) + p.LocalId = 0; + } if (sceneObject.IsAttachmentCheckFull()) // Attachment { sceneObject.RootPart.AddFlag(PrimFlags.TemporaryOnRez); sceneObject.RootPart.AddFlag(PrimFlags.Phantom); - // Don't sent a full update here because this will cause full updates to be sent twice for // attachments on region crossings, resulting in viewer glitches. @@ -2447,7 +2454,6 @@ namespace OpenSim.Region.Framework.Scenes if (sp != null) { - SceneObjectGroup grp = sceneObject; m_log.DebugFormat( @@ -2459,7 +2465,6 @@ namespace OpenSim.Region.Framework.Scenes if (AttachmentsModule != null) AttachmentsModule.AttachObject(sp.ControllingClient, grp, 0, false); - } else { diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 31faeec..2b24706 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -364,45 +364,48 @@ namespace OpenSim.Region.Framework.Scenes // "[SCENE GRAPH]: Adding object {0} {1} to region {2}", // sceneObject.Name, sceneObject.UUID, m_parentScene.RegionInfo.RegionName); - if (m_parentScene.m_clampPrimSize) + lock (sceneObject.Children) { - foreach (SceneObjectPart part in sceneObject.Children.Values) + if (m_parentScene.m_clampPrimSize) { - Vector3 scale = part.Shape.Scale; - - if (scale.X > m_parentScene.m_maxNonphys) - scale.X = m_parentScene.m_maxNonphys; - if (scale.Y > m_parentScene.m_maxNonphys) - scale.Y = m_parentScene.m_maxNonphys; - if (scale.Z > m_parentScene.m_maxNonphys) - scale.Z = m_parentScene.m_maxNonphys; - - part.Shape.Scale = scale; + foreach (SceneObjectPart part in sceneObject.Children.Values) + { + Vector3 scale = part.Shape.Scale; + + if (scale.X > m_parentScene.m_maxNonphys) + scale.X = m_parentScene.m_maxNonphys; + if (scale.Y > m_parentScene.m_maxNonphys) + scale.Y = m_parentScene.m_maxNonphys; + if (scale.Z > m_parentScene.m_maxNonphys) + scale.Z = m_parentScene.m_maxNonphys; + + part.Shape.Scale = scale; + } } - } + + sceneObject.AttachToScene(m_parentScene); + + if (sendClientUpdates) + sceneObject.ScheduleGroupForFullUpdate(); + + Entities.Add(sceneObject); + m_numPrim += sceneObject.Children.Count; - sceneObject.AttachToScene(m_parentScene); + if (attachToBackup) + sceneObject.AttachToBackup(); - if (sendClientUpdates) - sceneObject.ScheduleGroupForFullUpdate(); - - Entities.Add(sceneObject); - m_numPrim += sceneObject.Children.Count; - - if (attachToBackup) - sceneObject.AttachToBackup(); - - if (OnObjectCreate != null) - OnObjectCreate(sceneObject); - - lock (m_dictionary_lock) - { - SceneObjectGroupsByFullID[sceneObject.UUID] = sceneObject; - SceneObjectGroupsByLocalID[sceneObject.LocalId] = sceneObject; - foreach (SceneObjectPart part in sceneObject.Children.Values) + if (OnObjectCreate != null) + OnObjectCreate(sceneObject); + + lock (m_dictionary_lock) { - SceneObjectGroupsByFullID[part.UUID] = sceneObject; - SceneObjectGroupsByLocalID[part.LocalId] = sceneObject; + SceneObjectGroupsByFullID[sceneObject.UUID] = sceneObject; + SceneObjectGroupsByLocalID[sceneObject.LocalId] = sceneObject; + foreach (SceneObjectPart part in sceneObject.Children.Values) + { + SceneObjectGroupsByFullID[part.UUID] = sceneObject; + SceneObjectGroupsByLocalID[part.LocalId] = sceneObject; + } } } } @@ -420,11 +423,16 @@ namespace OpenSim.Region.Framework.Scenes { if (!resultOfObjectLinked) { - m_numPrim -= ((SceneObjectGroup) Entities[uuid]).Children.Count; - - if ((((SceneObjectGroup)Entities[uuid]).RootPart.Flags & PrimFlags.Physics) == PrimFlags.Physics) + SceneObjectGroup sog = Entities[uuid] as SceneObjectGroup; + + lock (sog.Children) { - RemovePhysicalPrim(((SceneObjectGroup)Entities[uuid]).Children.Count); + m_numPrim -= sog.PrimCount; + + if ((((SceneObjectGroup)Entities[uuid]).RootPart.Flags & PrimFlags.Physics) == PrimFlags.Physics) + { + RemovePhysicalPrim(sog.PrimCount); + } } } @@ -1603,7 +1611,7 @@ namespace OpenSim.Region.Framework.Scenes { if (part != null) { - if (part.ParentGroup.Children.Count != 1) // Skip single + if (part.ParentGroup.PrimCount != 1) // Skip single { if (part.LinkNum < 2) // Root rootParts.Add(part); @@ -1631,8 +1639,15 @@ namespace OpenSim.Region.Framework.Scenes // However, editing linked parts and unlinking may be different // SceneObjectGroup group = root.ParentGroup; - List newSet = new List(group.Children.Values); - int numChildren = group.Children.Count; + + List newSet = null; + int numChildren = -1; + + lock (group.Children) + { + newSet = new List(group.Children.Values); + numChildren = group.PrimCount; + } // If there are prims left in a link set, but the root is // slated for unlink, we need to do this @@ -1711,12 +1726,17 @@ namespace OpenSim.Region.Framework.Scenes { if (ent is SceneObjectGroup) { - foreach (KeyValuePair subent in ((SceneObjectGroup)ent).Children) + SceneObjectGroup sog = ent as SceneObjectGroup; + + lock (sog.Children) { - if (subent.Value.LocalId == localID) + foreach (KeyValuePair subent in sog.Children) { - objid = subent.Key; - obj = subent.Value; + if (subent.Value.LocalId == localID) + { + objid = subent.Key; + obj = subent.Value; + } } } } @@ -1781,7 +1801,8 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectGroup original = GetGroupByPrim(originalPrimID); if (original != null) { - if (m_parentScene.Permissions.CanDuplicateObject(original.Children.Count, original.UUID, AgentID, original.AbsolutePosition)) + if (m_parentScene.Permissions.CanDuplicateObject( + original.PrimCount, original.UUID, AgentID, original.AbsolutePosition)) { SceneObjectGroup copy = original.Copy(true); copy.AbsolutePosition = copy.AbsolutePosition + offset; diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 952d280..5ee8d73 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -213,7 +213,7 @@ namespace OpenSim.Region.Framework.Scenes /// public int PrimCount { - get { return m_parts.Count; } + get { lock (m_parts) { return m_parts.Count; } } } protected Quaternion m_rotation = Quaternion.Identity; @@ -237,6 +237,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// The parts of this scene object group. You must lock this property before using it. + /// If you want to know the number of children, consider using the PrimCount property instead /// public Dictionary Children { @@ -298,6 +299,7 @@ namespace OpenSim.Region.Framework.Scenes { m_scene.CrossPrimGroupIntoNewRegion(val, this, true); } + if (RootPart.GetStatusSandbox()) { if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) @@ -308,6 +310,7 @@ namespace OpenSim.Region.Framework.Scenes return; } } + lock (m_parts) { foreach (SceneObjectPart part in m_parts.Values) @@ -558,21 +561,23 @@ namespace OpenSim.Region.Framework.Scenes if (m_rootPart.LocalId == 0) m_rootPart.LocalId = m_scene.AllocateLocalId(); - // No need to lock here since the object isn't yet in a scene - foreach (SceneObjectPart part in m_parts.Values) + lock (m_parts) { - if (Object.ReferenceEquals(part, m_rootPart)) - { - continue; - } - - if (part.LocalId == 0) + foreach (SceneObjectPart part in m_parts.Values) { - part.LocalId = m_scene.AllocateLocalId(); + if (Object.ReferenceEquals(part, m_rootPart)) + { + continue; + } + + if (part.LocalId == 0) + { + part.LocalId = m_scene.AllocateLocalId(); + } + + part.ParentID = m_rootPart.LocalId; + //m_log.DebugFormat("[SCENE]: Given local id {0} to part {1}, linknum {2}, parent {3} {4}", part.LocalId, part.UUID, part.LinkNum, part.ParentID, part.ParentUUID); } - - part.ParentID = m_rootPart.LocalId; - //m_log.DebugFormat("[SCENE]: Given local id {0} to part {1}, linknum {2}, parent {3} {4}", part.LocalId, part.UUID, part.LinkNum, part.ParentID, part.ParentUUID); } ApplyPhysics(m_scene.m_physicalPrim); @@ -670,7 +675,7 @@ namespace OpenSim.Region.Framework.Scenes minY = 256f; minZ = 8192f; - lock(m_parts); + lock(m_parts) { foreach (SceneObjectPart part in m_parts.Values) { @@ -995,9 +1000,12 @@ namespace OpenSim.Region.Framework.Scenes m_rootPart.AttachedAvatar = agentID; //Anakin Lohner bug #3839 - foreach (SceneObjectPart p in m_parts.Values) + lock (m_parts) { - p.AttachedAvatar = agentID; + foreach (SceneObjectPart p in m_parts.Values) + { + p.AttachedAvatar = agentID; + } } if (m_rootPart.PhysActor != null) @@ -1065,10 +1073,14 @@ namespace OpenSim.Region.Framework.Scenes AbsolutePosition = detachedpos; m_rootPart.AttachedAvatar = UUID.Zero; - //Anakin Lohner bug #3839 - foreach (SceneObjectPart p in m_parts.Values) + + //Anakin Lohner bug #3839 + lock (m_parts) { - p.AttachedAvatar = UUID.Zero; + foreach (SceneObjectPart p in m_parts.Values) + { + p.AttachedAvatar = UUID.Zero; + } } m_rootPart.SetParentLocalId(0); @@ -1094,10 +1106,14 @@ namespace OpenSim.Region.Framework.Scenes } m_rootPart.AttachedAvatar = UUID.Zero; + //Anakin Lohner bug #3839 - foreach (SceneObjectPart p in m_parts.Values) + lock (m_parts) { - p.AttachedAvatar = UUID.Zero; + foreach (SceneObjectPart p in m_parts.Values) + { + p.AttachedAvatar = UUID.Zero; + } } m_rootPart.SetParentLocalId(0); @@ -1160,9 +1176,8 @@ namespace OpenSim.Region.Framework.Scenes part.ParentID = 0; part.LinkNum = 0; - // No locking required since the SOG should not be in the scene yet - one can't change root parts after - // the scene object has been attached to the scene - m_parts.Add(m_rootPart.UUID, m_rootPart); + lock (m_parts) + m_parts.Add(m_rootPart.UUID, m_rootPart); } /// @@ -1625,7 +1640,7 @@ namespace OpenSim.Region.Framework.Scenes } /// - /// + /// Copy the given part as the root part of this scene object. /// /// /// @@ -1882,11 +1897,12 @@ namespace OpenSim.Region.Framework.Scenes /// public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) { - SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); - newPart.SetParent(this); - + SceneObjectPart newPart = null; + lock (m_parts) - { + { + newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); + newPart.SetParent(this); m_parts.Add(newPart.UUID, newPart); } @@ -1903,14 +1919,15 @@ namespace OpenSim.Region.Framework.Scenes /// public void ResetIDs() { - // As this is only ever called for prims which are not currently part of the scene (and hence - // not accessible by clients), there should be no need to lock - List partsList = new List(m_parts.Values); - m_parts.Clear(); - foreach (SceneObjectPart part in partsList) + lock (m_parts) { - part.ResetIDs(part.LinkNum); // Don't change link nums - m_parts.Add(part.UUID, part); + List partsList = new List(m_parts.Values); + m_parts.Clear(); + foreach (SceneObjectPart part in partsList) + { + part.ResetIDs(part.LinkNum); // Don't change link nums + m_parts.Add(part.UUID, part); + } } } @@ -2136,10 +2153,15 @@ namespace OpenSim.Region.Framework.Scenes public SceneObjectPart GetChildPart(UUID primID) { SceneObjectPart childPart = null; - if (m_parts.ContainsKey(primID)) + + lock (m_parts) { - childPart = m_parts[primID]; + if (m_parts.ContainsKey(primID)) + { + childPart = m_parts[primID]; + } } + return childPart; } @@ -2174,9 +2196,10 @@ namespace OpenSim.Region.Framework.Scenes /// public bool HasChildPrim(UUID primID) { - if (m_parts.ContainsKey(primID)) + lock (m_parts) { - return true; + if (m_parts.ContainsKey(primID)) + return true; } return false; @@ -2370,17 +2393,19 @@ namespace OpenSim.Region.Framework.Scenes lock (m_parts) { m_parts.Remove(linkPart.UUID); - } - - if (m_parts.Count == 1 && RootPart != null) //Single prim is left - RootPart.LinkNum = 0; - else - { - foreach (SceneObjectPart p in m_parts.Values) + + if (m_parts.Count == 1 && RootPart != null) //Single prim is left { - if (p.LinkNum > linkPart.LinkNum) - p.LinkNum--; + RootPart.LinkNum = 0; } + else + { + foreach (SceneObjectPart p in m_parts.Values) + { + if (p.LinkNum > linkPart.LinkNum) + p.LinkNum--; + } + } } linkPart.ParentID = 0; @@ -2762,9 +2787,11 @@ namespace OpenSim.Region.Framework.Scenes public void UpdatePermissions(UUID AgentID, byte field, uint localID, uint mask, byte addRemTF) { - foreach (SceneObjectPart part in m_parts.Values) - part.UpdatePermissions(AgentID, field, localID, mask, - addRemTF); + lock (m_parts) + { + foreach (SceneObjectPart part in m_parts.Values) + part.UpdatePermissions(AgentID, field, localID, mask, addRemTF); + } HasGroupChanged = true; } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs index 84b7365..e08fa77 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs @@ -601,7 +601,10 @@ namespace OpenSim.Region.Framework.Scenes rootPart.Name = item.Name; rootPart.Description = item.Description; - List partList = new List(group.Children.Values); + List partList = null; + + lock (group.Children) + partList = new List(group.Children.Values); group.SetGroup(m_part.GroupID, null); -- cgit v1.1