We're getting a crash with some ive paged terrains, it was being ht
when the system was under load with 7 OSG application instances all
thrashing their pagers.  I've tracked it down to a race condition and
included two patches, the first adds a sleep to greatly increase the
chance of the crash to reproduce it, the second is a potential fix.
I've verified trunk crashes.  The first one obviously is not to be
committed.  I don't know enough about GeometryTechnique to know if
there is a better way to fix it, so I didn't include the full file as
I didn't think it was ready to submit.

I would have thought a subtree would either be being processed by the
DatabasePager or in the main scene graph for draw, but not both at the
same time, and something is happening to cause one to be deleting
nodes while the other is trying to compile the state sets.  Any ideas?

-------------------------------
cause GeometryTechnique::traverse crash

Add a sleep to widen the race condition to demonstrate a crash in
GeometryTechnique::traverse

partial stack trace of the crashing thread,
osg::NodeVisitor::traverse
osgUtil::StateToCompile::apply
osg::NodeVisitor::apply
osg::NodeVisitor::apply
osg::NodeVisitor::apply
osg::MatrixTransform::accept
osgTerrain::GeometryTechnique::traverse
osgTerrain::TerrainTile::traverse
osg::NodeVisitor::traverse
osgUtil::StateToCompile::apply
...
osg::Group::accept
osgDB::DatabasePager::DatabaseThread::run

The additional sleep allows another thread to call
GeometryTechnique::init which leaves a dangling pointer for this code.

main thread,
osg::MatrixTransform::~MatrixTransform()
osg::Referenced::signalObserversAndDelete
osg::Referenced::unref
osg::ref_ptr<osg::MatrixTransform>::~ref_ptr()
osgTerrain::GeometryTechnique::BufferData::~BufferData()
osgTerrain::GeometryTechnique::BufferData::~BufferData()
osg::Referenced::signalObserversAndDelete
assign<osgTerrain::GeometryTechnique::BufferData>
operator=
osgTerrain::GeometryTechnique::init(int, bool)
(GeometryTechnique.cpp:145)
---
 src/osgUtil/IncrementalCompileOperation.cpp |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/osgUtil/IncrementalCompileOperation.cpp 
b/src/osgUtil/IncrementalCompileOperation.cpp
index 520f4db..dff6354 100644
--- a/src/osgUtil/IncrementalCompileOperation.cpp
+++ b/src/osgUtil/IncrementalCompileOperation.cpp
@@ -67,6 +67,9 @@ void StateToCompile::apply(osg::Node& node)
         apply(*(node.getStateSet()));
     }
 
+    // widen the race condition to demonstrate GeometryTechnique::traverse 
causing a crash
+    OpenThreads::Thread::microSleep(100000);
+
     traverse(node);
 }
 
-- 
1.7.10.4

-------------------------------

add a lock to GeometryTechnique::traverse

One thread can be in init while another in traverse and the end result
is a crash.
---
 include/osgTerrain/GeometryTechnique |    3 ++-
 src/osgTerrain/GeometryTechnique.cpp |    1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/include/osgTerrain/GeometryTechnique 
b/include/osgTerrain/GeometryTechnique
index fdb0df4..071e0c6 100644
--- a/include/osgTerrain/GeometryTechnique
+++ b/include/osgTerrain/GeometryTechnique
@@ -20,6 +20,7 @@
 
 #include <osgTerrain/TerrainTechnique>
 #include <osgTerrain/Locator>
+#include <OpenThreads/ReentrantMutex>
 
 namespace osgTerrain {
 
@@ -99,7 +100,7 @@ class OSGTERRAIN_EXPORT GeometryTechnique : public 
TerrainTechnique
         virtual void applyTransparency(BufferData& buffer);
 
 
-        OpenThreads::Mutex                  _writeBufferMutex;
+        OpenThreads::ReentrantMutex         _writeBufferMutex;
         osg::ref_ptr<BufferData>            _currentBufferData;
         osg::ref_ptr<BufferData>            _newBufferData;
 
diff --git a/src/osgTerrain/GeometryTechnique.cpp 
b/src/osgTerrain/GeometryTechnique.cpp
index e1c461b..9b161e0 100644
--- a/src/osgTerrain/GeometryTechnique.cpp
+++ b/src/osgTerrain/GeometryTechnique.cpp
@@ -1451,6 +1451,7 @@ void GeometryTechnique::cull(osgUtil::CullVisitor* cv)
 void GeometryTechnique::traverse(osg::NodeVisitor& nv)
 {
     if (!_terrainTile) return;
+    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_writeBufferMutex);
 
     // if app traversal update the frame count.
     if (nv.getVisitorType()==osg::NodeVisitor::UPDATE_VISITOR)
-- 
1.7.10.4

_______________________________________________
osg-users mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org

Reply via email to