--- /dev/null
+// 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
+
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:
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);
};
/**
{};
}
+ /** @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;
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>);
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 )
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.
*/