Hi Robert, I tried to reproduce this problem on linux but without luck.
gcc use more complex method of initialization of static variables at function scope.
So problem is only with MSVC 2008 (not sure about newer versions). Mikhail. 05.06.2012 10:39, Mikhail I. Izmestev написал:
Hi, Here is code to reproduce crash: <code> #include <osgDB/ReadFile> #include <OpenThreads/Mutex> #include <OpenThreads/Thread> #include <OpenThreads/Condition> static OpenThreads::Condition s_cond; static OpenThreads::Mutex s_mtx; class ReadThread : public OpenThreads::Thread { public: ReadThread() {} void run() { { OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mtx); s_cond.wait(&s_mtx); } osg::ref_ptr<osg::Node> node = osgDB::readNodeFile("cow.osg"); } }; int main() { ReadThread t1, t2; t1.start(); t2.start(); // OpenThreads::Thread::microSleep(500); { OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mtx); s_cond.broadcast(); } t1.join(); t2.join(); return 0; } </code> To reproduce you can use this script: <code> #!/usr/bin/env bash while(true); do ./test done </code> But while testing fix I have new crash at: ntdll!RtlReportCriticalFailure+0x62 ntdll!RtlpReportHeapFailure+0x26 ntdll!RtlpHeapHandleError+0x12 ntdll!RtlpLogHeapFailure+0xa4 ntdll!RtlpAnalyzeHeapFailure+0x3a8 ntdll!RtlpFreeHeap+0x141f ntdll!RtlFreeHeap+0x1a6 kernel32!HeapFree+0xa MSVCR90!free+0x1c MSVCP90!std::basic_string<char,std::char_traits<char>,std::allocator<char> MSVCP90!std::basic_string<char,std::char_traits<char>,std::allocator<char> MSVCP90!std::operator+<char,std::char_traits<char>,std::allocator<char> osg92_osgDB!osgDB::Registry::createLibraryNameForExtension+0x34b osg92_osgDB!osgDB::Registry::createLibraryNameForFile+0x42 osg92_osgDB!osgDB::Registry::read+0x1608 osg92_osgDB!osgDB::Registry::readImplementation+0x34c osg92_osgDB!osgDB::Registry::readNodeImplementation+0x6a osg92_osgDB!osgDB::Registry::readNode+0xfc osg92_osgDB!osgDB::readNodeFile+0x4e dotosgcrash!ReadThread::run+0x79 code: std::string Registry::createLibraryNameForExtension(const std::string& ext) { std::string lowercase_ext; for(std::string::const_iterator sitr=ext.begin(); sitr!=ext.end(); ++sitr) { lowercase_ext.push_back(tolower(*sitr)); } ExtensionAliasMap::iterator itr=_extAliasMap.find(lowercase_ext); if (itr!=_extAliasMap.end() && ext != itr->second) return createLibraryNameForExtension(itr->second); #if defined(OSG_JAVA_BUILD) static std::string prepend = std::string("osgPlugins-")+std::string(osgGetVersion())+std::string("/java"); #else static std::string prepend = std::string("osgPlugins-")+std::string(osgGetVersion())+std::string("/"); #endif [..] same design: static std::string prepend = std::string("osgPlugins-")+std::string(osgGetVersion())+std::string("/"); Mikhail. 04.06.2012 13:17, Mikhail I. Izmestev написал:Hi Robert, It is hard to reproduce this problem (as any thread safety problem) in same state as previous. I have another crash with same problem at: ntdll!RtlEnterCriticalSection+0x6 ot12_OpenThreads!OpenThreads::Mutex::lock+0xe osgdb_deprecated_osg!initGLNames+0x66 osgdb_deprecated_osg!StateSet_readLocalData+0x4f osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObjectOfType+0x9eb osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObjectOfType+0x28 osgdb_deprecated_osg!Node_readLocalData+0x349 osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObject+0x8fb osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readNode+0xe1 osgdb_osg!OSGReaderWriter::readNode+0xfe osgdb_osg!OSGReaderWriter::readNode+0x31c osg80_osgDB!osgDB::Registry::ReadNodeFunctor::doRead+0x28 osg80_osgDB!osgDB::Registry::read+0x5e4 osg80_osgDB!osgDB::Registry::readImplementation+0x34c osg80_osgDB!osgDB::Registry::readNodeImplementation+0x6a osg80_osgDB!osgDB::Registry::readNode+0xfc osg80_osgDB!osgDB::readNodeFile+0x4e crashed code: int Mutex::lock() { Win32MutexPrivateData *pd = static_cast<Win32MutexPrivateData*>(_prvData); #ifdef USE_CRITICAL_SECTION // Block until we can take this lock. EnterCriticalSection( &(pd->_cs) ); <<<<<<<<<<<< CRASH HERE return 0; [...] pd->_cs == NULL in this case problem at void initGLNames() { static bool first_time = true; if (!first_time) return; static OpenThreads::Mutex s_initGLNames; OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_initGLNames); [...] There is lot of other places with same design: AnimationPath.cpp:201: static osg::ref_ptr<osg::AnimationPath> s_path = new osg::AnimationPath; CoordinateSystemNode.cpp:48: static ref_ptr<EllipsoidModel> s_ellipsoidModel = new EllipsoidModel; Drawable.cpp:30: static ref_ptr<StateSet> s_drawstate = new osg::StateSet; Node.cpp:77: static ref_ptr<StateSet> s_drawstate = new osg::StateSet; Node.cpp:85: static ref_ptr<NodeCallback> s_nodecallback = new osg::NodeCallback; NodeCallback.cpp:31: static osg::ref_ptr<NodeCallback> s_nc = new NodeCallback; OccluderNode.cpp:30: static ref_ptr<ConvexPlanarOccluder> s_occluder = new ConvexPlanarOccluder; Sequence.cpp:26:static bool Sequence_matchLoopMode(const char* str, Sequence.cpp:45:static const char* Sequence_getLoopMode(Sequence::LoopMode mode) Sequence.cpp:57:static bool Sequence_matchSeqMode(const char* str, Sequence.cpp:76:static const char* Sequence_getSeqMode(Sequence::SequenceMode mode) StateAttribute.cpp:32: static ref_ptr<StateAttributeCallback> s_callback = new osg::StateAttributeCallback; StateSet.cpp:80: static bool first_time = true; StateSet.cpp:83: static OpenThreads::Mutex s_initGLNames; StateSet.cpp:362: static ref_ptr<StateSet::Callback> s_callback = new osg::StateSet::Callback; Uniform.cpp:212: static ref_ptr<Uniform::Callback> s_callback = new osg::Uniform::Callback; Mikhail. 04.06.2012 12:44, Robert Osfield написал:Hi Mikhail, I have moved the static into the global scope of the osgWrappers/deprecated-dotosg/Drawable.cpp, file attached, could try it out? Robert. On 2 June 2012 11:12, Mikhail I. Izmestev<[email protected]> wrote:Hi, I noticed crashing in dotosg wrappers when try to use osgDB::readNodeFile from multiple threads. Crash occurs when I try to load .osg file from two threads. For example callstack of crashed thread: osg80_osgDB!concrete_wrapper::matches+0x4 osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObjectOfType+0x527 osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObjectOfType+0x28 osgdb_deprecated_osg!Drawable_readLocalData+0xa1 osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObject+0x8fb osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readDrawable+0xe1 osgdb_deprecated_osg!Geode_readLocalData+0x90 osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObject+0x8fb osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readNode+0xe1 osgdb_deprecated_osg!Group_readLocalData+0x71 osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObject+0x8fb osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readNode+0xe1 osgdb_deprecated_osg!Group_readLocalData+0x71 osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObject+0x8fb osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readNode+0xe1 osgdb_osg!OSGReaderWriter::readNode+0xfe osgdb_osg!OSGReaderWriter::readNode+0x31c osg80_osgDB!osgDB::Registry::ReadNodeFunctor::doRead+0x28 osg80_osgDB!osgDB::Registry::read+0x5e4 osg80_osgDB!osgDB::Registry::readImplementation+0x34c osg80_osgDB!osgDB::Registry::readNodeImplementation+0x6a osg80_osgDB!osgDB::Registry::readNode+0xfc osg80_osgDB!osgDB::readNodeFile+0x4e [...] second thread callstack: msvcp90!std::basic_istream<char,std::char_traits<char> msvcp90!std::basic_istream<char,std::char_traits<char> osg80_osgDB!osgDB::FieldReader::_readField+0x3f8 osg80_osgDB!osgDB::FieldReaderIterator::field+0x19d osgdb_deprecated_osg!Array_readLocalData+0xbfb osgdb_deprecated_osg!Geometry_readLocalData+0x991 osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObject+0x8fb osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readDrawable+0xe1 osgdb_deprecated_osg!Geode_readLocalData+0x90 osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObject+0x8fb osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readNode+0xe1 osgdb_deprecated_osg!Group_readLocalData+0x71 osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObject+0x8fb osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readNode+0xe1 osgdb_deprecated_osg!Group_readLocalData+0x9a osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObject+0x8fb osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readNode+0xe1 osgdb_deprecated_osg!Group_readLocalData+0x9a osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObject+0x8fb osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readNode+0xe1 osgdb_deprecated_osg!Group_readLocalData+0x71 osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObject+0x8fb osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readNode+0xe1 osgdb_osg!OSGReaderWriter::readNode+0xfe osgdb_osg!OSGReaderWriter::readNode+0x31c osg80_osgDB!osgDB::Registry::ReadNodeFunctor::doRead+0x28 osg80_osgDB!osgDB::Registry::read+0x5e4 osg80_osgDB!osgDB::Registry::readImplementation+0x34c osg80_osgDB!osgDB::Registry::readNodeImplementation+0x6a osg80_osgDB!osgDB::Registry::readNode+0xfc osg80_osgDB!osgDB::readNodeFile+0x4e [...] code: struct concrete_wrapper: basic_type_wrapper { virtual ~concrete_wrapper() {} concrete_wrapper(const osg::Object *myobj) : myobj_(myobj) {} bool matches(const osg::Object *proto) const { return myobj_->isSameKindAs(proto);<<<<<<<<<<<<<<<<<CRASH HERE<<<<<<< } const osg::Object *myobj_; }; crash occurs because myobj_ is NULL. myobj_ passed from osgdb_deprecated_osg!Drawable_readLocalData as s_drawstate bool Drawable_readLocalData(Object& obj, Input& fr) { bool iteratorAdvanced = false; Drawable& drawable = static_cast<Drawable&>(obj); static ref_ptr<StateSet> s_drawstate = new osg::StateSet; if (StateSet* readState = static_cast<StateSet*>(fr.readObjectOfType(*s_drawstate))) { drawable.setStateSet(readState); iteratorAdvanced = true; } [...] so problem is in static ref_ptr<StateSet> s_drawstate = new osg::StateSet; MSVC 2008 x64 compiler (maybe gcc too) generate this code as: static bool s_drawstate_init = false; static ref_ptr<StateSet> s_drawstate = NULL; bool Drawable_readLocalData(Object& obj, Input& fr) { bool iteratorAdvanced = false; Drawable& drawable = static_cast<Drawable&>(obj); if(!s_drawstate_init) { s_drawstate_init = true; s_drawstate = new osg::StateSet; } if (StateSet* readState = static_cast<StateSet*>(fr.readObjectOfType(*s_drawstate))) { drawable.setStateSet(readState); iteratorAdvanced = true; } [...] and this code is not thread safe as you can see. Possible solution is to move static variables to global scope to avoid lazy initialization. Mikhail. _______________________________________________ osg-users mailing list [email protected] http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org _______________________________________________ osg-users mailing list [email protected] http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
_______________________________________________ osg-users mailing list [email protected] http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org

