From: Thomas Geymayer Date: Sun, 15 Jun 2014 14:31:40 +0000 (+0200) Subject: cppbind: queue Ghosts for deletion and delete outside gc. X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=5024b62c0a86b2b4d830c1b9aa3781c795507752;p=simgear.git cppbind: queue Ghosts for deletion and delete outside gc. --- diff --git a/simgear/nasal/cppbind/CMakeLists.txt b/simgear/nasal/cppbind/CMakeLists.txt index 952411d7..8e8057f8 100644 --- a/simgear/nasal/cppbind/CMakeLists.txt +++ b/simgear/nasal/cppbind/CMakeLists.txt @@ -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 index 00000000..dcfb55af --- /dev/null +++ b/simgear/nasal/cppbind/Ghost.cxx @@ -0,0 +1,108 @@ +// Expose C++ objects to Nasal as ghosts +// +// Copyright (C) 2014 Thomas Geymayer +// +// 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 + diff --git a/simgear/nasal/cppbind/Ghost.hxx b/simgear/nasal/cppbind/Ghost.hxx index 25a0d875..b7d1d849 100644 --- a/simgear/nasal/cppbind/Ghost.hxx +++ b/simgear/nasal/cppbind/Ghost.hxx @@ -83,40 +83,18 @@ namespace nasal class GhostMetadata { public: + typedef void(*Deleter)(void*); + typedef std::vector > 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 MethodHolderPtr; typedef SGWeakPtr MethodHolderWeakPtr; @@ -1171,7 +1136,7 @@ namespace nasal supports_weak_ref::value ? &_ghost_type_weak : NULL ) { _ghost_type_strong.destroy = - SG_GET_TEMPLATE_MEMBER(Ghost, destroy); + SG_GET_TEMPLATE_MEMBER(Ghost, queueDestroy); _ghost_type_strong.name = _name_strong.c_str(); _ghost_type_strong.get_member = SG_GET_TEMPLATE_MEMBER(Ghost, getMember); @@ -1179,7 +1144,7 @@ namespace nasal SG_GET_TEMPLATE_MEMBER(Ghost, setMember); _ghost_type_weak.destroy = - SG_GET_TEMPLATE_MEMBER(Ghost, destroy); + SG_GET_TEMPLATE_MEMBER(Ghost, queueDestroy); _ghost_type_weak.name = _name_weak.c_str(); if( supports_weak_ref::value ) @@ -1208,6 +1173,12 @@ namespace nasal delete static_cast(ptr); } + template + static void queueDestroy(void *ptr) + { + _destroy_list.push_back( DestroyList::value_type(&destroy, ptr) ); + } + /** * Callback for retrieving a ghost member. */ diff --git a/simgear/nasal/cppbind/cppbind_test_ghost.cxx b/simgear/nasal/cppbind/cppbind_test_ghost.cxx index 2394dfe0..569e8e7a 100644 --- a/simgear/nasal/cppbind/cppbind_test_ghost.cxx +++ b/simgear/nasal/cppbind/cppbind_test_ghost.cxx @@ -83,6 +83,7 @@ BOOST_AUTO_TEST_CASE( ghost_weak_strong_nasal_conversion ) naFreeContext(c); naGC(); + nasal::ghostProcessDestroyList(); BOOST_REQUIRE( !weak.lock() ); }