OpenSceneGraph/include/osg/Referenced
Robert Osfield 5a4ce5a387 From Mathias Froechlich, "Attached is a change to that atomic stuff to move the win32, msvc
implementation of the atomic increment and decrement into a implementation
file.
This way inlining and compiler optimization can no longer happen for these
implementations, but it fixes compilation on win32 msvc targets. I expect
that this is still faster than with with mutexes.

Also the i386 gcc target gets atomic operations with this patch. By using an
implementation file we can guarantee that we have the right compiler flags
available."
2008-06-26 10:27:16 +00:00

222 lines
6.7 KiB
C++

/* -*-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,
// therefore so OSG_JAVA_BUILD must be defined. Also the thread-safe ref/unref test
// as built in for the NoodleGlue wrapping. NoodleGlue has a Garbage collector mechanism
// which is very similar to osg::DeletionManager. So these aspects of osg::Referenced
// have been removed
//#define OSG_JAVA_BUILD
#include <osg/Export>
#ifdef OSG_JAVA_BUILD
#include <NoodleGlue/Bridgable.h>
#else
#include <OpenThreads/ScopedLock>
#include <OpenThreads/Mutex>
#endif
#include <OpenThreads/Atomic>
#if !defined(_OPENTHREADS_ATOMIC_USE_MUTEX)
# define _OSG_REFERENCED_USE_ATOMIC_OPERATIONS
#endif
namespace osg {
#ifndef OSG_JAVA_BUILD
// forward declare, declared after Referenced below.
class DeleteHandler;
class Observer;
/** 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 0; }
#else
OpenThreads::Mutex* getRefMutex() const { return _refMutex; }
#endif
/** 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);
/** Add a Observer that is observing this object, notify the Observer when this object gets deleted.*/
void removeObserver(Observer* observer);
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;
OpenThreads::AtomicPtr _observerSetDataPtr;
mutable OpenThreads::Atomic _refCount;
#else
mutable OpenThreads::Mutex* _refMutex;
mutable int _refCount;
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;
}
}
#else
/** Java wrappers use the CBridgable base-class for referencing
* and garbage collection.
*/
class OSG_EXPORT Referenced : public NoodleGlue::CBridgable
{
public:
/** Method not used in NoodleGlue referencing
*/
inline void unref_nodelete() const { --_refCount; }
inline int referenceCount() const { return _refCount; }
/* These methods are not used in JavaOSG */
void addObserver(Observer* observer) {}
void removeObserver(Observer* observer) {}
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() { return true; }
protected:
virtual ~Referenced() {}
};
#endif //OSG_JAVA_BUILD
}
#endif