1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
|
/* -*-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 <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;
/** template class to help enforce static initialization order. */
template <typename T, T M()>
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<OpenThreads::Mutex> 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<OpenThreads::Mutex> 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
|