Provide a thread safe SGWeakPtr implementation.
Extend SGAtomic with atomic exchange and add. Import updates from the original implementation of that in OpenFDM. Modified Files: Makefile.am SGAtomic.cxx SGAtomic.hxx SGReferenced.hxx SGSharedPtr.hxx Added Files: SGWeakPtr.hxx SGWeakReferenced.hxx
This commit is contained in:
@@ -17,6 +17,8 @@ include_HEADERS = \
|
||||
SGSharedPtr.hxx \
|
||||
SGSmplhist.hxx \
|
||||
SGSmplstat.hxx \
|
||||
SGWeakPtr.hxx \
|
||||
SGWeakReferenced.hxx \
|
||||
Singleton.hxx
|
||||
|
||||
libsgstructure_a_SOURCES = \
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*-c++-*-
|
||||
*
|
||||
* Copyright (C) 2005-2006 Mathias Froehlich
|
||||
* Copyright (C) 2005-2009 Mathias Froehlich
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
@@ -53,6 +53,18 @@ unsigned __sync_add_and_fetch_4(volatile void *ptr, unsigned value)
|
||||
return result + value;
|
||||
}
|
||||
|
||||
unsigned __sync_bool_compare_and_swap_4(volatile void *ptr,
|
||||
unsigned oldValue, unsigned newValue)
|
||||
{
|
||||
register volatile unsigned* mem = reinterpret_cast<volatile unsigned*>(ptr);
|
||||
unsigned before;
|
||||
__asm__ __volatile__("lock; cmpxchg{l} {%1,%2|%1,%2}"
|
||||
: "=a"(before)
|
||||
: "q"(newValue), "m"(*mem), "0"(oldValue)
|
||||
: "memory");
|
||||
return before == oldValue;
|
||||
}
|
||||
|
||||
void __sync_synchronize()
|
||||
{
|
||||
__asm__ __volatile__("": : : "memory");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*-c++-*-
|
||||
*
|
||||
* Copyright (C) 2005-2006 Mathias Froehlich
|
||||
* Copyright (C) 2005-2009 Mathias Froehlich
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
@@ -81,7 +81,25 @@ public:
|
||||
SGGuard<SGMutex> lock(mMutex);
|
||||
return mValue;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bool compareAndExchange(unsigned oldValue, unsigned newValue)
|
||||
{
|
||||
#if defined(SGATOMIC_USE_GCC4_BUILTINS)
|
||||
return __sync_bool_compare_and_swap(&mValue, oldValue, newValue);
|
||||
#elif defined(SGATOMIC_USE_MIPOSPRO_BUILTINS)
|
||||
return __compare_and_swap(&mValue, oldValue, newValue);
|
||||
#elif defined(SGATOMIC_USE_WIN32_INTERLOCKED)
|
||||
long volatile* lvPtr = reinterpret_cast<long volatile*>(&mValue);
|
||||
return oldValue == InterlockedCompareExchange(lvPtr, newValue, oldValue);
|
||||
#else
|
||||
SGGuard<SGMutex> lock(mMutex);
|
||||
if (mValue != oldValue)
|
||||
return false;
|
||||
mValue = newValue;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
SGAtomic(const SGAtomic&);
|
||||
@@ -91,9 +109,6 @@ private:
|
||||
&& !defined(SGATOMIC_USE_MIPOSPRO_BUILTINS) \
|
||||
&& !defined(SGATOMIC_USE_WIN32_INTERLOCKED)
|
||||
mutable SGMutex mMutex;
|
||||
#endif
|
||||
#ifdef SGATOMIC_USE_WIN32_INTERLOCKED
|
||||
__declspec(align(32))
|
||||
#endif
|
||||
unsigned mValue;
|
||||
};
|
||||
|
||||
@@ -20,13 +20,8 @@
|
||||
|
||||
#ifndef SGReferenced_HXX
|
||||
#define SGReferenced_HXX
|
||||
#define USE_OPENTHREADS_ATOMIC
|
||||
|
||||
#ifndef USE_OPENTHREADS_ATOMIC
|
||||
#include "SGAtomic.hxx"
|
||||
#else
|
||||
#include <OpenThreads/Atomic>
|
||||
#endif
|
||||
|
||||
/// Base class for all reference counted SimGear objects
|
||||
/// Classes derived from this one are meant to be managed with
|
||||
@@ -54,11 +49,7 @@ public:
|
||||
{ if (ref) return 1u < ref->_refcount; else return false; }
|
||||
|
||||
private:
|
||||
#ifndef USE_OPENTHREADS_ATOMIC
|
||||
mutable SGAtomic _refcount;
|
||||
#else
|
||||
mutable OpenThreads::Atomic _refcount;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*-c++-*-
|
||||
*
|
||||
* Copyright (C) 2005-2006 Mathias Froehlich
|
||||
* Copyright (C) 2005-2009 Mathias Froehlich
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
@@ -37,11 +37,14 @@
|
||||
/// to zero and consequently the objects will never be destroyed.
|
||||
/// Always try to use directed graphs where the references away from the
|
||||
/// top node are made with SGSharedPtr's and the back references are done with
|
||||
/// ordinary pointers.
|
||||
/// ordinary pointers or SGWeakPtr's.
|
||||
/// There is a very good description of OpenSceneGraphs ref_ptr which is
|
||||
/// pretty much the same than this one at
|
||||
/// http://dburns.dhs.org/OSG/Articles/RefPointers/RefPointers.html
|
||||
|
||||
template<typename T>
|
||||
class SGWeakPtr;
|
||||
|
||||
template<typename T>
|
||||
class SGSharedPtr {
|
||||
public:
|
||||
@@ -49,19 +52,19 @@ public:
|
||||
{}
|
||||
SGSharedPtr(T* ptr) : _ptr(ptr)
|
||||
{ get(_ptr); }
|
||||
SGSharedPtr(const SGSharedPtr& p) : _ptr(p.ptr())
|
||||
SGSharedPtr(const SGSharedPtr& p) : _ptr(p.get())
|
||||
{ get(_ptr); }
|
||||
template<typename U>
|
||||
SGSharedPtr(const SGSharedPtr<U>& p) : _ptr(p.ptr())
|
||||
SGSharedPtr(const SGSharedPtr<U>& p) : _ptr(p.get())
|
||||
{ get(_ptr); }
|
||||
~SGSharedPtr(void)
|
||||
{ put(); }
|
||||
|
||||
SGSharedPtr& operator=(const SGSharedPtr& p)
|
||||
{ assign(p.ptr()); return *this; }
|
||||
{ assign(p.get()); return *this; }
|
||||
template<typename U>
|
||||
SGSharedPtr& operator=(const SGSharedPtr<U>& p)
|
||||
{ assign(p.ptr()); return *this; }
|
||||
{ assign(p.get()); return *this; }
|
||||
template<typename U>
|
||||
SGSharedPtr& operator=(U* p)
|
||||
{ assign(p); return *this; }
|
||||
@@ -74,26 +77,38 @@ public:
|
||||
{ return _ptr; }
|
||||
T* ptr(void) const
|
||||
{ return _ptr; }
|
||||
T* get(void) const
|
||||
{ return _ptr; }
|
||||
T* release()
|
||||
{ T* tmp = _ptr; _ptr = 0; T::put(tmp); return tmp; }
|
||||
|
||||
bool isShared(void) const
|
||||
{ return SGReferenced::shared(_ptr); }
|
||||
{ return T::shared(_ptr); }
|
||||
unsigned getNumRefs(void) const
|
||||
{ return SGReferenced::count(_ptr); }
|
||||
{ return T::count(_ptr); }
|
||||
|
||||
bool valid(void) const
|
||||
{ return _ptr; }
|
||||
|
||||
void clear()
|
||||
{ put(); }
|
||||
void swap(SGSharedPtr& sharedPtr)
|
||||
{ T* tmp = _ptr; _ptr = sharedPtr._ptr; sharedPtr._ptr = tmp; }
|
||||
|
||||
private:
|
||||
void assign(T* p)
|
||||
{ get(p); put(); _ptr = p; }
|
||||
|
||||
void get(const T* p) const
|
||||
{ SGReferenced::get(p); }
|
||||
{ T::get(p); }
|
||||
void put(void)
|
||||
{ if (!SGReferenced::put(_ptr)) { delete _ptr; _ptr = 0; } }
|
||||
{ if (!T::put(_ptr)) { delete _ptr; _ptr = 0; } }
|
||||
|
||||
// The reference itself.
|
||||
T* _ptr;
|
||||
|
||||
template<typename U>
|
||||
friend class SGWeakPtr;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
75
simgear/structure/SGWeakPtr.hxx
Normal file
75
simgear/structure/SGWeakPtr.hxx
Normal file
@@ -0,0 +1,75 @@
|
||||
// Copyright (C) 2004-2009 Mathias Froehlich - Mathias.Froehlich@web.de
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// 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 GNU
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SGWeakPtr_HXX
|
||||
#define SGWeakPtr_HXX
|
||||
|
||||
#include "SGWeakReferenced.hxx"
|
||||
|
||||
template<typename T>
|
||||
class SGWeakPtr {
|
||||
public:
|
||||
SGWeakPtr(void)
|
||||
{ }
|
||||
SGWeakPtr(const SGWeakPtr& p) : mWeakData(p.mWeakData)
|
||||
{ }
|
||||
template<typename U>
|
||||
SGWeakPtr(const SGSharedPtr<U>& p)
|
||||
{ SGSharedPtr<T> sharedPtr = p; assign(sharedPtr.get()); }
|
||||
template<typename U>
|
||||
SGWeakPtr(const SGWeakPtr<U>& p)
|
||||
{ SGSharedPtr<T> sharedPtr = p.lock(); assign(sharedPtr.get()); }
|
||||
~SGWeakPtr(void)
|
||||
{ }
|
||||
|
||||
template<typename U>
|
||||
SGWeakPtr& operator=(const SGSharedPtr<U>& p)
|
||||
{ SGSharedPtr<T> sharedPtr = p; assign(sharedPtr.get()); return *this; }
|
||||
template<typename U>
|
||||
SGWeakPtr& operator=(const SGWeakPtr<U>& p)
|
||||
{ SGSharedPtr<T> sharedPtr = p.lock(); assign(sharedPtr.get()); return *this; }
|
||||
SGWeakPtr& operator=(const SGWeakPtr& p)
|
||||
{ mWeakData = p.mWeakData; return *this; }
|
||||
|
||||
SGSharedPtr<T> lock(void) const
|
||||
{
|
||||
if (!mWeakData)
|
||||
return SGSharedPtr<T>();
|
||||
SGSharedPtr<T> sharedPtr;
|
||||
sharedPtr.assignNonRef(mWeakData->getPointer<T>());
|
||||
return sharedPtr;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{ mWeakData = 0; }
|
||||
void swap(SGWeakPtr& weakPtr)
|
||||
{ mWeakData.swap(weakPtr.mWeakData); }
|
||||
|
||||
private:
|
||||
void assign(T* p)
|
||||
{
|
||||
if (p)
|
||||
mWeakData = p->mWeakData;
|
||||
else
|
||||
mWeakData = 0;
|
||||
}
|
||||
|
||||
// The indirect reference itself.
|
||||
SGSharedPtr<SGWeakReferenced::WeakData> mWeakData;
|
||||
};
|
||||
|
||||
#endif
|
||||
103
simgear/structure/SGWeakReferenced.hxx
Normal file
103
simgear/structure/SGWeakReferenced.hxx
Normal file
@@ -0,0 +1,103 @@
|
||||
// Copyright (C) 2004-2009 Mathias Froehlich - Mathias.Froehlich@web.de
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// 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 GNU
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SGWeakReferenced_HXX
|
||||
#define SGWeakReferenced_HXX
|
||||
|
||||
#include "SGReferenced.hxx"
|
||||
#include "SGSharedPtr.hxx"
|
||||
|
||||
template<typename T>
|
||||
class SGWeakPtr;
|
||||
|
||||
class SGWeakReferenced {
|
||||
public:
|
||||
/// The object backref and the reference count for this object need to be
|
||||
/// there in any case. Also these are per object and shall not be copied nor
|
||||
/// assigned.
|
||||
/// The reference count for this object is stored in a secondary object that
|
||||
/// is shared with all weak pointers to this current object. This way we
|
||||
/// have an atomic decision using the reference count of this current object
|
||||
/// if the backref is still valid. At the time where the atomic count is
|
||||
/// equal to zero the object is considered dead.
|
||||
SGWeakReferenced(void) :
|
||||
mWeakData(new WeakData(this))
|
||||
{}
|
||||
SGWeakReferenced(const SGWeakReferenced& weakReferenced) :
|
||||
mWeakData(new WeakData(this))
|
||||
{}
|
||||
~SGWeakReferenced(void)
|
||||
{ mWeakData->mWeakReferenced = 0; }
|
||||
|
||||
/// Do not copy the weak backward references ...
|
||||
SGWeakReferenced& operator=(const SGWeakReferenced&)
|
||||
{ return *this; }
|
||||
|
||||
/// The usual operations on weak pointers.
|
||||
/// The interface should stay the same then what we have in Referenced.
|
||||
static unsigned get(const SGWeakReferenced* ref)
|
||||
{ if (ref) return ++(ref->mWeakData->mRefcount); else return 0u; }
|
||||
static unsigned put(const SGWeakReferenced* ref)
|
||||
{ if (ref) return --(ref->mWeakData->mRefcount); else return ~0u; }
|
||||
static unsigned count(const SGWeakReferenced* ref)
|
||||
{ if (ref) return ref->mWeakData->mRefcount; else return 0u; }
|
||||
|
||||
private:
|
||||
/// Support for weak references, not increasing the reference count
|
||||
/// that is done through that small helper class which holds an uncounted
|
||||
/// reference which is zeroed out on destruction of the current object
|
||||
class WeakData : public SGReferenced {
|
||||
public:
|
||||
WeakData(SGWeakReferenced* weakReferenced) :
|
||||
mRefcount(0u),
|
||||
mWeakReferenced(weakReferenced)
|
||||
{ }
|
||||
|
||||
template<typename T>
|
||||
T* getPointer()
|
||||
{
|
||||
// Try to increment the reference count if the count is greater
|
||||
// then zero. Since it should only be incremented iff it is nonzero, we
|
||||
// need to check that value and try to do an atomic test and set. If this
|
||||
// fails, try again. The usual lockless algorithm ...
|
||||
unsigned count;
|
||||
do {
|
||||
count = mRefcount;
|
||||
if (count == 0)
|
||||
return 0;
|
||||
} while (!mRefcount.compareAndExchange(count, count + 1));
|
||||
// We know that as long as the refcount is not zero, the pointer still
|
||||
// points to valid data. So it is safe to work on it.
|
||||
return static_cast<T*>(mWeakReferenced);
|
||||
}
|
||||
|
||||
SGAtomic mRefcount;
|
||||
SGWeakReferenced* mWeakReferenced;
|
||||
|
||||
private:
|
||||
WeakData(void);
|
||||
WeakData(const WeakData&);
|
||||
WeakData& operator=(const WeakData&);
|
||||
};
|
||||
|
||||
SGSharedPtr<WeakData> mWeakData;
|
||||
|
||||
template<typename T>
|
||||
friend class SGWeakPtr;
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user