openscenegraph
Referenced
Go to the documentation of this file.
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
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.
7 *
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.
12*/
13
14#ifndef OSG_REFERENCED
15#define OSG_REFERENCED 1
16
17#include <osg/Export>
18
19#include <OpenThreads/ScopedLock>
20#include <OpenThreads/Mutex>
21#include <OpenThreads/Atomic>
22
23#if !defined(_OPENTHREADS_ATOMIC_USE_MUTEX)
24# define _OSG_REFERENCED_USE_ATOMIC_OPERATIONS
25#endif
26
27namespace osg {
28
29// forward declare, declared after Referenced below.
30class DeleteHandler;
31class Observer;
32class ObserverSet;
33class State;
34
35/** template class to help enforce static initialization order. */
36template <typename T, T M()>
37struct depends_on
38{
39 depends_on() { M(); }
40};
41
42/** Base class for providing reference counted objects.*/
43class OSG_EXPORT Referenced
44{
45
46 public:
47
48
49 Referenced();
50
51 /** Deprecated, Referenced is now always uses thread safe ref/unref, use default Referenced() constructor instead */
52 explicit Referenced(bool threadSafeRefUnref);
53
54 Referenced(const Referenced&);
55
56 inline Referenced& operator = (const Referenced&) { return *this; }
57
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*/) {}
60
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; }
64#else
65 bool getThreadSafeRefUnref() const { return _refMutex!=0; }
66#endif
67
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(); }
71#else
72 OpenThreads::Mutex* getRefMutex() const { return _refMutex; }
73#endif
74
75 /** Get the optional global Referenced mutex, this can be shared between all osg::Referenced.*/
76 static OpenThreads::Mutex* getGlobalReferencedMutex();
77
78 /** Increment the reference count by one, indicating that
79 this object has another pointer which is referencing it.*/
80 inline int ref() const;
81
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;
87
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;
95
96 /** Return the number of pointers currently referencing this object. */
97 inline int referenceCount() const { return _refCount; }
98
99
100 /** Get the ObserverSet if one is attached, otherwise return NULL.*/
101 ObserverSet* getObserverSet() const
102 {
103 #if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
104 return static_cast<ObserverSet*>(_observerSet.get());
105 #else
106 return static_cast<ObserverSet*>(_observerSet);
107 #endif
108 }
109
110 /** Get the ObserverSet if one is attached, otherwise create an ObserverSet, attach it, then return this newly created ObserverSet.*/
111 ObserverSet* getOrCreateObserverSet() const;
112
113 /** Add a Observer that is observing this object, notify the Observer when this object gets deleted.*/
114 void addObserver(Observer* observer) const;
115
116 /** Remove Observer that is observing this object.*/
117 void removeObserver(Observer* observer) const;
118#if 0
119 /** Resize any per context GLObject buffers to specified size. */
120 virtual void resizeGLObjectBuffers(unsigned int /*maxSize*/) {}
121
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 {}
126#endif
127public:
128
129 friend class DeleteHandler;
130
131 /** Set a DeleteHandler to which deletion of all referenced counted objects
132 * will be delegated.*/
133 static void setDeleteHandler(DeleteHandler* handler);
134
135 /** Get a DeleteHandler.*/
136 static DeleteHandler* getDeleteHandler();
137
138
139 protected:
140
141 virtual ~Referenced();
142
143 void signalObserversAndDelete(bool signalDelete, bool doDelete) const;
144
145 void deleteUsingDeleteHandler() const;
146
147#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
148 mutable OpenThreads::AtomicPtr _observerSet;
149
150 mutable OpenThreads::Atomic _refCount;
151#else
152
153 mutable OpenThreads::Mutex* _refMutex;
154
155 mutable int _refCount;
156
157 mutable void* _observerSet;
158#endif
159};
160
161inline int Referenced::ref() const
162{
163#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
164 return ++_refCount;
165#else
166 if (_refMutex)
167 {
168 OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
169 return ++_refCount;
170 }
171 else
172 {
173 return ++_refCount;
174 }
175#endif
176}
177
178inline int Referenced::unref() const
179{
180 int newRef;
181#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
182 newRef = --_refCount;
183 bool needDelete = (newRef == 0);
184#else
185 bool needDelete = false;
186 if (_refMutex)
187 {
188 OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
189 newRef = --_refCount;
190 needDelete = newRef==0;
191 }
192 else
193 {
194 newRef = --_refCount;
195 needDelete = newRef==0;
196 }
197#endif
198
199 if (needDelete)
200 {
201 signalObserversAndDelete(true,true);
202 }
203 return newRef;
204}
205
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(); }
210
211}
212
213#endif