1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version. The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * OpenSceneGraph Public License for more details.
15#define OSG_REFERENCED 1
19#include <OpenThreads/ScopedLock>
20#include <OpenThreads/Mutex>
21#include <OpenThreads/Atomic>
23#if !defined(_OPENTHREADS_ATOMIC_USE_MUTEX)
24# define _OSG_REFERENCED_USE_ATOMIC_OPERATIONS
29// forward declare, declared after Referenced below.
35/** template class to help enforce static initialization order. */
36template <typename T, T M()>
42/** Base class for providing reference counted objects.*/
43class OSG_EXPORT Referenced
51 /** Deprecated, Referenced is now always uses thread safe ref/unref, use default Referenced() constructor instead */
52 explicit Referenced(bool threadSafeRefUnref);
54 Referenced(const Referenced&);
56 inline Referenced& operator = (const Referenced&) { return *this; }
58 /** Deprecated, Referenced is always theadsafe so there method now has no effect and does not need to be called.*/
59 virtual void setThreadSafeRefUnref(bool /*threadSafe*/) {}
61 /** Get whether a mutex is used to ensure ref() and unref() are thread safe.*/
62#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
63 bool getThreadSafeRefUnref() const { return true; }
65 bool getThreadSafeRefUnref() const { return _refMutex!=0; }
68 /** Get the mutex used to ensure thread safety of ref()/unref(). */
69#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
70 OpenThreads::Mutex* getRefMutex() const { return getGlobalReferencedMutex(); }
72 OpenThreads::Mutex* getRefMutex() const { return _refMutex; }
75 /** Get the optional global Referenced mutex, this can be shared between all osg::Referenced.*/
76 static OpenThreads::Mutex* getGlobalReferencedMutex();
78 /** Increment the reference count by one, indicating that
79 this object has another pointer which is referencing it.*/
80 inline int ref() const;
82 /** Decrement the reference count by one, indicating that
83 a pointer to this object is no longer referencing it. If the
84 reference count goes to zero, it is assumed that this object
85 is no longer referenced and is automatically deleted.*/
86 inline int unref() const;
88 /** Decrement the reference count by one, indicating that
89 a pointer to this object is no longer referencing it. However, do
90 not delete it, even if ref count goes to 0. Warning, unref_nodelete()
91 should only be called if the user knows exactly who will
92 be responsible for, one should prefer unref() over unref_nodelete()
93 as the latter can lead to memory leaks.*/
94 int unref_nodelete() const;
96 /** Return the number of pointers currently referencing this object. */
97 inline int referenceCount() const { return _refCount; }
100 /** Get the ObserverSet if one is attached, otherwise return NULL.*/
101 ObserverSet* getObserverSet() const
103 #if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
104 return static_cast<ObserverSet*>(_observerSet.get());
106 return static_cast<ObserverSet*>(_observerSet);
110 /** Get the ObserverSet if one is attached, otherwise create an ObserverSet, attach it, then return this newly created ObserverSet.*/
111 ObserverSet* getOrCreateObserverSet() const;
113 /** Add a Observer that is observing this object, notify the Observer when this object gets deleted.*/
114 void addObserver(Observer* observer) const;
116 /** Remove Observer that is observing this object.*/
117 void removeObserver(Observer* observer) const;
119 /** Resize any per context GLObject buffers to specified size. */
120 virtual void resizeGLObjectBuffers(unsigned int /*maxSize*/) {}
122 /** If State is non-zero, this function releases any associated OpenGL objects for
123 * the specified graphics context. Otherwise, releases OpenGL objects
124 * for all graphics contexts. */
125 virtual void releaseGLObjects(osg::State* = 0) const {}
129 friend class DeleteHandler;
131 /** Set a DeleteHandler to which deletion of all referenced counted objects
132 * will be delegated.*/
133 static void setDeleteHandler(DeleteHandler* handler);
135 /** Get a DeleteHandler.*/
136 static DeleteHandler* getDeleteHandler();
141 virtual ~Referenced();
143 void signalObserversAndDelete(bool signalDelete, bool doDelete) const;
145 void deleteUsingDeleteHandler() const;
147#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
148 mutable OpenThreads::AtomicPtr _observerSet;
150 mutable OpenThreads::Atomic _refCount;
153 mutable OpenThreads::Mutex* _refMutex;
155 mutable int _refCount;
157 mutable void* _observerSet;
161inline int Referenced::ref() const
163#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
168 OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
178inline int Referenced::unref() const
181#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
182 newRef = --_refCount;
183 bool needDelete = (newRef == 0);
185 bool needDelete = false;
188 OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
189 newRef = --_refCount;
190 needDelete = newRef==0;
194 newRef = --_refCount;
195 needDelete = newRef==0;
201 signalObserversAndDelete(true,true);
206// intrusive_ptr_add_ref and intrusive_ptr_release allow
207// use of osg Referenced classes with boost::intrusive_ptr
208inline void intrusive_ptr_add_ref(Referenced* p) { p->ref(); }
209inline void intrusive_ptr_release(Referenced* p) { p->unref(); }