/* -*-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 // When building OSG with Java need to derive from Noodle::CBridgable class, #include #include #include #include #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; /** template class to help enforce static initialization order. */ template struct depends_on { depends_on() { M(); } }; /** Base class from providing referencing counted objects.*/ class OSG_EXPORT Referenced { public: Referenced(); explicit Referenced(bool threadSafeRefUnref); Referenced(const Referenced&); inline Referenced& operator = (const Referenced&) { return *this; } /** Set whether to use a mutex to ensure ref() and unref() are thread safe.*/ 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 void ref() const; /** Decrement the reference count by one, indicating that a pointer to this object is referencing it. If the reference count goes to zero, it is assumed that this object is no longer referenced and is automatically deleted.*/ inline void unref() const; /** Decrement the reference count by one, indicating that a pointer to this object is 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 later can lead to memory leaks.*/ void unref_nodelete() const; /** Return the number pointers currently referencing this object. */ 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; /** Add a Observer that is observing this object, notify the Observer when this object gets deleted.*/ void removeObserver(Observer* observer) const; public: /** Set whether reference counting should be use a mutex to create thread reference counting.*/ static void setThreadSafeReferenceCounting(bool enableThreadSafeReferenceCounting); /** Get whether reference counting is active.*/ static bool getThreadSafeReferenceCounting(); friend class DeleteHandler; /** Set a DeleteHandler to which deletion of all referenced counted objects * will be delegated to.*/ static void setDeleteHandler(DeleteHandler* handler); /** Get a DeleteHandler.*/ static DeleteHandler* getDeleteHandler(); protected: virtual ~Referenced(); void deleteUsingDeleteHandler() const; #if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS) struct ObserverSetData; mutable OpenThreads::AtomicPtr _observerSetDataPtr; mutable OpenThreads::Atomic _refCount; #else mutable OpenThreads::Mutex* _refMutex; mutable int _refCount; mutable void* _observers; #endif }; inline void Referenced::ref() const { #if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS) ++_refCount; #else if (_refMutex) { OpenThreads::ScopedLock lock(*_refMutex); ++_refCount; } else { ++_refCount; } #endif } inline void Referenced::unref() const { #if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS) bool needDelete = (--_refCount == 0); #else bool needDelete = false; if (_refMutex) { OpenThreads::ScopedLock lock(*_refMutex); --_refCount; needDelete = _refCount<=0; } else { --_refCount; needDelete = _refCount<=0; } #endif if (needDelete) { if (getDeleteHandler()) deleteUsingDeleteHandler(); else delete this; } } // 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