]> git.mxchange.org Git - simgear.git/commitdiff
cppbind: queue Ghosts for deletion and delete outside gc.
authorThomas Geymayer <tomgey@gmail.com>
Sun, 15 Jun 2014 14:31:40 +0000 (16:31 +0200)
committerThomas Geymayer <tomgey@gmail.com>
Sun, 15 Jun 2014 14:34:47 +0000 (16:34 +0200)
simgear/nasal/cppbind/CMakeLists.txt
simgear/nasal/cppbind/Ghost.cxx [new file with mode: 0644]
simgear/nasal/cppbind/Ghost.hxx
simgear/nasal/cppbind/cppbind_test_ghost.cxx

index 952411d728dc987f1424a841470781ba200fb9de..8e8057f82002cf9b0f97c50130b9b656a538e0c1 100644 (file)
@@ -20,6 +20,7 @@ set(DETAIL_HEADERS
 )
 
 set(SOURCES
+  Ghost.cxx
   NasalHash.cxx
   NasalString.cxx
   NasalObject.cxx
diff --git a/simgear/nasal/cppbind/Ghost.cxx b/simgear/nasal/cppbind/Ghost.cxx
new file mode 100644 (file)
index 0000000..dcfb55a
--- /dev/null
@@ -0,0 +1,108 @@
+// Expose C++ objects to Nasal as ghosts
+//
+// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
+//
+// 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 Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
+
+#include "Ghost.hxx"
+
+namespace nasal
+{
+  namespace internal
+  {
+    //--------------------------------------------------------------------------
+    GhostMetadata::DestroyList GhostMetadata::_destroy_list;
+
+    //--------------------------------------------------------------------------
+    void GhostMetadata::addNasalBase(const naRef& parent)
+    {
+      assert( naIsHash(parent) );
+      _parents.push_back(parent);
+    }
+
+    //--------------------------------------------------------------------------
+    bool GhostMetadata::isBaseOf(naGhostType* ghost_type, bool& is_weak) const
+    {
+      if( ghost_type == _ghost_type_strong_ptr )
+      {
+        is_weak = false;
+        return true;
+      }
+
+      if( ghost_type == _ghost_type_weak_ptr )
+      {
+        is_weak = true;
+        return true;
+      }
+
+      for( DerivedList::const_iterator derived = _derived_classes.begin();
+                                       derived != _derived_classes.end();
+                                     ++derived )
+      {
+        if( (*derived)->isBaseOf(ghost_type, is_weak) )
+          return true;
+      }
+
+      return false;
+    }
+
+    //--------------------------------------------------------------------------
+    GhostMetadata::GhostMetadata( const std::string& name,
+                                  const naGhostType* ghost_type_strong,
+                                  const naGhostType* ghost_type_weak ):
+      _name_strong(name),
+      _name_weak(name + " (weak ref)"),
+      _ghost_type_strong_ptr(ghost_type_strong),
+      _ghost_type_weak_ptr(ghost_type_weak)
+    {
+
+    }
+
+    //--------------------------------------------------------------------------
+    void GhostMetadata::addDerived(const GhostMetadata* derived)
+    {
+      assert(derived);
+      _derived_classes.push_back(derived);
+
+      SG_LOG
+      (
+        SG_NASAL,
+        SG_INFO,
+        "Ghost::addDerived: " << _name_strong << " -> "
+                              << derived->_name_strong
+      );
+    }
+
+    //--------------------------------------------------------------------------
+    naRef GhostMetadata::getParents(naContext c)
+    {
+      return nasal::to_nasal(c, _parents);
+    }
+  } // namespace internal
+
+  //----------------------------------------------------------------------------
+  void ghostProcessDestroyList()
+  {
+    using internal::GhostMetadata;
+    typedef GhostMetadata::DestroyList::const_iterator destroy_iterator;
+    for( destroy_iterator it = GhostMetadata::_destroy_list.begin();
+                          it != GhostMetadata::_destroy_list.end();
+                        ++it )
+      it->first(it->second);
+    GhostMetadata::_destroy_list.clear();
+  }
+
+} // namespace nasal
+
index 25a0d875f2a107a7bd83d5c5162afa3e8681788a..b7d1d84993b8a0e25f61f2b013a0bf26afaf1287 100644 (file)
@@ -83,40 +83,18 @@ namespace nasal
     class GhostMetadata
     {
       public:
+        typedef void(*Deleter)(void*);
+        typedef std::vector<std::pair<Deleter, void*> > DestroyList;
+
+        static DestroyList _destroy_list;
+
         /**
          * Add a nasal base class to the ghost. Will be available in the ghosts
          * parents array.
          */
-        void addNasalBase(const naRef& parent)
-        {
-          assert( naIsHash(parent) );
-          _parents.push_back(parent);
-        }
-
-        bool isBaseOf(naGhostType* ghost_type, bool& is_weak) const
-        {
-          if( ghost_type == _ghost_type_strong_ptr )
-          {
-            is_weak = false;
-            return true;
-          }
-
-          if( ghost_type == _ghost_type_weak_ptr )
-          {
-            is_weak = true;
-            return true;
-          }
+        void addNasalBase(const naRef& parent);
 
-          for( DerivedList::const_iterator derived = _derived_classes.begin();
-                                           derived != _derived_classes.end();
-                                         ++derived )
-          {
-            if( (*derived)->isBaseOf(ghost_type, is_weak) )
-              return true;
-          }
-
-          return false;
-        }
+        bool isBaseOf(naGhostType* ghost_type, bool& is_weak) const;
 
       protected:
 
@@ -131,33 +109,11 @@ namespace nasal
 
         GhostMetadata( const std::string& name,
                        const naGhostType* ghost_type_strong,
-                       const naGhostType* ghost_type_weak ):
-          _name_strong(name),
-          _name_weak(name + " (weak ref)"),
-          _ghost_type_strong_ptr(ghost_type_strong),
-          _ghost_type_weak_ptr(ghost_type_weak)
-        {
-
-        }
-
-        void addDerived(const GhostMetadata* derived)
-        {
-          assert(derived);
-          _derived_classes.push_back(derived);
+                       const naGhostType* ghost_type_weak );
 
-          SG_LOG
-          (
-            SG_NASAL,
-            SG_INFO,
-            "Ghost::addDerived: " << _name_strong << " -> "
-                                  << derived->_name_strong
-          );
-        }
+        void addDerived(const GhostMetadata* derived);
 
-        naRef getParents(naContext c)
-        {
-          return nasal::to_nasal(c, _parents);
-        }
+        naRef getParents(naContext c);
     };
 
     /**
@@ -198,6 +154,15 @@ namespace nasal
     {};
   }
 
+  /** @brief Destroy all ghost queued for deletion.
+   *
+   * This needs can not be done directly during garbage collection, as
+   * destructors may execute Nasal code which requires creating new Nasal
+   * contexts. Creating a Nasal context during garbage collection is not
+   * possible and leads to a dead lock.
+   */
+  void ghostProcessDestroyList();
+
   typedef SGSharedPtr<internal::MethodHolder> MethodHolderPtr;
   typedef SGWeakPtr<internal::MethodHolder> MethodHolderWeakPtr;
 
@@ -1171,7 +1136,7 @@ namespace nasal
                        supports_weak_ref<T>::value ? &_ghost_type_weak : NULL )
       {
         _ghost_type_strong.destroy =
-          SG_GET_TEMPLATE_MEMBER(Ghost, destroy<strong_ref>);
+          SG_GET_TEMPLATE_MEMBER(Ghost, queueDestroy<strong_ref>);
         _ghost_type_strong.name = _name_strong.c_str();
         _ghost_type_strong.get_member =
           SG_GET_TEMPLATE_MEMBER(Ghost, getMember<false>);
@@ -1179,7 +1144,7 @@ namespace nasal
           SG_GET_TEMPLATE_MEMBER(Ghost, setMember<false>);
 
         _ghost_type_weak.destroy =
-          SG_GET_TEMPLATE_MEMBER(Ghost, destroy<weak_ref>);
+          SG_GET_TEMPLATE_MEMBER(Ghost, queueDestroy<weak_ref>);
         _ghost_type_weak.name = _name_weak.c_str();
 
         if( supports_weak_ref<T>::value )
@@ -1208,6 +1173,12 @@ namespace nasal
         delete static_cast<Type*>(ptr);
       }
 
+      template<class Type>
+      static void queueDestroy(void *ptr)
+      {
+        _destroy_list.push_back( DestroyList::value_type(&destroy<Type>, ptr) );
+      }
+
       /**
        * Callback for retrieving a ghost member.
        */
index 2394dfe0e423e760dac28b5b813089f781f1246c..569e8e7adfaa9439f4dea19e8af26f897c210511 100644 (file)
@@ -83,6 +83,7 @@ BOOST_AUTO_TEST_CASE( ghost_weak_strong_nasal_conversion )
 
   naFreeContext(c);
   naGC();
+  nasal::ghostProcessDestroyList();
 
   BOOST_REQUIRE( !weak.lock() );
 }