add ObjectDeletor; avoid unnecessary locks on RenderState

This commit is contained in:
David Rose 2006-04-10 21:19:48 +00:00
parent a5cb0b9e0b
commit 1fabf70443
25 changed files with 616 additions and 111 deletions

View File

@ -39,6 +39,7 @@
#include "thread.h"
#include "pipeline.h"
#include "throw_event.h"
#include "objectDeletor.h"
#if defined(WIN32)
#define WINDOWS_LEAN_AND_MEAN
@ -68,6 +69,7 @@ PStatCollector GraphicsEngine::_render_states_pcollector("RenderStates");
PStatCollector GraphicsEngine::_render_states_unused_pcollector("RenderStates:Unused");
PStatCollector GraphicsEngine::_cyclers_pcollector("PipelineCyclers");
PStatCollector GraphicsEngine::_dirty_cyclers_pcollector("Dirty PipelineCyclers");
PStatCollector GraphicsEngine::_delete_pcollector("App:Delete");
// These are counted independently by the collision system; we
// redefine them here so we can reset them at each frame.
@ -631,6 +633,14 @@ render_frame() {
#endif // THREADED_PIPELINE && DO_PSTATS
// If there is an object deletor, tell it to flush now, while we're
// between frames.
ObjectDeletor *deletor = ObjectDeletor::get_global_ptr();
if (deletor != (ObjectDeletor *)NULL) {
PStatTimer timer(_delete_pcollector);
deletor->flush();
}
GeomCacheManager::flush_level();
CullTraverser::flush_level();
RenderState::flush_level();

View File

@ -359,6 +359,7 @@ private:
static PStatCollector _render_states_unused_pcollector;
static PStatCollector _cyclers_pcollector;
static PStatCollector _dirty_cyclers_pcollector;
static PStatCollector _delete_pcollector;
static PStatCollector _cnode_volume_pcollector;
static PStatCollector _gnode_volume_pcollector;

View File

@ -30,6 +30,7 @@
multifile.I multifile.h \
namable.I \
namable.h nativeNumericData.I nativeNumericData.h \
objectDeletor.h objectDeletor.I \
ordered_vector.h ordered_vector.I ordered_vector.T \
password_hash.h \
patchfile.I patchfile.h \
@ -77,6 +78,7 @@
memoryUsagePointers.cxx multifile.cxx \
namable.cxx \
nativeNumericData.cxx \
objectDeletor.cxx \
ordered_vector.cxx \
password_hash.cxx \
patchfile.cxx \
@ -130,6 +132,7 @@
multifile.I multifile.h \
namable.I \
namable.h nativeNumericData.I nativeNumericData.h \
objectDeletor.h objectDeletor.I \
ordered_vector.h ordered_vector.I ordered_vector.T \
password_hash.h \
patchfile.I patchfile.h \

View File

@ -168,45 +168,6 @@ init_libexpress() {
#endif
}
bool
get_leak_memory() {
static ConfigVariableBool *leak_memory = NULL;
if (leak_memory == (ConfigVariableBool *)NULL) {
leak_memory = new ConfigVariableBool
("leak-memory", false,
PRC_DESC("Set leak-memory true to disable the actual deletion of "
"ReferenceCount-derived objects. This is sometimes useful to track "
"a reference counting bug, since the formerly deleted objects will "
"still remain (with a reference count of -100) without being "
"overwritten with a newly-allocated object, and the assertion tests "
"in ReferenceCount may more accurately detect the first instance of "
"an error."));
}
return *leak_memory;
}
bool
get_never_destruct() {
static ConfigVariableBool *never_destruct = NULL;
if (never_destruct == (ConfigVariableBool *)NULL) {
never_destruct = new ConfigVariableBool
("never-destruct", false,
PRC_DESC("never-destruct is similar to leak-memory, except that not "
"only will memory not be freed, but the destructor will not even be "
"called (on ReferenceCount objects, at least). This will leak gobs "
"of memory, but ensures that every pointer to a ReferenceCount "
"object will always be valid, and may be useful for tracking down "
"certain kinds of errors. "
"never-destruct is only respected if leak-memory is true."));
}
return *never_destruct;
}
bool
get_use_high_res_clock() {
static ConfigVariableBool *use_high_res_clock = NULL;

View File

@ -51,8 +51,6 @@ NotifyCategoryDecl(express, EXPCL_PANDAEXPRESS, EXPTP_PANDAEXPRESS);
//extern EXPCL_PANDAEXPRESS const bool track_memory_usage;
EXPCL_PANDAEXPRESS bool get_leak_memory();
EXPCL_PANDAEXPRESS bool get_never_destruct();
EXPCL_PANDAEXPRESS bool get_use_high_res_clock();
EXPCL_PANDAEXPRESS bool get_paranoid_clock();
EXPCL_PANDAEXPRESS bool get_paranoid_inheritance();

View File

@ -18,6 +18,7 @@
#include "multifile.cxx"
#include "namable.cxx"
#include "nativeNumericData.cxx"
#include "objectDeletor.cxx"
#include "ordered_vector.cxx"
#include "patchfile.cxx"
#include "password_hash.cxx"

View File

@ -0,0 +1,62 @@
// Filename: objectDeletor.I
// Created by: drose (10Apr06)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: ObjectDeletor::get_global_ptr
// Access: Public, Static
// Description: Returns the global ObjectDeletor object. This may
// return NULL if there is no such object.
////////////////////////////////////////////////////////////////////
INLINE ObjectDeletor *ObjectDeletor::
get_global_ptr() {
return (ObjectDeletor *)AtomicAdjust::get_ptr(_global_ptr);
}
////////////////////////////////////////////////////////////////////
// Function: ObjectDeletor::set_global_ptr
// Access: Public, Static
// Description: Assigns the global ObjectDeletor object. Returns
// the pointer to the previous object, if any.
////////////////////////////////////////////////////////////////////
INLINE ObjectDeletor *ObjectDeletor::
set_global_ptr(ObjectDeletor *ptr) {
return (ObjectDeletor *)AtomicAdjust::set_ptr(_global_ptr, ptr);
}
////////////////////////////////////////////////////////////////////
// Function: ObjectDeletor::DeleteToken::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE ObjectDeletor::DeleteToken::
DeleteToken(DeleteFunc *func, void *ptr) :
_func(func),
_ptr(ptr)
{
}
////////////////////////////////////////////////////////////////////
// Function: ObjectDeletor::DeleteToken::do_delete
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void ObjectDeletor::DeleteToken::
do_delete() {
(*_func)(_ptr);
}

View File

@ -0,0 +1,84 @@
// Filename: objectDeletor.h
// Created by: drose (10Apr06)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "objectDeletor.h"
#include "configVariableString.h"
void *ObjectDeletor::_global_ptr = NULL;
////////////////////////////////////////////////////////////////////
// Function: ObjectDeletor::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
ObjectDeletor::
~ObjectDeletor() {
}
////////////////////////////////////////////////////////////////////
// Function: ObjectDeletor::delete_object
// Access: Public, Virtual
// Description: Adds the pointer to the object to be deleted, along
// with a pointer to a function that can delete it.
////////////////////////////////////////////////////////////////////
void ObjectDeletor::
delete_object(DeleteFunc *func, void *ptr) {
// The base class functionality simply deletes the pointer
// immediately.
(*func)(ptr);
}
////////////////////////////////////////////////////////////////////
// Function: ObjectDeletor::flush
// Access: Public, Virtual
// Description: Ensures that any objects queued up for deletion have
// been fully deleted by the time flush() returns.
////////////////////////////////////////////////////////////////////
void ObjectDeletor::
flush() {
}
////////////////////////////////////////////////////////////////////
// Function: ObjectDeletor::register_subclass
// Access: Public, Static
// Description: Called at static init time as each subclass is
// defined. The purpose here is to consult the config
// variable object-deletor and install the requested
// deletor. If the indicated deletor is the one that is
// named by the config variable, it is installed.
////////////////////////////////////////////////////////////////////
void ObjectDeletor::
register_subclass(ObjectDeletor *deletor, const string &name) {
ConfigVariableString object_deletor
("object-deletor", "",
PRC_DESC("Specify the type of ObjectDeletor to install. This string "
"must match one of the existing ObjectDeletor types, and if "
"it does not match, no error message is generated. To "
"determine if the ObjectDeletor was properly installed, "
"set notify-level-express debug."));
if (object_deletor == name) {
if (express_cat.is_debug()) {
express_cat.debug()
<< "Installing ObjectDeletor type " << name << "\n";
}
set_global_ptr(deletor);
} else {
delete deletor;
}
}

View File

@ -0,0 +1,72 @@
// Filename: objectDeletor.h
// Created by: drose (10Apr06)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef OBJECTDELETOR_H
#define OBJECTDELETOR_H
#include "pandabase.h"
#include "atomicAdjust.h"
////////////////////////////////////////////////////////////////////
// Class : ObjectDeletor
// Description : This class is used to collect together pointers to
// objects that are ready to be destructed and freed.
// The actual destruction may be performed immediately,
// or it can be performed at some later time, when it is
// convenient for the application.
//
// This is particularly useful for a multithreaded
// application; the destruction may be performed in a
// sub-thread with a lower priority.
//
// This class body is just an interface; the
// ObjectDeletor class simply deletes its pointers
// immediately. More sophisticated deletors are
// implemented elsewhere.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEXPRESS ObjectDeletor {
public:
virtual ~ObjectDeletor();
typedef void DeleteFunc(void *ptr);
virtual void delete_object(DeleteFunc *func, void *ptr);
virtual void flush();
INLINE static ObjectDeletor *get_global_ptr();
INLINE static ObjectDeletor *set_global_ptr(ObjectDeletor *ptr);
static void register_subclass(ObjectDeletor *deletor, const string &name);
protected:
class DeleteToken {
public:
INLINE DeleteToken(DeleteFunc *func, void *ptr);
INLINE void do_delete();
DeleteFunc *_func;
void *_ptr;
};
private:
static void *_global_ptr;
};
#include "objectDeletor.I"
#endif

View File

@ -332,6 +332,41 @@ weak_unref(WeakPointerToVoid *ptv) {
_weak_list->clear_reference(ptv);
}
////////////////////////////////////////////////////////////////////
// Function: DeleteWrapper::do_delete
// Access: Public, Static
// Description: This helper function encapsulates calling the
// destructor and delete operator for the given pointer.
// A pointer to this function is passed to the global
// ObjectDeletor, when there is one.
////////////////////////////////////////////////////////////////////
template<class ObjectType>
void DeleteWrapper<ObjectType>::
do_delete(void *ptr) {
TAU_PROFILE("void DeleteWrapper::do_delete(void *)", " ", TAU_USER);
delete ((ObjectType *)ptr);
}
////////////////////////////////////////////////////////////////////
// Function: RefCountDeleteWrapper::do_delete
// Access: Public, Static
// Description: This is similar to DeleteWrapper::do_delete(), above,
// except it is specialized for an object that inherits
// from ReferenceCount, and it will check that some
// other pointer hasn't incremented the reference count
// in the interim before the pointer is actually
// deleted.
////////////////////////////////////////////////////////////////////
template<class RefCountType>
void RefCountDeleteWrapper<RefCountType>::
do_delete(void *ptr) {
TAU_PROFILE("void RefCountDeleteWrapper::do_delete(void *)", " ", TAU_USER);
if (!((RefCountType *)ptr)->unref()) {
// The reference count has reached 0; time to delete the pointer.
delete ((RefCountType *)ptr);
}
}
////////////////////////////////////////////////////////////////////
// Function: unref_delete
// Description: This global helper function will unref the given
@ -345,32 +380,66 @@ weak_unref(WeakPointerToVoid *ptv) {
template<class RefCountType>
INLINE void
unref_delete(RefCountType *ptr) {
TAU_PROFILE("unref_delete()", " ", TAU_USER);
TAU_PROFILE("void unref_delete(RefCountType *)", " ", TAU_USER);
// Although it may be tempting to try to upcast ptr to a
// ReferenceCount object (particularly to get around inheritance
// issues), resist that temptation, since some classes (in
// particular, TransformState and RenderState) rely on a non-virtual
// overloading of the unref() method.
if (!ptr->unref()) {
#ifndef NDEBUG
if (get_leak_memory()) {
// In leak-memory mode, we don't actually delete the pointer,
// although we do call the destructor explicitly. This has
// exactly the same effect as deleting it, without actually
// freeing up the memory it uses.
// Furthermore, if we have never-destruct set, we don't even
// call the destructor.
if (!get_never_destruct()) {
ptr->~RefCountType();
}
if (!ptr->unref()) {
// The reference count has reached 0; time to delete the pointer.
// Is there a deletor in effect? If so, pass it to that object.
ObjectDeletor *deletor = ObjectDeletor::get_global_ptr();
if (deletor != (ObjectDeletor *)NULL) {
// Re-ref the pointer before adding it to the deletor. The
// deletor will de-ref it again before deleting it.
ptr->ref();
deletor->delete_object(RefCountDeleteWrapper<RefCountType>::do_delete, (void *)ptr);
return;
}
#endif
// If there's no deletor, just delete the pointer now.
delete ptr;
}
}
////////////////////////////////////////////////////////////////////
// Function: defer_delete
// Description: This global helper function is designed to be called
// in lieu of the delete operator on any type of object
// (except for an object that inherits from
// ReferenceCount, of course, since you should never
// call delete explicitly on a reference-counted
// object).
//
// This function will ultimately have the same effect as
// calling delete on the object. If a ObjectDeletor
// is currently in effect, the delete will happen at
// some later time; but if a ObjectDeletor is not in
// effect, the delete will happen immediately.
//
// You should not attempt to replace an array-delete
// call, e.g. delete[] array, with a call to
// defer_delete(). This only replaces single-object
// deletes, e.g. delete object.
////////////////////////////////////////////////////////////////////
template<class ObjectType>
INLINE void
defer_delete(ObjectType *ptr) {
TAU_PROFILE("void defer_delete(ObjectType *)", " ", TAU_USER);
ObjectDeletor *deletor = ObjectDeletor::get_global_ptr();
if (deletor != (ObjectDeletor *)NULL) {
deletor->delete_object(DeleteWrapper<ObjectType>::do_delete, (void *)ptr);
return;
}
// If there's no deletor, just delete the pointer now.
delete ptr;
}
////////////////////////////////////////////////////////////////////
// Function: RefCountProxy::Constructor

View File

@ -27,6 +27,7 @@
#include "atomicAdjust.h"
#include "numeric_types.h"
#include "deletedChain.h"
#include "objectDeletor.h"
#include <stdlib.h>
@ -101,9 +102,24 @@ private:
static TypeHandle _type_handle;
};
template<class ObjectType>
class DeleteWrapper {
public:
static void do_delete(void *ptr);
};
template<class RefCountType>
class RefCountDeleteWrapper {
public:
static void do_delete(void *ptr);
};
template<class RefCountType>
INLINE void unref_delete(RefCountType *ptr);
template<class ObjectType>
INLINE void defer_delete(ObjectType *ptr);
////////////////////////////////////////////////////////////////////
// Class : RefCountProxy
// Description : A "proxy" to use to make a reference-countable object

View File

@ -606,6 +606,20 @@ get_override(TypeHandle type) const {
////////////////////////////////////////////////////////////////////
bool RenderState::
unref() const {
// Most of the time, we won't need to grab the lock. We first check
// whether we think we will need to grab it. Then, after we have
// successfully acquired the lock, we check that the condition is
// still valid.
// It is possible that, due to some race condition, this condition
// is never seen as true on any one thread. In that case, the cycle
// will not automatically be detected and broken. But since (a)
// that will be a relatively rare situation, (b) it will be
// expensive to protect against it, and (c) the damage is minimal,
// the race condition is allowed to remain.
if (get_cache_ref_count() > 0 &&
get_ref_count() == get_cache_ref_count() + 1) {
ReMutexHolder holder(*_states_lock);
if (get_cache_ref_count() > 0 &&
@ -629,6 +643,7 @@ unref() const {
}
}
}
}
return ReferenceCount::unref();
}

View File

@ -805,6 +805,20 @@ invert_compose(const TransformState *other) const {
////////////////////////////////////////////////////////////////////
bool TransformState::
unref() const {
// Most of the time, we won't need to grab the lock. We first check
// whether we think we will need to grab it. Then, after we have
// successfully acquired the lock, we check that the condition is
// still valid.
// It is possible that, due to some race condition, this condition
// is never seen as true on any one thread. In that case, the cycle
// will not automatically be detected and broken. But since (a)
// that will be a relatively rare situation, (b) it will be
// expensive to protect against it, and (c) the damage is minimal,
// the race condition is allowed to remain.
if (get_cache_ref_count() > 0 &&
get_ref_count() == get_cache_ref_count() + 1) {
ReMutexHolder holder(*_states_lock);
if (get_cache_ref_count() > 0 &&
@ -828,6 +842,7 @@ unref() const {
}
}
}
}
return ReferenceCount::unref();
}

View File

@ -27,6 +27,7 @@
config_util.N config_util.h configurable.h \
datagramInputFile.I datagramInputFile.h \
datagramOutputFile.I datagramOutputFile.h \
deferredDeletor.h \
drawMask.h \
factoryBase.I factoryBase.h \
factoryParam.I factoryParam.h factoryParams.I \
@ -47,6 +48,7 @@
nodeCachedReferenceCount.h nodeCachedReferenceCount.I \
nodePointerToBase.h nodePointerToBase.I \
nodePointerTo.h nodePointerTo.I \
nonDeletor.h \
pta_double.h \
pta_float.h pta_int.h \
string_utils.I string_utils.N string_utils.h \
@ -72,6 +74,7 @@
clockObject.cxx \
config_util.cxx configurable.cxx \
datagramInputFile.cxx datagramOutputFile.cxx \
deferredDeletor.cxx \
factoryBase.cxx \
factoryParam.cxx factoryParams.cxx \
globalPointerRegistry.cxx \
@ -85,6 +88,7 @@
nodeCachedReferenceCount.cxx \
nodePointerToBase.cxx \
nodePointerTo.cxx \
nonDeletor.cxx \
pta_double.cxx pta_float.cxx \
pta_int.cxx pta_ushort.cxx \
string_utils.cxx timedCycle.cxx typedWritable.cxx \
@ -112,6 +116,7 @@
config_util.h configurable.h factory.I factory.h \
datagramInputFile.I datagramInputFile.h \
datagramOutputFile.I datagramOutputFile.h \
deferredDeletor.h \
drawMask.h \
factoryBase.I factoryBase.h factoryParam.I factoryParam.h \
factoryParams.I factoryParams.h \
@ -132,6 +137,7 @@
nodeCachedReferenceCount.h nodeCachedReferenceCount.I \
nodePointerToBase.h nodePointerToBase.I \
nodePointerTo.h nodePointerTo.I \
nonDeletor.h \
pta_double.h \
pta_float.h pta_int.h pta_ushort.h \
string_utils.I \

View File

@ -234,21 +234,12 @@ INLINE void
cache_unref_delete(RefCountType *ptr) {
ptr->cache_unref();
if (ptr->get_ref_count() == 0) {
#ifndef NDEBUG
if (get_leak_memory()) {
// In leak-memory mode, we don't actually delete the pointer,
// although we do call the destructor explicitly. This has
// exactly the same effect as deleting it, without actually
// freeing up the memory it uses.
// Furthermore, if we have never-destruct set, we don't even
// call the destructor.
if (!get_never_destruct()) {
ptr->~RefCountType();
}
ObjectDeletor *deletor = ObjectDeletor::get_global_ptr();
if (deletor != (ObjectDeletor *)NULL) {
ptr->ref();
deletor->delete_object(RefCountDeleteWrapper<RefCountType>::do_delete, (void *)ptr);
return;
}
#endif
delete ptr;
}
}

View File

@ -22,6 +22,7 @@
#include "pandabase.h"
#include "typedWritableReferenceCount.h"
#include "objectDeletor.h"
////////////////////////////////////////////////////////////////////
// Class : CachedTypedWritableReferenceCount

View File

@ -38,6 +38,8 @@
#include "writableParam.h"
#include "keyboardButton.h"
#include "mouseButton.h"
#include "deferredDeletor.h"
#include "nonDeletor.h"
#include "dconfig.h"
@ -98,6 +100,9 @@ ConfigureFn(config_util) {
KeyboardButton::init_keyboard_buttons();
MouseButton::init_mouse_buttons();
DeferredDeletor::register_deletor();
NonDeletor::register_deletor();
register_type(BamReader::_remove_flag, "remove");
}

View File

@ -0,0 +1,68 @@
// Filename: deferredDeletor.cxx
// Created by: drose (10Apr06)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "deferredDeletor.h"
#include "config_util.h"
#include "mutexHolder.h"
////////////////////////////////////////////////////////////////////
// Function: DeferredDeletor::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
DeferredDeletor::
DeferredDeletor() : _lock("DeferredDeletor") {
}
////////////////////////////////////////////////////////////////////
// Function: DeferredDeletor::delete_object
// Access: Public, Virtual
// Description: Adds the pointer to the object to be deleted, along
// with a pointer to a function that can delete it.
////////////////////////////////////////////////////////////////////
void DeferredDeletor::
delete_object(DeleteFunc *func, void *ptr) {
MutexHolder holder(_lock);
_tokens.push_back(DeleteToken(func, ptr));
}
////////////////////////////////////////////////////////////////////
// Function: DeferredDeletor::flush
// Access: Public, Virtual
// Description: Ensures that any objects queued up for deletion have
// been fully deleted by the time flush() returns.
////////////////////////////////////////////////////////////////////
void DeferredDeletor::
flush() {
MutexHolder holder(_lock);
Tokens::iterator ti;
for (ti = _tokens.begin(); ti != _tokens.end(); ++ti) {
(*ti).do_delete();
}
_tokens.clear();
}
////////////////////////////////////////////////////////////////////
// Function: DeferredDeletor::register_deletor
// Access: Public, Static
// Description: Registers this deletor with the global pool.
////////////////////////////////////////////////////////////////////
void DeferredDeletor::
register_deletor() {
register_subclass(new DeferredDeletor, "deferred");
}

View File

@ -0,0 +1,48 @@
// Filename: deferredDeletor.h
// Created by: drose (10Apr06)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef DEFERREDDELETOR_H
#define DEFERREDDELETOR_H
#include "pandabase.h"
#include "objectDeletor.h"
#include "pvector.h"
#include "pmutex.h"
////////////////////////////////////////////////////////////////////
// Class : DeferredDeletor
// Description : The DeferredDeletor does all its deleting between
// frames, where it can be observed by PStats and where
// it won't interfere with rendering.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEXPRESS DeferredDeletor : public ObjectDeletor {
public:
DeferredDeletor();
virtual void delete_object(DeleteFunc *func, void *ptr);
virtual void flush();
static void register_deletor();
private:
typedef pvector<DeleteToken> Tokens;
Tokens _tokens;
Mutex _lock;
};
#endif

View File

@ -258,21 +258,13 @@ INLINE void
node_unref_delete(RefCountType *ptr) {
ptr->node_unref();
if (ptr->get_ref_count() == 0) {
#ifndef NDEBUG
if (get_leak_memory()) {
// In leak-memory mode, we don't actually delete the pointer,
// although we do call the destructor explicitly. This has
// exactly the same effect as deleting it, without actually
// freeing up the memory it uses.
// Furthermore, if we have never-destruct set, we don't even
// call the destructor.
if (!get_never_destruct()) {
ptr->~RefCountType();
}
ObjectDeletor *deletor = ObjectDeletor::get_global_ptr();
if (deletor != (ObjectDeletor *)NULL) {
ptr->ref();
deletor->delete_object(RefCountDeleteWrapper<RefCountType>::do_delete, (void *)ptr);
return;
}
#endif
delete ptr;
}
}

View File

@ -22,6 +22,7 @@
#include "pandabase.h"
#include "cachedTypedWritableReferenceCount.h"
#include "objectDeletor.h"
////////////////////////////////////////////////////////////////////
// Class : NodeCachedReferenceCount

View File

@ -0,0 +1,44 @@
// Filename: nonDeletor.cxx
// Created by: drose (10Apr06)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "nonDeletor.h"
#include "config_util.h"
////////////////////////////////////////////////////////////////////
// Function: NonDeletor::delete_object
// Access: Public, Virtual
// Description: Adds the pointer to the object to be deleted, along
// with a pointer to a function that can delete it.
////////////////////////////////////////////////////////////////////
void NonDeletor::
delete_object(DeleteFunc *, void *ptr) {
if (util_cat.is_spam()) {
util_cat.spam()
<< "Not deleting pointer " << ptr << "\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: NonDeletor::register_deletor
// Access: Public, Static
// Description: Registers this deletor with the global pool.
////////////////////////////////////////////////////////////////////
void NonDeletor::
register_deletor() {
register_subclass(new NonDeletor, "none");
}

View File

@ -0,0 +1,40 @@
// Filename: nonDeletor.h
// Created by: drose (10Apr06)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef NONDELETOR_H
#define NONDELETOR_H
#include "pandabase.h"
#include "objectDeletor.h"
////////////////////////////////////////////////////////////////////
// Class : NonDeletor
// Description : This specialization of ObjectDeletor serves a very
// specific function: it *doesn't* delete pointers it is
// given. This is useful mainly for testing, for
// instance to determine if there is a problem with a
// destructor somewhere.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEXPRESS NonDeletor : public ObjectDeletor {
public:
virtual void delete_object(DeleteFunc *func, void *ptr);
static void register_deletor();
};
#endif

View File

@ -14,6 +14,7 @@
#include "configurable.cxx"
#include "datagramInputFile.cxx"
#include "datagramOutputFile.cxx"
#include "deferredDeletor.cxx"
#include "factoryBase.cxx"
#include "factoryParam.cxx"
#include "factoryParams.cxx"

View File

@ -5,6 +5,7 @@
#include "nodeCachedReferenceCount.cxx"
#include "nodePointerToBase.cxx"
#include "nodePointerTo.cxx"
#include "nonDeletor.cxx"
#include "pta_double.cxx"
#include "pta_float.cxx"
#include "pta_int.cxx"