]> git.mxchange.org Git - simgear.git/commitdiff
Provide a thread safe SGWeakPtr implementation.
authorfrohlich <frohlich>
Wed, 24 Jun 2009 05:19:52 +0000 (05:19 +0000)
committerTim Moore <timoore@redhat.com>
Thu, 25 Jun 2009 08:13:03 +0000 (10:13 +0200)
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

simgear/structure/Makefile.am
simgear/structure/SGAtomic.cxx
simgear/structure/SGAtomic.hxx
simgear/structure/SGReferenced.hxx
simgear/structure/SGSharedPtr.hxx
simgear/structure/SGWeakPtr.hxx [new file with mode: 0644]
simgear/structure/SGWeakReferenced.hxx [new file with mode: 0644]

index d0009177bbfc212b737a0fbcba7ee0aa550c1fa1..0f54669b2dae6cc1283f0c9404f5a411fd73b86e 100644 (file)
@@ -17,6 +17,8 @@ include_HEADERS = \
        SGSharedPtr.hxx \
        SGSmplhist.hxx \
        SGSmplstat.hxx \
+       SGWeakPtr.hxx \
+       SGWeakReferenced.hxx \
        Singleton.hxx
 
 libsgstructure_a_SOURCES = \
index 9eabf4ec816719557daa2c42ae9830e3f4845a95..ee219d84c086d7754ce7f18bbe60dbb25b84c8ad 100644 (file)
@@ -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");
index 4029f3527fb91938f0871ee8670e454118faf93e..1ff9a44d05213f08c4cfd3ab7337c99e86d6ee7a 100644 (file)
@@ -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;
 };
index 6bce1eb82bd83da9e4fce1d88e37c414340baf91..6a3038f3576494619e6590144ce3d638d547be31 100644 (file)
 
 #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
index d0f899bd6682945396e8e1b01cc038c05e8b5607..b99a6a8f7f95bd64f993de5be65be825e0e1ba50 100644 (file)
@@ -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
 /// 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
diff --git a/simgear/structure/SGWeakPtr.hxx b/simgear/structure/SGWeakPtr.hxx
new file mode 100644 (file)
index 0000000..c84ae37
--- /dev/null
@@ -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
diff --git a/simgear/structure/SGWeakReferenced.hxx b/simgear/structure/SGWeakReferenced.hxx
new file mode 100644 (file)
index 0000000..8108300
--- /dev/null
@@ -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