123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- /* -*-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.
- */
- #ifndef OSG_REFERENCED
- #define OSG_REFERENCED 1
- #include <osg/Export>
- #include <OpenThreads/ScopedLock>
- #include <OpenThreads/Mutex>
- #include <OpenThreads/Atomic>
- #if !defined(_OPENTHREADS_ATOMIC_USE_MUTEX)
- # define _OSG_REFERENCED_USE_ATOMIC_OPERATIONS
- #endif
- namespace osg {
- // forward declare, declared after Referenced below.
- class DeleteHandler;
- class Observer;
- class ObserverSet;
- class State;
- /** template class to help enforce static initialization order. */
- template <typename T, T M()>
- struct depends_on
- {
- depends_on() { M(); }
- };
- /** Base class for providing reference counted objects.*/
- class OSG_EXPORT Referenced
- {
- public:
- Referenced();
- /** Deprecated, Referenced is now always uses thread safe ref/unref, use default Referenced() constructor instead */
- explicit Referenced(bool threadSafeRefUnref);
- Referenced(const Referenced&);
- inline Referenced& operator = (const Referenced&) { return *this; }
- /** Deprecated, Referenced is always theadsafe so there method now has no effect and does not need to be called.*/
- virtual void setThreadSafeRefUnref(bool /*threadSafe*/) {}
- /** Get whether a mutex is used to ensure ref() and unref() are thread safe.*/
- #if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
- bool getThreadSafeRefUnref() const { return true; }
- #else
- bool getThreadSafeRefUnref() const { return _refMutex!=0; }
- #endif
- /** Get the mutex used to ensure thread safety of ref()/unref(). */
- #if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
- OpenThreads::Mutex* getRefMutex() const { return getGlobalReferencedMutex(); }
- #else
- OpenThreads::Mutex* getRefMutex() const { return _refMutex; }
- #endif
- /** Get the optional global Referenced mutex, this can be shared between all osg::Referenced.*/
- static OpenThreads::Mutex* getGlobalReferencedMutex();
- /** Increment the reference count by one, indicating that
- this object has another pointer which is referencing it.*/
- inline int ref() const;
- /** Decrement the reference count by one, indicating that
- a pointer to this object is no longer referencing it. If the
- reference count goes to zero, it is assumed that this object
- is no longer referenced and is automatically deleted.*/
- inline int unref() const;
- /** Decrement the reference count by one, indicating that
- a pointer to this object is no longer referencing it. However, do
- not delete it, even if ref count goes to 0. Warning, unref_nodelete()
- should only be called if the user knows exactly who will
- be responsible for, one should prefer unref() over unref_nodelete()
- as the latter can lead to memory leaks.*/
- int unref_nodelete() const;
- /** Return the number of pointers currently referencing this object. */
- inline int referenceCount() const { return _refCount; }
- /** 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.*/
- void addObserver(Observer* observer) const;
- /** Remove Observer that is observing this object.*/
- void removeObserver(Observer* observer) const;
- #if 0
- /** Resize any per context GLObject buffers to specified size. */
- virtual void resizeGLObjectBuffers(unsigned int /*maxSize*/) {}
- /** If State is non-zero, this function releases any associated OpenGL objects for
- * the specified graphics context. Otherwise, releases OpenGL objects
- * for all graphics contexts. */
- virtual void releaseGLObjects(osg::State* = 0) const {}
- #endif
- public:
- friend class DeleteHandler;
- /** Set a DeleteHandler to which deletion of all referenced counted objects
- * will be delegated.*/
- static void setDeleteHandler(DeleteHandler* handler);
- /** Get a DeleteHandler.*/
- static DeleteHandler* getDeleteHandler();
- protected:
- virtual ~Referenced();
- void signalObserversAndDelete(bool signalDelete, bool doDelete) const;
- void deleteUsingDeleteHandler() const;
- #if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
- mutable OpenThreads::AtomicPtr _observerSet;
- mutable OpenThreads::Atomic _refCount;
- #else
- mutable OpenThreads::Mutex* _refMutex;
- mutable int _refCount;
- mutable void* _observerSet;
- #endif
- };
- inline int Referenced::ref() 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
- }
- inline int Referenced::unref() const
- {
- int newRef;
- #if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
- newRef = --_refCount;
- bool needDelete = (newRef == 0);
- #else
- bool needDelete = false;
- if (_refMutex)
- {
- OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
- newRef = --_refCount;
- needDelete = newRef==0;
- }
- else
- {
- newRef = --_refCount;
- needDelete = newRef==0;
- }
- #endif
- if (needDelete)
- {
- signalObserversAndDelete(true,true);
- }
- return newRef;
- }
- // intrusive_ptr_add_ref and intrusive_ptr_release allow
- // use of osg Referenced classes with boost::intrusive_ptr
- inline void intrusive_ptr_add_ref(Referenced* p) { p->ref(); }
- inline void intrusive_ptr_release(Referenced* p) { p->unref(); }
- }
- #endif
|