From 50ed97aa1a91beb20747b5d6377390669c614450 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 30 Jul 2014 21:49:57 -0700 Subject: [PATCH] BulletSim: thread safe handling of list of avatars. Fix for 7284 which is an enumeration exception when starting up a region. --- .../Region/Physics/BulletSPlugin/BSScene.cs | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index e5173894ec..f7317c01fe 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -471,7 +471,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters // We must generate a collision for avatars whether they collide or not. // This is required by OpenSim to update avatar animations, etc. lock (m_avatars) - m_avatars.Add(actor); + { + // The funky copy is because this list has few and infrequent changes but is + // read zillions of times. This allows the reader/iterator to use the + // list and this creates a new list with any updates. + HashSet avatarTemp = new HashSet(m_avatars); + avatarTemp.Add(actor); + m_avatars = avatarTemp; + } return actor; } @@ -491,7 +498,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters PhysObjects.Remove(bsactor.LocalID); // Remove kludge someday lock (m_avatars) - m_avatars.Remove(bsactor); + { + HashSet avatarTemp = new HashSet(m_avatars); + avatarTemp.Remove(bsactor); + m_avatars = avatarTemp; + } } catch (Exception e) { @@ -736,9 +747,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters // The simulator expects collisions for avatars even if there are have been no collisions. // The event updates avatar animations and stuff. // If you fix avatar animation updates, remove this overhead and let normal collision processing happen. - foreach (BSPhysObject bsp in m_avatars) + // Note that we copy the root of the list to search. Any updates will create a new list + // thus freeing this code from having to do an extra lock for every collision. + HashSet avatarTemp = m_avatars; + foreach (BSPhysObject bsp in avatarTemp) if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice bsp.SendCollisions(); + avatarTemp = null; // Objects that are done colliding are removed from the ObjectsWithCollisions list. // Not done above because it is inside an iteration of ObjectWithCollisions.