Refactored the osg::Referenced observerset code so that it now uses a dedicated ObserverSet class,
which utilises a global recursive mutex that is dedicated to manage Observer and ObserverSet. The new global mutex for observers avoids problems with deadlocks that were occurring previously when an osg::Refenced object was being deleted at the same time as on osg::ObserverNodePath.
This commit is contained in:
parent
6196652ef0
commit
b09757bdb8
@ -11,28 +11,63 @@
|
|||||||
* OpenSceneGraph Public License for more details.
|
* OpenSceneGraph Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef OSG_OCCLUDER
|
#ifndef OSG_OBSERVER
|
||||||
#define OSG_OCCLUDER 1
|
#define OSG_OBSERVER 1
|
||||||
|
|
||||||
|
#include <OpenThreads/Mutex>
|
||||||
|
#include <osg/Export>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
namespace osg {
|
namespace osg {
|
||||||
|
|
||||||
/** Observer base class for tracking when objects are unreferenced (there reference count goes to 0) and are being deleted.*/
|
/** Observer base class for tracking when objects are unreferenced (there reference count goes to 0) and are being deleted.*/
|
||||||
class Observer
|
class OSG_EXPORT Observer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~Observer() {}
|
virtual ~Observer() {}
|
||||||
|
|
||||||
/** objectUnreferenced(void*) is called when the observed object's referenced count goes to zero, indicating that
|
/** Get the optional global observer mutex, this can be shared between all osg::Observer.*/
|
||||||
* the object will be deleted unless a new reference is made to it. If you wish to prevent deletion of the object
|
static OpenThreads::Mutex* getGlobalObserverMutex();
|
||||||
* then it's reference count should be incremented such as via taking a ref_ptr<> to it, if no refernce is taken
|
|
||||||
* by any of the observers of the object then the object will be deleted, and objectDeleted will in turn be called.
|
|
||||||
* return true if the Observer wishes to removed from the oberseved objects observer set.*/
|
|
||||||
virtual bool objectUnreferenced(void*) { return false; }
|
|
||||||
|
|
||||||
/** objectDeleted is called when the observed object is about to be deleted. The observer will be automatically
|
inline OpenThreads::Mutex* getObserverMutex() const { return osg::Observer::getGlobalObserverMutex(); }
|
||||||
* removed from the observerd objects observer set so there is no need for the objectDeleted implementation
|
|
||||||
* to call removeObserver() on the observed object. */
|
/** objectUnreferenced(void*) is called when the observed object's referenced count goes to zero, indicating that
|
||||||
virtual void objectDeleted(void*) {}
|
* the object will be deleted unless a new reference is made to it. If you wish to prevent deletion of the object
|
||||||
|
* then it's reference count should be incremented such as via taking a ref_ptr<> to it, if no refernce is taken
|
||||||
|
* by any of the observers of the object then the object will be deleted, and objectDeleted will in turn be called.
|
||||||
|
* return true if the Observer wishes to removed from the oberseved objects observer set.*/
|
||||||
|
virtual bool objectUnreferenced(void*) { return false; }
|
||||||
|
|
||||||
|
/** objectDeleted is called when the observed object is about to be deleted. The observer will be automatically
|
||||||
|
* removed from the observerd objects observer set so there is no need for the objectDeleted implementation
|
||||||
|
* to call removeObserver() on the observed object. */
|
||||||
|
virtual void objectDeleted(void*) {}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Class used by osg::Referenced to track the observers assoicated with it.*/
|
||||||
|
class OSG_EXPORT ObserverSet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
ObserverSet();
|
||||||
|
~ObserverSet();
|
||||||
|
|
||||||
|
inline OpenThreads::Mutex* getObserverSetMutex() const { return osg::Observer::getGlobalObserverMutex(); }
|
||||||
|
|
||||||
|
void addObserver(Observer* observer);
|
||||||
|
void removeObserver(Observer* observer);
|
||||||
|
|
||||||
|
void signalObjectUnreferenced(void* ptr);
|
||||||
|
void signalObjectDeleted(void* ptr);
|
||||||
|
|
||||||
|
typedef std::set<Observer*> Observers;
|
||||||
|
Observers& getObservers() { return _observers; }
|
||||||
|
const Observers& getObservers() const { return _observers; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
Observers _observers;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,6 @@ class OSG_EXPORT ObserverNodePath : public osg::Observer
|
|||||||
|
|
||||||
virtual bool objectUnreferenced(void* ptr);
|
virtual bool objectUnreferenced(void* ptr);
|
||||||
|
|
||||||
mutable OpenThreads::Mutex _mutex;
|
|
||||||
osg::NodePath _nodePath;
|
osg::NodePath _nodePath;
|
||||||
bool _valid;
|
bool _valid;
|
||||||
};
|
};
|
||||||
|
@ -14,8 +14,7 @@
|
|||||||
#ifndef OSG_REFERENCED
|
#ifndef OSG_REFERENCED
|
||||||
#define OSG_REFERENCED 1
|
#define OSG_REFERENCED 1
|
||||||
|
|
||||||
// When building OSG with Java need to derive from Noodle::CBridgable class,
|
#include <osg/Observer>
|
||||||
#include <osg/Export>
|
|
||||||
|
|
||||||
#include <OpenThreads/ScopedLock>
|
#include <OpenThreads/ScopedLock>
|
||||||
#include <OpenThreads/Mutex>
|
#include <OpenThreads/Mutex>
|
||||||
@ -30,6 +29,7 @@ namespace osg {
|
|||||||
// forward declare, declared after Referenced below.
|
// forward declare, declared after Referenced below.
|
||||||
class DeleteHandler;
|
class DeleteHandler;
|
||||||
class Observer;
|
class Observer;
|
||||||
|
class ObserverSet;
|
||||||
|
|
||||||
/** template class to help enforce static initialization order. */
|
/** template class to help enforce static initialization order. */
|
||||||
template <typename T, T M()>
|
template <typename T, T M()>
|
||||||
@ -95,11 +95,25 @@ class OSG_EXPORT Referenced
|
|||||||
/** Return the number pointers currently referencing this object. */
|
/** Return the number pointers currently referencing this object. */
|
||||||
inline int referenceCount() const { return _refCount; }
|
inline int referenceCount() const { return _refCount; }
|
||||||
|
|
||||||
/** Add a Observer that is observing this object, notify the Observer when this object gets deleted.*/
|
|
||||||
void addObserver(Observer* observer) const;
|
/** Get the ObserverSet if one is attached, otherwise return NULL.*/
|
||||||
|
ObserverSet* getObserverSet() const
|
||||||
|
{
|
||||||
|
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
||||||
|
return static_cast<ObserverSet*>(_observerSet.get());
|
||||||
|
#else
|
||||||
|
return static_cast<ObserverSet*>(_observerSet);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the ObserverSet if one is attached, otherwise create an ObserverSet, attach it, then return this newly created ObserverSet.*/
|
||||||
|
ObserverSet* getOrCreateObserverSet() const;
|
||||||
|
|
||||||
/** Add a Observer that is observing this object, notify the Observer when this object gets deleted.*/
|
/** Add a Observer that is observing this object, notify the Observer when this object gets deleted.*/
|
||||||
void removeObserver(Observer* observer) const;
|
void addObserver(Observer* observer) const { getOrCreateObserverSet()->addObserver(observer); }
|
||||||
|
|
||||||
|
/** remove Observer that is observing this object.*/
|
||||||
|
void removeObserver(Observer* observer) const { getOrCreateObserverSet()->removeObserver(observer); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -128,9 +142,7 @@ class OSG_EXPORT Referenced
|
|||||||
void deleteUsingDeleteHandler() const;
|
void deleteUsingDeleteHandler() const;
|
||||||
|
|
||||||
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
||||||
struct ObserverSetData;
|
mutable OpenThreads::AtomicPtr _observerSet;
|
||||||
|
|
||||||
mutable OpenThreads::AtomicPtr _observerSetDataPtr;
|
|
||||||
|
|
||||||
mutable OpenThreads::Atomic _refCount;
|
mutable OpenThreads::Atomic _refCount;
|
||||||
#else
|
#else
|
||||||
@ -139,7 +151,7 @@ class OSG_EXPORT Referenced
|
|||||||
|
|
||||||
mutable int _refCount;
|
mutable int _refCount;
|
||||||
|
|
||||||
mutable void* _observers;
|
mutable void* _observerSet;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -163,17 +175,17 @@ inline void Referenced::ref() const
|
|||||||
inline void Referenced::unref() const
|
inline void Referenced::unref() const
|
||||||
{
|
{
|
||||||
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
||||||
bool needDelete = (--_refCount <= 0);
|
bool needDelete = ((--_refCount) == 0);
|
||||||
#else
|
#else
|
||||||
bool needDelete = false;
|
bool needDelete = false;
|
||||||
if (_refMutex)
|
if (_refMutex)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
|
||||||
needDelete = (--_refCount)<=0;
|
needDelete = (--_refCount)==0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
needDelete = (--_refCount)<=0;
|
needDelete = (--_refCount)==0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -276,6 +276,7 @@ ADD_LIBRARY(${LIB_NAME}
|
|||||||
NodeVisitor.cpp
|
NodeVisitor.cpp
|
||||||
Notify.cpp
|
Notify.cpp
|
||||||
Object.cpp
|
Object.cpp
|
||||||
|
Observer.cpp
|
||||||
ObserverNodePath.cpp
|
ObserverNodePath.cpp
|
||||||
OccluderNode.cpp
|
OccluderNode.cpp
|
||||||
OcclusionQueryNode.cpp
|
OcclusionQueryNode.cpp
|
||||||
|
71
src/osg/Observer.cpp
Normal file
71
src/osg/Observer.cpp
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/* -*-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 <osg/ObserverNodePath>
|
||||||
|
#include <osg/Notify>
|
||||||
|
|
||||||
|
using namespace osg;
|
||||||
|
|
||||||
|
ObserverSet::ObserverSet()
|
||||||
|
{
|
||||||
|
//OSG_NOTICE<<"ObserverSet::ObserverSet() "<<this<<std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObserverSet::~ObserverSet()
|
||||||
|
{
|
||||||
|
//OSG_NOTICE<<"ObserverSet::~ObserverSet() "<<this<<", _observers.size()="<<_observers.size()<<std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObserverSet::addObserver(Observer* observer)
|
||||||
|
{
|
||||||
|
//OSG_NOTICE<<"ObserverSet::addObserver("<<observer<<") "<<this<<std::endl;
|
||||||
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*getObserverSetMutex());
|
||||||
|
_observers.insert(observer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObserverSet::removeObserver(Observer* observer)
|
||||||
|
{
|
||||||
|
//OSG_NOTICE<<"ObserverSet::removeObserver("<<observer<<") "<<this<<std::endl;
|
||||||
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*getObserverSetMutex());
|
||||||
|
_observers.erase(observer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObserverSet::signalObjectUnreferenced(void* ptr)
|
||||||
|
{
|
||||||
|
for(Observers::iterator itr = _observers.begin();
|
||||||
|
itr != _observers.end();
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if ((*itr)->objectUnreferenced(ptr))
|
||||||
|
{
|
||||||
|
Observers::iterator orig_itr = itr;
|
||||||
|
++itr;
|
||||||
|
_observers.erase(orig_itr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++itr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObserverSet::signalObjectDeleted(void* ptr)
|
||||||
|
{
|
||||||
|
for(Observers::iterator itr = _observers.begin();
|
||||||
|
itr != _observers.end();
|
||||||
|
++itr)
|
||||||
|
{
|
||||||
|
(*itr)->objectDeleted(ptr);
|
||||||
|
}
|
||||||
|
_observers.clear();
|
||||||
|
}
|
@ -82,7 +82,7 @@ void ObserverNodePath::setNodePathTo(osg::Node* node)
|
|||||||
|
|
||||||
void ObserverNodePath::setNodePath(const osg::NodePath& nodePath)
|
void ObserverNodePath::setNodePath(const osg::NodePath& nodePath)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*getObserverMutex());
|
||||||
_setNodePath(nodePath);
|
_setNodePath(nodePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +98,7 @@ void ObserverNodePath::setNodePath(const osg::RefNodePath& refNodePath)
|
|||||||
|
|
||||||
void ObserverNodePath::clearNodePath()
|
void ObserverNodePath::clearNodePath()
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*getObserverMutex());
|
||||||
_clearNodePath();
|
_clearNodePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ bool ObserverNodePath::getRefNodePath(RefNodePath& refNodePath) const
|
|||||||
{
|
{
|
||||||
refNodePath.clear();
|
refNodePath.clear();
|
||||||
|
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*getObserverMutex());
|
||||||
if (!_valid) return false;
|
if (!_valid) return false;
|
||||||
|
|
||||||
for(osg::NodePath::const_iterator itr = _nodePath.begin();
|
for(osg::NodePath::const_iterator itr = _nodePath.begin();
|
||||||
@ -123,7 +123,7 @@ bool ObserverNodePath::getNodePath(NodePath& nodePath) const
|
|||||||
{
|
{
|
||||||
nodePath.clear();
|
nodePath.clear();
|
||||||
|
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*getObserverMutex());
|
||||||
if (!_valid) return false;
|
if (!_valid) return false;
|
||||||
nodePath = _nodePath;
|
nodePath = _nodePath;
|
||||||
return true;
|
return true;
|
||||||
@ -168,7 +168,7 @@ bool ObserverNodePath::objectUnreferenced(void* ptr)
|
|||||||
{
|
{
|
||||||
osg::Node* node = reinterpret_cast<osg::Node*>(ptr);
|
osg::Node* node = reinterpret_cast<osg::Node*>(ptr);
|
||||||
|
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*getObserverMutex());
|
||||||
|
|
||||||
_valid = false;
|
_valid = false;
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
#include <osg/Referenced>
|
#include <osg/Referenced>
|
||||||
#include <osg/Notify>
|
#include <osg/Notify>
|
||||||
#include <osg/ApplicationUsage>
|
#include <osg/ApplicationUsage>
|
||||||
#include <osg/observer_ptr>
|
#include <osg/Observer>
|
||||||
|
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -87,14 +87,12 @@ OpenThreads::Mutex* Referenced::getGlobalReferencedMutex()
|
|||||||
return s_ReferencedGlobalMutext.get();
|
return s_ReferencedGlobalMutext.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef std::set<Observer*> ObserverSet;
|
// we'll implement Observer::getGlobalObserverMutex() here for convinience as ResetPointer is available.
|
||||||
|
OpenThreads::Mutex* Observer::getGlobalObserverMutex()
|
||||||
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
{
|
||||||
struct Referenced::ObserverSetData {
|
static GlobalMutexPointer s_ReferencedGlobalMutext = new OpenThreads::Mutex(OpenThreads::Mutex::MUTEX_RECURSIVE);
|
||||||
OpenThreads::Mutex _mutex;
|
return s_ReferencedGlobalMutext.get();
|
||||||
ObserverSet _observers;
|
}
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
||||||
static bool s_useThreadSafeReferenceCounting = getenv("OSG_THREAD_SAFE_REF_UNREF")!=0;
|
static bool s_useThreadSafeReferenceCounting = getenv("OSG_THREAD_SAFE_REF_UNREF")!=0;
|
||||||
@ -142,12 +140,12 @@ static int s_numObjects = 0;
|
|||||||
|
|
||||||
Referenced::Referenced():
|
Referenced::Referenced():
|
||||||
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
||||||
_observerSetDataPtr(0),
|
_observerSet(0),
|
||||||
_refCount(0)
|
_refCount(0)
|
||||||
#else
|
#else
|
||||||
_refMutex(0),
|
_refMutex(0),
|
||||||
_refCount(0),
|
_refCount(0),
|
||||||
_observers(0)
|
_observerSet(0)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
||||||
@ -161,7 +159,7 @@ Referenced::Referenced():
|
|||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getNumObjectMutex());
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getNumObjectMutex());
|
||||||
++s_numObjects;
|
++s_numObjects;
|
||||||
osg::notify(osg::NOTICE)<<"Object created, total num="<<s_numObjects<<std::endl;
|
OSG_NOTICE<<"Object created, total num="<<s_numObjects<<std::endl;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -169,12 +167,12 @@ Referenced::Referenced():
|
|||||||
|
|
||||||
Referenced::Referenced(bool threadSafeRefUnref):
|
Referenced::Referenced(bool threadSafeRefUnref):
|
||||||
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
||||||
_observerSetDataPtr(0),
|
_observerSet(0),
|
||||||
_refCount(0)
|
_refCount(0)
|
||||||
#else
|
#else
|
||||||
_refMutex(0),
|
_refMutex(0),
|
||||||
_refCount(0),
|
_refCount(0),
|
||||||
_observers(0)
|
_observerSet(0)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
||||||
@ -188,19 +186,19 @@ Referenced::Referenced(bool threadSafeRefUnref):
|
|||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getNumObjectMutex());
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getNumObjectMutex());
|
||||||
++s_numObjects;
|
++s_numObjects;
|
||||||
osg::notify(osg::NOTICE)<<"Object created, total num="<<s_numObjects<<std::endl;
|
OSG_NOTICE<<"Object created, total num="<<s_numObjects<<std::endl;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Referenced::Referenced(const Referenced&):
|
Referenced::Referenced(const Referenced&):
|
||||||
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
||||||
_observerSetDataPtr(0),
|
_observerSet(0),
|
||||||
_refCount(0)
|
_refCount(0)
|
||||||
#else
|
#else
|
||||||
_refMutex(0),
|
_refMutex(0),
|
||||||
_refCount(0),
|
_refCount(0),
|
||||||
_observers(0)
|
_observerSet(0)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
||||||
@ -214,7 +212,7 @@ Referenced::Referenced(const Referenced&):
|
|||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getNumObjectMutex());
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getNumObjectMutex());
|
||||||
++s_numObjects;
|
++s_numObjects;
|
||||||
osg::notify(osg::NOTICE)<<"Object created, total num="<<s_numObjects<<std::endl;
|
OSG_NOTICE<<"Object created, total num="<<s_numObjects<<std::endl;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -225,129 +223,84 @@ Referenced::~Referenced()
|
|||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getNumObjectMutex());
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getNumObjectMutex());
|
||||||
--s_numObjects;
|
--s_numObjects;
|
||||||
osg::notify(osg::NOTICE)<<"Object deleted, total num="<<s_numObjects<<std::endl;
|
OSG_NOTICE<<"Object deleted, total num="<<s_numObjects<<std::endl;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (_refCount>0)
|
if (_refCount>0)
|
||||||
{
|
{
|
||||||
notify(WARN)<<"Warning: deleting still referenced object "<<this<<" of type '"<<typeid(this).name()<<"'"<<std::endl;
|
OSG_WARN<<"Warning: deleting still referenced object "<<this<<" of type '"<<typeid(this).name()<<"'"<<std::endl;
|
||||||
notify(WARN)<<" the final reference count was "<<_refCount<<", memory corruption possible."<<std::endl;
|
OSG_WARN<<" the final reference count was "<<_refCount<<", memory corruption possible."<<std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// signal observers that we are being deleted.
|
// signal observers that we are being deleted.
|
||||||
signalObserversAndDelete(false, true, false);
|
signalObserversAndDelete(false, true, false);
|
||||||
|
|
||||||
|
// delete the ObserverSet
|
||||||
|
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
||||||
|
if (_observerSet.get()) delete static_cast<ObserverSet*>(_observerSet.get());
|
||||||
|
#else
|
||||||
|
if (_observerSet) delete static_cast<ObserverSet*>(_observerSet);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ObserverSet* Referenced::getOrCreateObserverSet() const
|
||||||
|
{
|
||||||
|
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
||||||
|
ObserverSet* observerSet = static_cast<ObserverSet*>(_observerSet.get());
|
||||||
|
while (0 == observerSet) {
|
||||||
|
ObserverSet* newObserverSet = new ObserverSet;
|
||||||
|
if (!_observerSet.assign(newObserverSet, 0))
|
||||||
|
delete newObserverSet;
|
||||||
|
observerSet = static_cast<ObserverSet*>(_observerSet.get());
|
||||||
|
}
|
||||||
|
return observerSet;
|
||||||
|
#else
|
||||||
|
if (_refMutex)
|
||||||
|
{
|
||||||
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
|
||||||
|
if (!_observerSet) _observerSet = new ObserverSet;
|
||||||
|
return static_cast<ObserverSet*>(_observerSet);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!_observerSet) _observerSet = new ObserverSet;
|
||||||
|
return static_cast<ObserverSet*>(_observerSet);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Referenced::signalObserversAndDelete(bool signalUnreferened, bool signalDelete, bool doDelete) const
|
void Referenced::signalObserversAndDelete(bool signalUnreferened, bool signalDelete, bool doDelete) const
|
||||||
{
|
{
|
||||||
if (signalUnreferened)
|
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
||||||
|
ObserverSet* observerSet = static_cast<ObserverSet*>(_observerSet.get());
|
||||||
|
#else
|
||||||
|
ObserverSet* observerSet = static_cast<ObserverSet*>(_observerSet);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (observerSet)
|
||||||
{
|
{
|
||||||
// tell all observers that we have been unreferenced so that they
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*(observerSet->getObserverSetMutex()));
|
||||||
// can do clean up or add their own reference to prevent deletion.
|
if (signalUnreferened)
|
||||||
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
{
|
||||||
ObserverSet* os = static_cast<ObserverSet*>(_observers);
|
observerSet->signalObjectUnreferenced(const_cast<Referenced*>(this));
|
||||||
if (os)
|
}
|
||||||
{
|
|
||||||
if (_refMutex)
|
if (_refCount!=0)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
|
OSG_NOTICE<<"Referenced::signalObserversAndDelete(,,) disabling delete as _refCount="<<_refCount<<std::endl;
|
||||||
for(ObserverSet::iterator itr = os->begin();
|
return;
|
||||||
itr != os->end();
|
}
|
||||||
)
|
|
||||||
{
|
if (signalDelete)
|
||||||
if ((*itr)->objectUnreferenced(const_cast<Referenced*>(this)))
|
{
|
||||||
{
|
observerSet->signalObjectDeleted(const_cast<Referenced*>(this));
|
||||||
ObserverSet::iterator orig_itr = itr;
|
}
|
||||||
++itr;
|
|
||||||
os.erase(orig_itr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
++itr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for(ObserverSet::iterator itr = os->begin();
|
|
||||||
itr != os->end();
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if ((*itr)->objectUnreferenced(const_cast<Referenced*>(this)))
|
|
||||||
{
|
|
||||||
ObserverSet::iterator orig_itr = itr;
|
|
||||||
++itr;
|
|
||||||
os.erase(orig_itr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
++itr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
ObserverSetData* observerSetData = static_cast<ObserverSetData*>(_observerSetDataPtr.get());
|
|
||||||
if (observerSetData)
|
|
||||||
{
|
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(observerSetData->_mutex);
|
|
||||||
for(ObserverSet::iterator itr = observerSetData->_observers.begin();
|
|
||||||
itr != observerSetData->_observers.end();
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if ((*itr)->objectUnreferenced(const_cast<Referenced*>(this)))
|
|
||||||
{
|
|
||||||
ObserverSet::iterator orig_itr = itr;
|
|
||||||
++itr;
|
|
||||||
observerSetData->_observers.erase(orig_itr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
++itr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_refCount!=0) return;
|
if (doDelete && _refCount==0)
|
||||||
|
|
||||||
if (signalDelete)
|
|
||||||
{
|
|
||||||
// tell all observers that we being delete so that they
|
|
||||||
// can do cleans up and remove any references they have.
|
|
||||||
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
|
||||||
ObserverSet* os = static_cast<ObserverSet*>(_observers);
|
|
||||||
if (os)
|
|
||||||
{
|
|
||||||
for(ObserverSet::iterator itr = os->begin();
|
|
||||||
itr != os->end();
|
|
||||||
++itr)
|
|
||||||
{
|
|
||||||
(*itr)->objectDeleted(const_cast<Referenced*>(this));
|
|
||||||
}
|
|
||||||
delete os;
|
|
||||||
_observers = 0;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
ObserverSetData* observerSetData = static_cast<ObserverSetData*>(_observerSetDataPtr.get());
|
|
||||||
if (observerSetData)
|
|
||||||
{
|
|
||||||
for(ObserverSet::iterator itr = observerSetData->_observers.begin();
|
|
||||||
itr != observerSetData->_observers.end();
|
|
||||||
++itr)
|
|
||||||
{
|
|
||||||
(*itr)->objectDeleted(const_cast<Referenced*>(this));
|
|
||||||
}
|
|
||||||
_observerSetDataPtr.assign(0, observerSetData);
|
|
||||||
delete observerSetData;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doDelete &&_refCount<=0)
|
|
||||||
{
|
{
|
||||||
|
//OSG_NOTICE<<"Referenced::signalObserversAndDelete(,,) doing delete as _refCount="<<_refCount<<std::endl;
|
||||||
if (getDeleteHandler()) deleteUsingDeleteHandler();
|
if (getDeleteHandler()) deleteUsingDeleteHandler();
|
||||||
else delete this;
|
else delete this;
|
||||||
}
|
}
|
||||||
@ -378,22 +331,21 @@ void Referenced::setThreadSafeRefUnref(bool threadSafe)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Referenced::unref_nodelete() const
|
void Referenced::unref_nodelete() const
|
||||||
{
|
{
|
||||||
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
||||||
|
bool needUnreferencedSignal = ((--_refCount) == 0);
|
||||||
|
#else
|
||||||
bool needUnreferencedSignal = false;
|
bool needUnreferencedSignal = false;
|
||||||
if (_refMutex)
|
if (_refMutex)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
|
||||||
needUnreferencedSignal = (--_refCount)<=0;
|
needUnreferencedSignal = ((--_refCount) == 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
needUnreferencedSignal = (--_refCount)<=0;
|
needUnreferencedSignal = ((--_refCount) == 0);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
bool needUnreferencedSignal = (--_refCount)<=0;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (needUnreferencedSignal)
|
if (needUnreferencedSignal)
|
||||||
@ -402,57 +354,6 @@ void Referenced::unref_nodelete() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Referenced::addObserver(Observer* observer) const
|
|
||||||
{
|
|
||||||
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
|
||||||
ObserverSetData* observerSetData = static_cast<ObserverSetData*>(_observerSetDataPtr.get());
|
|
||||||
while (0 == observerSetData) {
|
|
||||||
ObserverSetData* newObserverSetData = new ObserverSetData;
|
|
||||||
if (!_observerSetDataPtr.assign(newObserverSetData, 0))
|
|
||||||
delete newObserverSetData;
|
|
||||||
observerSetData = static_cast<ObserverSetData*>(_observerSetDataPtr.get());
|
|
||||||
}
|
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(observerSetData->_mutex);
|
|
||||||
observerSetData->_observers.insert(observer);
|
|
||||||
#else
|
|
||||||
if (_refMutex)
|
|
||||||
{
|
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
|
|
||||||
|
|
||||||
if (!_observers) _observers = new ObserverSet;
|
|
||||||
if (_observers) static_cast<ObserverSet*>(_observers)->insert(observer);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!_observers) _observers = new ObserverSet;
|
|
||||||
if (_observers) static_cast<ObserverSet*>(_observers)->insert(observer);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Referenced::removeObserver(Observer* observer) const
|
|
||||||
{
|
|
||||||
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
|
|
||||||
ObserverSetData* observerSetData = static_cast<ObserverSetData*>(_observerSetDataPtr.get());
|
|
||||||
if (observerSetData)
|
|
||||||
{
|
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(observerSetData->_mutex);
|
|
||||||
observerSetData->_observers.erase(observer);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (_refMutex)
|
|
||||||
{
|
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
|
|
||||||
|
|
||||||
if (_observers) static_cast<ObserverSet*>(_observers)->erase(observer);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (_observers) static_cast<ObserverSet*>(_observers)->erase(observer);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Referenced::deleteUsingDeleteHandler() const
|
void Referenced::deleteUsingDeleteHandler() const
|
||||||
{
|
{
|
||||||
getDeleteHandler()->requestDelete(this);
|
getDeleteHandler()->requestDelete(this);
|
||||||
|
Loading…
Reference in New Issue
Block a user