BulletSim: rearrange code and add different locking to eliminate chances

of race conditions and, especially, race conditions when an object is
removed and quickly re-added to a scene.

This hopefully reduces the occurance of problems when avatars TP within
a region -- the main problem being the loss of collisions.
0.8.2-post-fixes
Robert Adams 2015-08-09 15:36:50 -07:00
parent fe86df0ec9
commit fe37cb9990
3 changed files with 40 additions and 43 deletions

View File

@ -459,7 +459,7 @@ public sealed class BSCharacter : BSPhysObject
RawVelocity = value; RawVelocity = value;
OMV.Vector3 vel = RawVelocity; OMV.Vector3 vel = RawVelocity;
DetailLog("{0}: set Velocity = {1}", LogHeader, value); DetailLog("{0}: set Velocity = {1}", LocalID, value);
PhysScene.TaintedObject(LocalID, "BSCharacter.setVelocity", delegate() PhysScene.TaintedObject(LocalID, "BSCharacter.setVelocity", delegate()
{ {
@ -477,7 +477,7 @@ public sealed class BSCharacter : BSPhysObject
set { set {
PhysScene.AssertInTaintTime("BSCharacter.ForceVelocity"); PhysScene.AssertInTaintTime("BSCharacter.ForceVelocity");
// Util.PrintCallStack(); // Util.PrintCallStack();
DetailLog("{0}: set ForceVelocity = {1}", LogHeader, value); DetailLog("{0}: set ForceVelocity = {1}", LocalID, value);
RawVelocity = value; RawVelocity = value;
PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity); PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity);

View File

@ -80,12 +80,13 @@ public abstract class BSPhysObject : PhysicsActor
Name = name; // PhysicsActor also has the name of the object. Someday consolidate. Name = name; // PhysicsActor also has the name of the object. Someday consolidate.
TypeName = typeName; TypeName = typeName;
// The collection of things that push me around // Oddity if object is destroyed and recreated very quickly it could still have the old body.
PhysicalActors = new BSActorCollection(PhysScene); if (!PhysBody.HasPhysicalBody)
// We don't have any physical representation yet.
PhysBody = new BulletBody(localID); PhysBody = new BulletBody(localID);
PhysShape = new BSShapeNull();
// Clean out anything that might be in the physical actor list.
// Again, a workaround for destroying and recreating an object very quickly.
PhysicalActors.Dispose();
UserSetCenterOfMassDisplacement = null; UserSetCenterOfMassDisplacement = null;
@ -100,9 +101,6 @@ public abstract class BSPhysObject : PhysicsActor
// Default material type. Also sets Friction, Restitution and Density. // Default material type. Also sets Friction, Restitution and Density.
SetMaterial((int)MaterialAttributes.Material.Wood); SetMaterial((int)MaterialAttributes.Material.Wood);
CollisionCollection = new CollisionEventUpdate();
CollisionsLastReported = CollisionCollection;
CollisionsLastTick = new CollisionEventUpdate();
CollisionsLastTickStep = -1; CollisionsLastTickStep = -1;
SubscribedEventsMs = 0; SubscribedEventsMs = 0;
@ -158,9 +156,9 @@ public abstract class BSPhysObject : PhysicsActor
public OMV.Vector3 Inertia { get; set; } public OMV.Vector3 Inertia { get; set; }
// Reference to the physical body (btCollisionObject) of this object // Reference to the physical body (btCollisionObject) of this object
public BulletBody PhysBody; public BulletBody PhysBody = new BulletBody(0);
// Reference to the physical shape (btCollisionShape) of this object // Reference to the physical shape (btCollisionShape) of this object
public BSShape PhysShape; public BSShape PhysShape = new BSShapeNull();
// The physical representation of the prim might require an asset fetch. // The physical representation of the prim might require an asset fetch.
// The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'. // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'.
@ -445,12 +443,12 @@ public abstract class BSPhysObject : PhysicsActor
} }
// The collisions that have been collected for the next collision reporting (throttled by subscription) // The collisions that have been collected for the next collision reporting (throttled by subscription)
protected CollisionEventUpdate CollisionCollection; protected CollisionEventUpdate CollisionCollection = new CollisionEventUpdate();
// This is the collision collection last reported to the Simulator. // This is the collision collection last reported to the Simulator.
public CollisionEventUpdate CollisionsLastReported; public CollisionEventUpdate CollisionsLastReported = new CollisionEventUpdate();
// Remember the collisions recorded in the last tick for fancy collision checking // Remember the collisions recorded in the last tick for fancy collision checking
// (like a BSCharacter walking up stairs). // (like a BSCharacter walking up stairs).
public CollisionEventUpdate CollisionsLastTick; public CollisionEventUpdate CollisionsLastTick = new CollisionEventUpdate();
private long CollisionsLastTickStep = -1; private long CollisionsLastTickStep = -1;
// The simulation step is telling this object about a collision. // The simulation step is telling this object about a collision.
@ -495,7 +493,7 @@ public abstract class BSPhysObject : PhysicsActor
{ {
CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
} }
DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5},colliderMoving={6}", DetailLog("{0},{1}.Collision.AddCollider,call,with={2},point={3},normal={4},depth={5},colliderMoving={6}",
LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth, ColliderIsMoving); LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth, ColliderIsMoving);
ret = true; ret = true;
@ -596,7 +594,7 @@ public abstract class BSPhysObject : PhysicsActor
#region Per Simulation Step actions #region Per Simulation Step actions
public BSActorCollection PhysicalActors; public BSActorCollection PhysicalActors = new BSActorCollection();
// When an update to the physical properties happens, this event is fired to let // When an update to the physical properties happens, this event is fired to let
// different actors to modify the update before it is passed around // different actors to modify the update before it is passed around

View File

@ -76,7 +76,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
// Keep track of all the avatars so we can send them a collision event // Keep track of all the avatars so we can send them a collision event
// every tick so OpenSim will update its animation. // every tick so OpenSim will update its animation.
private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>(); private HashSet<BSPhysObject> AvatarsInScene = new HashSet<BSPhysObject>();
private Object AvatarsInSceneLock = new Object();
// let my minuions use my logger // let my minuions use my logger
public ILog Logger { get { return m_log; } } public ILog Logger { get { return m_log; } }
@ -425,11 +426,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
// make sure no stepping happens while we're deleting stuff // make sure no stepping happens while we're deleting stuff
m_initialized = false; m_initialized = false;
lock (PhysObjects)
{
foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects) foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
{ {
kvp.Value.Destroy(); kvp.Value.Destroy();
} }
PhysObjects.Clear(); PhysObjects.Clear();
}
// Now that the prims are all cleaned up, there should be no constraints left // Now that the prims are all cleaned up, there should be no constraints left
if (Constraints != null) if (Constraints != null)
@ -480,15 +484,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
// TODO: Remove kludge someday. // TODO: Remove kludge someday.
// We must generate a collision for avatars whether they collide or not. // We must generate a collision for avatars whether they collide or not.
// This is required by OpenSim to update avatar animations, etc. // This is required by OpenSim to update avatar animations, etc.
lock (m_avatars) lock (AvatarsInSceneLock)
{ AvatarsInScene.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<BSPhysObject> avatarTemp = new HashSet<BSPhysObject>(m_avatars);
avatarTemp.Add(actor);
m_avatars = avatarTemp;
}
return actor; return actor;
} }
@ -507,12 +504,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
lock (PhysObjects) lock (PhysObjects)
PhysObjects.Remove(bsactor.LocalID); PhysObjects.Remove(bsactor.LocalID);
// Remove kludge someday // Remove kludge someday
lock (m_avatars) lock (AvatarsInSceneLock)
{ AvatarsInScene.Remove(bsactor);
HashSet<BSPhysObject> avatarTemp = new HashSet<BSPhysObject>(m_avatars);
avatarTemp.Remove(bsactor);
m_avatars = avatarTemp;
}
} }
catch (Exception e) catch (Exception e)
{ {
@ -757,13 +750,18 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
// The simulator expects collisions for avatars even if there are have been no collisions. // The simulator expects collisions for avatars even if there are have been no collisions.
// The event updates avatar animations and stuff. // The event updates avatar animations and stuff.
// If you fix avatar animation updates, remove this overhead and let normal collision processing happen. // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
// Note that we copy the root of the list to search. Any updates will create a new list // Note that we get a copy of the list to search because SendCollision() can take a while.
// thus freeing this code from having to do an extra lock for every collision. HashSet<BSPhysObject> tempAvatarsInScene;
HashSet<BSPhysObject> avatarTemp = m_avatars; lock (AvatarsInSceneLock)
foreach (BSPhysObject bsp in avatarTemp) {
if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice tempAvatarsInScene = new HashSet<BSPhysObject>(AvatarsInScene);
bsp.SendCollisions(); }
avatarTemp = null; foreach (BSPhysObject actor in tempAvatarsInScene)
{
if (!ObjectsWithCollisions.Contains(actor)) // don't call avatars twice
actor.SendCollisions();
}
tempAvatarsInScene = null;
// Objects that are done colliding are removed from the ObjectsWithCollisions list. // Objects that are done colliding are removed from the ObjectsWithCollisions list.
// Not done above because it is inside an iteration of ObjectWithCollisions. // Not done above because it is inside an iteration of ObjectWithCollisions.
@ -813,6 +811,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
} }
BSPhysObject collider; BSPhysObject collider;
// NOTE that PhysObjects was locked before the call to SendCollision().
if (!PhysObjects.TryGetValue(localID, out collider)) if (!PhysObjects.TryGetValue(localID, out collider))
{ {
// If the object that is colliding cannot be found, just ignore the collision. // If the object that is colliding cannot be found, just ignore the collision.