mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 10:54:24 -04:00
add ObjectDeletor; avoid unnecessary locks on RenderState
This commit is contained in:
parent
a5cb0b9e0b
commit
1fabf70443
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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 \
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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"
|
||||
|
62
panda/src/express/objectDeletor.I
Normal file
62
panda/src/express/objectDeletor.I
Normal 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);
|
||||
}
|
84
panda/src/express/objectDeletor.cxx
Normal file
84
panda/src/express/objectDeletor.cxx
Normal 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;
|
||||
}
|
||||
}
|
72
panda/src/express/objectDeletor.h
Normal file
72
panda/src/express/objectDeletor.h
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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 \
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "typedWritableReferenceCount.h"
|
||||
#include "objectDeletor.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : CachedTypedWritableReferenceCount
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
68
panda/src/putil/deferredDeletor.cxx
Normal file
68
panda/src/putil/deferredDeletor.cxx
Normal 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");
|
||||
}
|
48
panda/src/putil/deferredDeletor.h
Normal file
48
panda/src/putil/deferredDeletor.h
Normal 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
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "cachedTypedWritableReferenceCount.h"
|
||||
#include "objectDeletor.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : NodeCachedReferenceCount
|
||||
|
44
panda/src/putil/nonDeletor.cxx
Normal file
44
panda/src/putil/nonDeletor.cxx
Normal 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");
|
||||
}
|
40
panda/src/putil/nonDeletor.h
Normal file
40
panda/src/putil/nonDeletor.h
Normal 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
|
@ -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"
|
||||
|
@ -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"
|
||||
|
Loading…
x
Reference in New Issue
Block a user