Changed the ref_ptr<T> observer_ptr<>::lock() method to be
bool observer_ptr<>::lock(ref_ptr<T>&) to avoid the temporary ref_ptr<>'s being created and destroyed on the stack along with the associated ref/unref() operations
This commit is contained in:
@@ -538,9 +538,10 @@ public:
|
||||
Object*, NodeVisitor* /*nv*/)
|
||||
{
|
||||
if (ea.getHandled()) return false;
|
||||
ref_ptr<Depth> depth = _depth.lock();
|
||||
if (!depth.valid())
|
||||
return false;
|
||||
|
||||
ref_ptr<Depth> depth;
|
||||
if (!_depth.lock(depth)) return false;
|
||||
|
||||
switch(ea.getEventType())
|
||||
{
|
||||
case(osgGA::GUIEventAdapter::KEYUP):
|
||||
|
||||
@@ -23,8 +23,6 @@
|
||||
|
||||
namespace osg {
|
||||
|
||||
#if 1
|
||||
|
||||
/** Smart pointer for observed objects, that automatically set pointers to them to null when they deleted.
|
||||
* To use the observer_ptr<> robustly in multi-threaded applications it is recommend to access the pointer via
|
||||
* the lock() method that passes back a ref_ptr<> that safely takes a reference to the object to prevent deletion
|
||||
@@ -96,17 +94,27 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ref_ptr from a observer_ptr. The ref_ptr will be valid if the
|
||||
* Assign the observer_ptr to a ref_ptr. The ref_ptr will be valid if the
|
||||
* referenced object hasn't been deleted and has a ref count > 0.
|
||||
*/
|
||||
ref_ptr<T> lock() const
|
||||
bool lock(ref_ptr<T>& rptr) const
|
||||
{
|
||||
if (!_reference) return ref_ptr<T>();
|
||||
if (!_reference)
|
||||
{
|
||||
rptr = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
Referenced* obj = _reference->addRefLock();
|
||||
if (!obj) return ref_ptr<T>();
|
||||
ref_ptr<T> result(_ptr);
|
||||
if (!obj)
|
||||
{
|
||||
rptr = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
rptr = _ptr;
|
||||
obj->unref_nodelete();
|
||||
return result;
|
||||
return rptr.valid();
|
||||
}
|
||||
|
||||
/** Comparison operators. These continue to work even after the
|
||||
@@ -146,316 +154,6 @@ protected:
|
||||
T* _ptr;
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
// Internal class used to hold the "naked" pointer to the weakly
|
||||
// referenced object
|
||||
template<typename T>
|
||||
struct WeakReference : public Observer, public Referenced
|
||||
{
|
||||
WeakReference(const T* ptr) : _ptr(const_cast<T*>(ptr)) {}
|
||||
|
||||
virtual void objectDeleted(void*)
|
||||
{
|
||||
bool deleteNeeded = false;
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
||||
if (!_ptr)
|
||||
{
|
||||
// The last weak reference was deleted after the last
|
||||
// reference, but the observer hasn't run yet. The
|
||||
// observer can't be prevented from running, so it
|
||||
// must delete itself.
|
||||
deleteNeeded = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_ptr = 0;
|
||||
}
|
||||
}
|
||||
if (deleteNeeded) delete this;
|
||||
}
|
||||
|
||||
/**
|
||||
* "Lock" a Referenced object i.e., protect it from being deleted
|
||||
* by incrementing its reference count.
|
||||
*
|
||||
* returns null if object doesn't exist anymore
|
||||
*/
|
||||
virtual T* addRefLock()
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
||||
if (!_ptr) return 0;
|
||||
int refCount = _ptr->ref();
|
||||
if (refCount == 1)
|
||||
{
|
||||
// The object is in the process of being deleted, but our
|
||||
// objectDeleted() method hasn't been run yet (and we're
|
||||
// blocking it -- and the final destruction -- with our lock).
|
||||
_ptr->unref_nodelete();
|
||||
return 0;
|
||||
}
|
||||
return _ptr;
|
||||
}
|
||||
OpenThreads::Mutex _mutex;
|
||||
T* _ptr;
|
||||
};
|
||||
|
||||
// Reference object for observer_ptr that was initialized with an
|
||||
// "unsafe" object e.g., a stack-allocated object.
|
||||
|
||||
template<typename T>
|
||||
struct UnsafeWeakReference : public WeakReference<T>
|
||||
{
|
||||
UnsafeWeakReference(const T* ptr) : WeakReference<T>(ptr) {}
|
||||
|
||||
// Don't even touch the ref count of an unsafe object
|
||||
T* addRefLock()
|
||||
{
|
||||
OSG_WARN << "tried to lock an unsafe observer_ptr.";
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
Delete the WeakReference object, if necessary. The WeakReference
|
||||
should be deleted when the last observer_ptr pointing to it goes
|
||||
out of scope; this avoids a memory leak. A race must be prevented
|
||||
between this function and WeakReference::objectDeleted(). If the
|
||||
referenced object is being deleted at the same time as this
|
||||
function is called, we can't prevent objectDeleted() from being
|
||||
run, so we need to leave the WeakReference in a valid state and let
|
||||
objectDeleted() delete it. */
|
||||
template<typename T>
|
||||
void maybeDelete(WeakReference<T>* weakRef)
|
||||
{
|
||||
if (!weakRef || weakRef->unref_nodelete() > 0)
|
||||
return;
|
||||
// No other observer_ptrs hold weakRef, so clean up.
|
||||
bool doDelete = false;
|
||||
bool doRemove = false;
|
||||
UnsafeWeakReference<T>* unsafe = 0;
|
||||
T* ptr = 0;
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(weakRef->_mutex);
|
||||
if (!weakRef->_ptr)
|
||||
{
|
||||
// The object has already been deleted; it's OK to delete weakRef.
|
||||
doDelete = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = weakRef->_ptr;
|
||||
// Carefully remove weakRef as an observer.
|
||||
unsafe = dynamic_cast<UnsafeWeakReference<T>*>(weakRef);
|
||||
if (!unsafe && weakRef->_ptr->ref() == 1)
|
||||
{
|
||||
// The referenced object is being deleted, so the
|
||||
// Observer method must delete the weak reference.
|
||||
weakRef->_ptr->unref_nodelete();
|
||||
weakRef->_ptr = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The referenced object won't be deleted until we
|
||||
// decrement the reference count, so remove the
|
||||
// observer. However, we need to give up the lock on
|
||||
// weakRef first, to avoid an ordering deadlock;
|
||||
// removeObserver takes a lock on the observer set.
|
||||
doRemove = true;
|
||||
doDelete = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (doRemove)
|
||||
{
|
||||
ptr->removeObserver(weakRef);
|
||||
if (!unsafe)
|
||||
ptr->unref_nodelete();
|
||||
}
|
||||
if (doDelete) delete weakRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a weak reference from a Referenced. This returns a
|
||||
* WeakReference object with the ref count bumped. We must already
|
||||
* hold a reference to the Referenced object so it won't get
|
||||
* deleted during this process.
|
||||
*/
|
||||
template<typename T> WeakReference<T>* getWeakReference(const T* object);
|
||||
|
||||
/** Smart pointer for observed objects, that automatically set pointers to them to null when they deleted.
|
||||
* To use the observer_ptr<> robustly in multi-threaded applications it is recommend to access the pointer via
|
||||
* the lock() method that passes back a ref_ptr<> that safely takes a reference to the object to prevent deletion
|
||||
* during usage of the object. In certain conditions it may be safe to use the pointer directly without using lock(),
|
||||
* which will confer a perfomance advantage, the conditions are:
|
||||
* 1) The data structure is only accessed/deleted in single threaded/serial way.
|
||||
* 2) The data strucutre is guarenteed by high level management of data strucutures and threads which avoid
|
||||
* possible situations where the observer_ptr<>'s object may be deleted by one thread whilst being accessed
|
||||
* by another.
|
||||
* If you are in any doubt about whether it is safe to access the object safe then use
|
||||
* ref_ptr<> observer_ptr<>.lock() combination. */
|
||||
template<class T>
|
||||
class observer_ptr : public Observer
|
||||
{
|
||||
public:
|
||||
typedef T element_type;
|
||||
observer_ptr() : _reference(0) {}
|
||||
/**
|
||||
* Create a observer_ptr from a ref_ptr.
|
||||
*/
|
||||
observer_ptr(const ref_ptr<T>& rp)
|
||||
{
|
||||
_reference = getWeakReference(rp.get());
|
||||
}
|
||||
/**
|
||||
* Create a observer_ptr from a raw pointer. For compatibility;
|
||||
* the result might not be lockable.
|
||||
*/
|
||||
observer_ptr(T* rp)
|
||||
{
|
||||
_reference = getWeakReference<T>(rp);
|
||||
}
|
||||
|
||||
observer_ptr(const observer_ptr& wp) : _reference(wp._reference)
|
||||
{
|
||||
if (_reference) _reference->ref();
|
||||
}
|
||||
|
||||
~observer_ptr()
|
||||
{
|
||||
maybeDelete(_reference);
|
||||
}
|
||||
|
||||
observer_ptr& operator = (const observer_ptr& wp)
|
||||
{
|
||||
if (wp._reference) wp._reference->ref();
|
||||
maybeDelete(_reference);
|
||||
_reference = wp._reference;
|
||||
return *this;
|
||||
}
|
||||
|
||||
observer_ptr& operator = (const ref_ptr<T>& rp)
|
||||
{
|
||||
WeakReference<T>* tmp = getWeakReference(rp.get());
|
||||
maybeDelete(_reference);
|
||||
_reference = tmp;
|
||||
return *this;
|
||||
}
|
||||
|
||||
observer_ptr& operator = (T* rp)
|
||||
{
|
||||
WeakReference<T>* tmp = getWeakReference(rp);
|
||||
maybeDelete(_reference);
|
||||
_reference = tmp;
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Create a ref_ptr from a observer_ptr. The ref_ptr will be valid if the
|
||||
* referenced object hasn't been deleted and has a ref count > 0.
|
||||
*/
|
||||
ref_ptr<T> lock() const
|
||||
{
|
||||
if (!_reference)
|
||||
return ref_ptr<T>();
|
||||
T* obj = _reference->addRefLock();
|
||||
if (!obj)
|
||||
return ref_ptr<T>();
|
||||
ref_ptr<T> result(obj);
|
||||
obj->unref_nodelete();
|
||||
return result;
|
||||
}
|
||||
/** Comparison operators. These continue to work even after the
|
||||
* observed object has been deleted.
|
||||
*/
|
||||
bool operator == (const observer_ptr& wp) const
|
||||
{ return _reference == wp._reference; }
|
||||
bool operator != (const observer_ptr& wp) const
|
||||
{ return _reference != wp._reference; }
|
||||
bool operator < (const observer_ptr& wp) const
|
||||
{ return _reference < wp._reference; }
|
||||
bool operator > (const observer_ptr& wp) const
|
||||
{ return _reference > wp._reference; }
|
||||
// Non-strict interface, for compatibility
|
||||
// comparison operator for const T*.
|
||||
inline bool operator == (const T* ptr) const
|
||||
{
|
||||
if (!_reference)
|
||||
return !ptr;
|
||||
else
|
||||
return (_reference->_ptr==ptr);
|
||||
}
|
||||
inline bool operator != (const T* ptr) const
|
||||
{
|
||||
if (!_reference)
|
||||
return ptr != 0;
|
||||
else
|
||||
return (_reference->_ptr!=ptr);
|
||||
}
|
||||
inline bool operator < (const T* ptr) const { return (_reference && _reference->_ptr<ptr); }
|
||||
inline bool operator > (const T* ptr) const { return (_reference && _reference->ptr>ptr); }
|
||||
// Convenience methods for operating on object, however, access is not automatically threadsafe.
|
||||
// To make thread safe, one should either ensure at a high level
|
||||
// that the object will not be deleted while operating on it, or
|
||||
// by using the observer_ptr<>::lock() to get a ref_ptr<> that
|
||||
// ensures the objects stay alive throughout all access to it.
|
||||
|
||||
// Throw an error if _reference is null?
|
||||
inline T& operator*() const { return *_reference->_ptr; }
|
||||
inline T* operator->() const { return _reference? _reference->_ptr : 0; }
|
||||
// get the raw C pointer
|
||||
inline T* get() const { return _reference ? _reference->_ptr : 0; }
|
||||
|
||||
inline bool operator!() const { return !_reference || !_reference->_ptr; }
|
||||
inline bool valid() const { return _reference && _reference->_ptr; }
|
||||
protected:
|
||||
// The pointer to the WeakReference is not kept in a ref_ptr so that
|
||||
// its deletion can be managed explicitly.
|
||||
WeakReference<T>* _reference;
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
WeakReference<T>*
|
||||
getWeakReference(const T* object)
|
||||
{
|
||||
if (!object)
|
||||
return 0;
|
||||
WeakReference<T>* result = 0;
|
||||
ObserverSet* setData = object->getOrCreateObserverSet();
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*setData->getObserverSetMutex());
|
||||
ObserverSet::Observers &observers = setData->getObservers();
|
||||
for (ObserverSet::Observers::iterator itr = observers.begin(),
|
||||
end = observers.end();
|
||||
itr != end;
|
||||
++itr)
|
||||
{
|
||||
if ((result = dynamic_cast<WeakReference<T>*>(*itr)))
|
||||
{
|
||||
int weakRefCount = result->ref();
|
||||
if (weakRefCount == 1)
|
||||
{
|
||||
// The last weak reference disappeared, but hasn't
|
||||
// been removed from the observers list yet.
|
||||
result->unref_nodelete();
|
||||
}
|
||||
else
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (object->referenceCount() > 0)
|
||||
result = new WeakReference<T>(object);
|
||||
else
|
||||
result = new UnsafeWeakReference<T>(object);
|
||||
result->ref();
|
||||
observers.insert(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -100,8 +100,7 @@ bool ObserverNodePath::getRefNodePath(RefNodePath& refNodePath) const
|
||||
refNodePath.resize(_nodePath.size());
|
||||
for(unsigned int i=0; i<_nodePath.size(); ++i)
|
||||
{
|
||||
refNodePath[i] = _nodePath[i].lock();
|
||||
if (!refNodePath[i].valid())
|
||||
if (!_nodePath[i].lock(refNodePath[i]))
|
||||
{
|
||||
OSG_INFO<<"ObserverNodePath::getRefNodePath() node has been invalidated"<<std::endl;
|
||||
refNodePath.clear();
|
||||
|
||||
@@ -1612,8 +1612,8 @@ void DatabasePager::removeExpiredSubgraphs(const osg::FrameStamp& frameStamp)
|
||||
itr != _activePagedLODList.end();
|
||||
)
|
||||
{
|
||||
osg::ref_ptr<osg::PagedLOD> plod = itr->lock();
|
||||
if (plod.valid())
|
||||
osg::ref_ptr<osg::PagedLOD> plod;
|
||||
if (itr->lock(plod))
|
||||
{
|
||||
int delta = frameStamp.getFrameNumber() - plod->getFrameNumberOfLastTraversal();
|
||||
if (delta>1)
|
||||
@@ -1643,8 +1643,8 @@ void DatabasePager::removeExpiredSubgraphs(const osg::FrameStamp& frameStamp)
|
||||
itr != _inactivePagedLODList.end();
|
||||
)
|
||||
{
|
||||
osg::ref_ptr<osg::PagedLOD> plod = itr->lock();
|
||||
if (plod.valid())
|
||||
osg::ref_ptr<osg::PagedLOD> plod;
|
||||
if (itr->lock(plod))
|
||||
{
|
||||
int delta = frameStamp.getFrameNumber() - plod->getFrameNumberOfLastTraversal();
|
||||
if (delta>1)
|
||||
@@ -1702,8 +1702,8 @@ void DatabasePager::removeExpiredSubgraphs(const osg::FrameStamp& frameStamp)
|
||||
itr!=_inactivePagedLODList.end() && countPagedLODsVisitor._numPagedLODs<numToPrune;
|
||||
)
|
||||
{
|
||||
osg::ref_ptr<osg::PagedLOD> plod = itr->lock();
|
||||
if (plod.valid() && countPagedLODsVisitor._pagedLODs.count(plod.get())==0)
|
||||
osg::ref_ptr<osg::PagedLOD> plod;
|
||||
if (itr->lock(plod) && countPagedLODsVisitor._pagedLODs.count(plod.get())==0)
|
||||
{
|
||||
countPagedLODsVisitor.removeExpiredChildrenAndCountPagedLODs(plod.get(), expiryTime, expiryFrame, childrenRemoved);
|
||||
|
||||
@@ -1721,8 +1721,8 @@ void DatabasePager::removeExpiredSubgraphs(const osg::FrameStamp& frameStamp)
|
||||
itr!=_activePagedLODList.end() && countPagedLODsVisitor._numPagedLODs<numToPrune;
|
||||
)
|
||||
{
|
||||
osg::ref_ptr<osg::PagedLOD> plod = itr->lock();
|
||||
if (plod.valid() && countPagedLODsVisitor._pagedLODs.count(plod.get())==0)
|
||||
osg::ref_ptr<osg::PagedLOD> plod;
|
||||
if (itr->lock(plod) && countPagedLODsVisitor._pagedLODs.count(plod.get())==0)
|
||||
{
|
||||
countPagedLODsVisitor.removeExpiredChildrenAndCountPagedLODs(plod.get(), expiryTime, expiryFrame, childrenRemoved);
|
||||
|
||||
|
||||
@@ -561,10 +561,10 @@ BEGIN_OBJECT_REFLECTOR(osg::observer_ptr< osg::GraphicsContext >)
|
||||
____observer_ptr__C5_observer_ptr_R1,
|
||||
"",
|
||||
"");
|
||||
I_Method0(osg::ref_ptr< osg::GraphicsContext >, lock,
|
||||
I_Method1(bool, lock, IN, osg::ref_ptr< osg::GraphicsContext > &, rptr,
|
||||
Properties::NON_VIRTUAL,
|
||||
__ref_ptrT1_T___lock,
|
||||
"Create a ref_ptr from a observer_ptr. ",
|
||||
__bool__lock__ref_ptrT1_T__R1,
|
||||
"Assign the observer_ptr to a ref_ptr. ",
|
||||
"The ref_ptr will be valid if the referenced object hasn't been deleted and has a ref count > 0. ");
|
||||
I_Method0(osg::GraphicsContext *, get,
|
||||
Properties::NON_VIRTUAL,
|
||||
|
||||
@@ -251,10 +251,10 @@ BEGIN_OBJECT_REFLECTOR(osg::observer_ptr< osg::Node >)
|
||||
____observer_ptr__C5_observer_ptr_R1,
|
||||
"",
|
||||
"");
|
||||
I_Method0(osg::ref_ptr< osg::Node >, lock,
|
||||
I_Method1(bool, lock, IN, osg::ref_ptr< osg::Node > &, rptr,
|
||||
Properties::NON_VIRTUAL,
|
||||
__ref_ptrT1_T___lock,
|
||||
"Create a ref_ptr from a observer_ptr. ",
|
||||
__bool__lock__ref_ptrT1_T__R1,
|
||||
"Assign the observer_ptr to a ref_ptr. ",
|
||||
"The ref_ptr will be valid if the referenced object hasn't been deleted and has a ref count > 0. ");
|
||||
I_Method0(osg::Node *, get,
|
||||
Properties::NON_VIRTUAL,
|
||||
|
||||
@@ -969,10 +969,10 @@ BEGIN_OBJECT_REFLECTOR(osg::observer_ptr< osgWidget::Widget >)
|
||||
____observer_ptr__C5_observer_ptr_R1,
|
||||
"",
|
||||
"");
|
||||
I_Method0(osg::ref_ptr< osgWidget::Widget >, lock,
|
||||
I_Method1(bool, lock, IN, osg::ref_ptr< osgWidget::Widget > &, rptr,
|
||||
Properties::NON_VIRTUAL,
|
||||
__ref_ptrT1_T___lock,
|
||||
"Create a ref_ptr from a observer_ptr. ",
|
||||
__bool__lock__ref_ptrT1_T__R1,
|
||||
"Assign the observer_ptr to a ref_ptr. ",
|
||||
"The ref_ptr will be valid if the referenced object hasn't been deleted and has a ref count > 0. ");
|
||||
I_Method0(osgWidget::Widget *, get,
|
||||
Properties::NON_VIRTUAL,
|
||||
|
||||
@@ -971,10 +971,10 @@ BEGIN_OBJECT_REFLECTOR(osg::observer_ptr< osgWidget::Window >)
|
||||
____observer_ptr__C5_observer_ptr_R1,
|
||||
"",
|
||||
"");
|
||||
I_Method0(osg::ref_ptr< osgWidget::Window >, lock,
|
||||
I_Method1(bool, lock, IN, osg::ref_ptr< osgWidget::Window > &, rptr,
|
||||
Properties::NON_VIRTUAL,
|
||||
__ref_ptrT1_T___lock,
|
||||
"Create a ref_ptr from a observer_ptr. ",
|
||||
__bool__lock__ref_ptrT1_T__R1,
|
||||
"Assign the observer_ptr to a ref_ptr. ",
|
||||
"The ref_ptr will be valid if the referenced object hasn't been deleted and has a ref count > 0. ");
|
||||
I_Method0(osgWidget::Window *, get,
|
||||
Properties::NON_VIRTUAL,
|
||||
|
||||
Reference in New Issue
Block a user