aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2012-01-25 19:31:50 +0000
committerJustin Clark-Casey (justincc)2012-01-25 19:31:50 +0000
commite20cf3789bc8bbcda86c8e9067fbe8ecdb3046ac (patch)
tree5a378b0ea1a3c52b7ec16a5be48a2400ee0defc6
parentMake errors reported by OpenSim when it halts because it can't find certain c... (diff)
downloadopensim-SC-e20cf3789bc8bbcda86c8e9067fbe8ecdb3046ac.zip
opensim-SC-e20cf3789bc8bbcda86c8e9067fbe8ecdb3046ac.tar.gz
opensim-SC-e20cf3789bc8bbcda86c8e9067fbe8ecdb3046ac.tar.bz2
opensim-SC-e20cf3789bc8bbcda86c8e9067fbe8ecdb3046ac.tar.xz
Serialize calls to ODE Collide() function across OdeScene instances to prevent ODE crashes on simulators running more than one region.
It turns out that calls to Collide() are not thread-safe even for objects in different ODE physics worlds due to ODE static caches. For simulators running multiple regions, not serializing calls from different scene loops will sooner or later cause OpenSim to crash with a native stack trace referencing OBBCollider. This affects the default OPCODE collider but not GIMPACT. However, GIMPACT fails for other reasons under some current simulator loads. ODE provides a thread local storage option, but as of ODE r1755 (and r1840) DLLs compiled with this crash OpenSim immediately.
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODECharacter.cs3
-rw-r--r--OpenSim/Region/Physics/OdePlugin/OdeScene.cs30
2 files changed, 32 insertions, 1 deletions
diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
index c6e8286..7c1c046 100644
--- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
+++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
@@ -1048,6 +1048,7 @@ namespace OpenSim.Region.Physics.OdePlugin
1048 CAPSULE_RADIUS = 0.01f; 1048 CAPSULE_RADIUS = 0.01f;
1049 } 1049 }
1050 1050
1051// lock (OdeScene.UniversalColliderSyncObject)
1051 Shell = d.CreateCapsule(_parent_scene.space, CAPSULE_RADIUS, CAPSULE_LENGTH); 1052 Shell = d.CreateCapsule(_parent_scene.space, CAPSULE_RADIUS, CAPSULE_LENGTH);
1052 1053
1053 d.GeomSetCategoryBits(Shell, (int)m_collisionCategories); 1054 d.GeomSetCategoryBits(Shell, (int)m_collisionCategories);
@@ -1179,7 +1180,9 @@ namespace OpenSim.Region.Physics.OdePlugin
1179 1180
1180 if (Shell != IntPtr.Zero) 1181 if (Shell != IntPtr.Zero)
1181 { 1182 {
1183// lock (OdeScene.UniversalColliderSyncObject)
1182 d.GeomDestroy(Shell); 1184 d.GeomDestroy(Shell);
1185
1183 _parent_scene.geom_name_map.Remove(Shell); 1186 _parent_scene.geom_name_map.Remove(Shell);
1184 _parent_scene.actor_name_map.Remove(Shell); 1187 _parent_scene.actor_name_map.Remove(Shell);
1185 1188
diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
index 37daf46..4530c09 100644
--- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
+++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
@@ -105,6 +105,32 @@ namespace OpenSim.Region.Physics.OdePlugin
105 private readonly ILog m_log; 105 private readonly ILog m_log;
106 // private Dictionary<string, sCollisionData> m_storedCollisions = new Dictionary<string, sCollisionData>(); 106 // private Dictionary<string, sCollisionData> m_storedCollisions = new Dictionary<string, sCollisionData>();
107 107
108 /// <summary>
109 /// Provide a sync object so that only one thread calls d.Collide() at a time across all OdeScene instances.
110 /// </summary>
111 /// <remarks>
112 /// With ODE as of r1755 (though also tested on r1860), only one thread can call d.Collide() at a
113 /// time, even where physics objects are in entirely different ODE worlds. This is because generating contacts
114 /// uses a static cache at the ODE level.
115 ///
116 /// Without locking, simulators running multiple regions will eventually crash with a native stack trace similar
117 /// to
118 ///
119 /// mono() [0x489171]
120 /// mono() [0x4d154f]
121 /// /lib/x86_64-linux-gnu/libpthread.so.0(+0xfc60) [0x7f6ded592c60]
122 /// .../opensim/bin/libode-x86_64.so(_ZN6Opcode11OBBCollider8_CollideEPKNS_14AABBNoLeafNodeE+0xd7a) [0x7f6dd822628a]
123 ///
124 /// ODE provides an experimental option to cache in thread local storage but compiling ODE with this option
125 /// causes OpenSimulator to immediately crash with a native stack trace similar to
126 ///
127 /// mono() [0x489171]
128 /// mono() [0x4d154f]
129 /// /lib/x86_64-linux-gnu/libpthread.so.0(+0xfc60) [0x7f03c9849c60]
130 /// .../opensim/bin/libode-x86_64.so(_Z12dCollideCCTLP6dxGeomS0_iP12dContactGeomi+0x92) [0x7f03b44bcf82]
131 /// </remarks>
132 internal static Object UniversalColliderSyncObject = new Object();
133
108 private Random fluidRandomizer = new Random(Environment.TickCount); 134 private Random fluidRandomizer = new Random(Environment.TickCount);
109 135
110 private const uint m_regionWidth = Constants.RegionSize; 136 private const uint m_regionWidth = Constants.RegionSize;
@@ -799,7 +825,9 @@ namespace OpenSim.Region.Physics.OdePlugin
799 if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact)) 825 if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact))
800 return; 826 return;
801 827
802 count = d.Collide(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf); 828 lock (OdeScene.UniversalColliderSyncObject)
829 count = d.Collide(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf);
830
803 if (count > contacts.Length) 831 if (count > contacts.Length)
804 m_log.Error("[ODE SCENE]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length); 832 m_log.Error("[ODE SCENE]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length);
805 } 833 }