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
SGSharedPtr.hxx \
SGSmplhist.hxx \
SGSmplstat.hxx \
+ SGWeakPtr.hxx \
+ SGWeakReferenced.hxx \
Singleton.hxx
libsgstructure_a_SOURCES = \
/* -*-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
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");
/* -*-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
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&);
&& !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;
};
#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
{ if (ref) return 1u < ref->_refcount; else return false; }
private:
-#ifndef USE_OPENTHREADS_ATOMIC
mutable SGAtomic _refcount;
-#else
- mutable OpenThreads::Atomic _refcount;
-#endif
};
#endif
/* -*-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
/// 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:
{}
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; }
{ 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
--- /dev/null
+// 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
--- /dev/null
+// 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