cppbind: queue Ghosts for deletion and delete outside gc.
This commit is contained in:
@@ -20,6 +20,7 @@ set(DETAIL_HEADERS
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
Ghost.cxx
|
||||
NasalHash.cxx
|
||||
NasalString.cxx
|
||||
NasalObject.cxx
|
||||
|
||||
108
simgear/nasal/cppbind/Ghost.cxx
Normal file
108
simgear/nasal/cppbind/Ghost.cxx
Normal 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
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -83,6 +83,7 @@ BOOST_AUTO_TEST_CASE( ghost_weak_strong_nasal_conversion )
|
||||
|
||||
naFreeContext(c);
|
||||
naGC();
|
||||
nasal::ghostProcessDestroyList();
|
||||
|
||||
BOOST_REQUIRE( !weak.lock() );
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user