cppbind: queue Ghosts for deletion and delete outside gc.

This commit is contained in:
Thomas Geymayer
2014-06-15 16:31:40 +02:00
parent 82d5c605e5
commit 5024b62c0a
4 changed files with 137 additions and 56 deletions

View File

@@ -20,6 +20,7 @@ set(DETAIL_HEADERS
)
set(SOURCES
Ghost.cxx
NasalHash.cxx
NasalString.cxx
NasalObject.cxx

View File

@@ -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

View 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);
}
void addNasalBase(const naRef& 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;
}
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)
{
const naGhostType* ghost_type_weak );
}
void addDerived(const GhostMetadata* derived);
void 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 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.
*/

View File

@@ -83,6 +83,7 @@ BOOST_AUTO_TEST_CASE( ghost_weak_strong_nasal_conversion )
naFreeContext(c);
naGC();
nasal::ghostProcessDestroyList();
BOOST_REQUIRE( !weak.lock() );
}