Files
OpenSceneGraph/src/osg/Referenced.cpp
2016-09-05 15:35:54 +01:00

319 lines
7.8 KiB
C++

/* -*-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 <stdlib.h>
#include <osg/Referenced>
#include <osg/Notify>
#include <osg/ApplicationUsage>
#include <osg/Observer>
#include <typeinfo>
#include <memory>
#include <set>
#include <OpenThreads/ScopedLock>
#include <OpenThreads/Mutex>
#include <osg/DeleteHandler>
namespace osg
{
//#define ENFORCE_THREADSAFE
//#define DEBUG_OBJECT_ALLOCATION_DESTRUCTION
// specialized smart pointer, used to get round auto_ptr<>'s lack of the destructor resetting itself to 0.
template<typename T>
struct ResetPointer
{
ResetPointer():
_ptr(0) {}
ResetPointer(T* ptr):
_ptr(ptr) {}
~ResetPointer()
{
delete _ptr;
_ptr = 0;
}
inline ResetPointer& operator = (T* ptr)
{
if (_ptr==ptr) return *this;
delete _ptr;
_ptr = ptr;
return *this;
}
void reset(T* ptr)
{
if (_ptr==ptr) return;
delete _ptr;
_ptr = ptr;
}
inline T& operator*() { return *_ptr; }
inline const T& operator*() const { return *_ptr; }
inline T* operator->() { return _ptr; }
inline const T* operator->() const { return _ptr; }
T* get() { return _ptr; }
const T* get() const { return _ptr; }
T* _ptr;
};
typedef ResetPointer<DeleteHandler> DeleteHandlerPointer;
typedef ResetPointer<OpenThreads::Mutex> GlobalMutexPointer;
OpenThreads::Mutex* Referenced::getGlobalReferencedMutex()
{
static GlobalMutexPointer s_ReferencedGlobalMutext = new OpenThreads::Mutex;
return s_ReferencedGlobalMutext.get();
}
// helper class for forcing the global mutex to be constructed when the library is loaded.
struct InitGlobalMutexes
{
InitGlobalMutexes()
{
Referenced::getGlobalReferencedMutex();
}
};
static InitGlobalMutexes s_initGlobalMutexes;
// static std::auto_ptr<DeleteHandler> s_deleteHandler(0);
static DeleteHandlerPointer s_deleteHandler(0);
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():
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
_observerSet(0),
_refCount(0)
#else
_refMutex(0),
_refCount(0),
_observerSet(0)
#endif
{
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
_refMutex = new OpenThreads::Mutex;
#endif
#ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getNumObjectMutex());
++s_numObjects;
printf("Object created, total num=%d\n",s_numObjects);
}
#endif
}
Referenced::Referenced(bool /*threadSafeRefUnref*/):
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
_observerSet(0),
_refCount(0)
#else
_refMutex(0),
_refCount(0),
_observerSet(0)
#endif
{
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
_refMutex = new OpenThreads::Mutex;
#endif
#ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getNumObjectMutex());
++s_numObjects;
printf("Object created, total num=%d\n",s_numObjects);
}
#endif
}
Referenced::Referenced(const Referenced&):
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
_observerSet(0),
_refCount(0)
#else
_refMutex(0),
_refCount(0),
_observerSet(0)
#endif
{
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
_refMutex = new OpenThreads::Mutex;
#endif
#ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getNumObjectMutex());
++s_numObjects;
printf("Object created, total num=%d\n",s_numObjects);
}
#endif
}
Referenced::~Referenced()
{
#ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getNumObjectMutex());
--s_numObjects;
printf("Object created, total num=%d\n",s_numObjects);
}
#endif
if (_refCount>0)
{
OSG_WARN<<"Warning: deleting still referenced object "<<this<<" of type '"<<typeid(this).name()<<"'"<<std::endl;
OSG_WARN<<" the final reference count was "<<_refCount<<", memory corruption possible."<<std::endl;
}
// signal observers that we are being deleted.
signalObserversAndDelete(true, false);
// delete the ObserverSet
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
if (_observerSet.get()) static_cast<ObserverSet*>(_observerSet.get())->unref();
#else
if (_observerSet) static_cast<ObserverSet*>(_observerSet)->unref();
#endif
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
if (_refMutex) delete _refMutex;
#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(this);
newObserverSet->ref();
if (!_observerSet.assign(newObserverSet, 0))
{
newObserverSet->unref();
}
observerSet = static_cast<ObserverSet*>(_observerSet.get());
}
return observerSet;
#else
if (_refMutex)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
if (!_observerSet)
{
_observerSet = new ObserverSet(this);
static_cast<ObserverSet*>(_observerSet)->ref();
}
return static_cast<ObserverSet*>(_observerSet);
}
else
{
if (!_observerSet)
{
_observerSet = new ObserverSet(this);
static_cast<ObserverSet*>(_observerSet)->ref();
}
return static_cast<ObserverSet*>(_observerSet);
}
#endif
}
void Referenced::addObserver(Observer* observer) const
{
getOrCreateObserverSet()->addObserver(observer);
}
void Referenced::removeObserver(Observer* observer) const
{
getOrCreateObserverSet()->removeObserver(observer);
}
void Referenced::signalObserversAndDelete(bool signalDelete, bool doDelete) const
{
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
ObserverSet* observerSet = static_cast<ObserverSet*>(_observerSet.get());
#else
ObserverSet* observerSet = static_cast<ObserverSet*>(_observerSet);
#endif
if (observerSet && signalDelete)
{
observerSet->signalObjectDeleted(const_cast<Referenced*>(this));
}
if (doDelete)
{
if (_refCount!=0)
OSG_NOTICE<<"Warning Referenced::signalObserversAndDelete(,,) doing delete with _refCount="<<_refCount<<std::endl;
if (getDeleteHandler()) deleteUsingDeleteHandler();
else delete this;
}
}
int Referenced::unref_nodelete() const
{
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
return --_refCount;
#else
if (_refMutex)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
return --_refCount;
}
else
{
return --_refCount;
}
#endif
}
void Referenced::deleteUsingDeleteHandler() const
{
getDeleteHandler()->requestDelete(this);
}
} // end of namespace osg