/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include #ifndef OSG_JAVA_BUILD namespace osg { //#define ENFORCE_THREADSAFE //#define DEBUG_OBJECT_ALLOCATION_DESTRUCTION // specialized smart pointer, used to get round auto_ptr<>'s lack of the destructor reseting itself to 0. struct DeleteHandlerPointer { DeleteHandlerPointer(): _ptr(0) {} DeleteHandlerPointer(DeleteHandler* ptr): _ptr(ptr) {} ~DeleteHandlerPointer() { delete _ptr; _ptr = 0; } inline DeleteHandlerPointer& operator = (DeleteHandler* ptr) { if (_ptr==ptr) return *this; delete _ptr; _ptr = ptr; return *this; } void reset(DeleteHandler* ptr) { if (_ptr==ptr) return; delete _ptr; _ptr = ptr; } inline DeleteHandler& operator*() { return *_ptr; } inline const DeleteHandler& operator*() const { return *_ptr; } inline DeleteHandler* operator->() { return _ptr; } inline const DeleteHandler* operator->() const { return _ptr; } DeleteHandler* get() { return _ptr; } const DeleteHandler* get() const { return _ptr; } DeleteHandler* _ptr; }; typedef std::set ObserverSet; static bool s_useThreadSafeReferenceCounting = getenv("OSG_THREAD_SAFE_REF_UNREF")!=0; // static std::auto_ptr s_deleteHandler(0); static DeleteHandlerPointer s_deleteHandler(0); static ApplicationUsageProxy Referenced_e0(ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_THREAD_SAFE_REF_UNREF",""); void Referenced::setThreadSafeReferenceCounting(bool enableThreadSafeReferenceCounting) { s_useThreadSafeReferenceCounting = enableThreadSafeReferenceCounting; } bool Referenced::getThreadSafeReferenceCounting() { return s_useThreadSafeReferenceCounting; } void Referenced::setDeleteHandler(DeleteHandler* handler) { s_deleteHandler.reset(handler); } DeleteHandler* Referenced::getDeleteHandler() { return s_deleteHandler.get(); } #ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION OpenThreads::Mutex& getNumObjectMutex() { static OpenThreads::Mutex s_numObjectMutex; return s_numObjectMutex; } static int s_numObjects = 0; #endif Referenced::Referenced(): _refMutex(0), _refCount(0), _observers(0) { #ifndef ENFORCE_THREADSAFE if (s_useThreadSafeReferenceCounting) #endif _refMutex = new OpenThreads::Mutex; #ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION { OpenThreads::ScopedLock lock(getNumObjectMutex()); ++s_numObjects; osg::notify(osg::NOTICE)<<"Object created, total num="< lock(getNumObjectMutex()); ++s_numObjects; osg::notify(osg::NOTICE)<<"Object created, total num="< lock(getNumObjectMutex()); ++s_numObjects; osg::notify(osg::NOTICE)<<"Object created, total num="< lock(getNumObjectMutex()); --s_numObjects; osg::notify(osg::NOTICE)<<"Object deleted, total num="<0) { notify(WARN)<<"Warning: deleting still referenced object "<(_observers); for(ObserverSet::iterator itr = os->begin(); itr != os->end(); ++itr) { (*itr)->objectDeleted(this); } delete os; _observers = 0; } if (_refMutex) { OpenThreads::Mutex* tmpMutexPtr = _refMutex; _refMutex = 0; delete tmpMutexPtr; } } void Referenced::setThreadSafeRefUnref(bool threadSafe) { if (threadSafe) { if (!_refMutex) { // we want thread safe ref()/unref() so assign a mutex _refMutex = new OpenThreads::Mutex; } } else { if (_refMutex) { // we don't want thread safe ref()/unref() so remove any assigned mutex OpenThreads::Mutex* tmpMutexPtr = _refMutex; _refMutex = 0; delete tmpMutexPtr; } } } void Referenced::unref_nodelete() const { if (_refMutex) { OpenThreads::ScopedLock lock(*_refMutex); --_refCount; } else { --_refCount; } } void Referenced::addObserver(Observer* observer) { if (_refMutex) { OpenThreads::ScopedLock lock(*_refMutex); if (!_observers) _observers = new ObserverSet; if (_observers) static_cast(_observers)->insert(observer); } else { if (!_observers) _observers = new ObserverSet; if (_observers) static_cast(_observers)->insert(observer); } } void Referenced::removeObserver(Observer* observer) { if (_refMutex) { OpenThreads::ScopedLock lock(*_refMutex); if (_observers) static_cast(_observers)->erase(observer); } else { if (_observers) static_cast(_observers)->erase(observer); } } void Referenced::deleteUsingDeleteHandler() const { getDeleteHandler()->requestDelete(this); } } // end of namespace osg #endif //OSG_JAVA_BUILD