diff --git a/dtool/src/dtoolbase/memoryHook.cxx b/dtool/src/dtoolbase/memoryHook.cxx index 11ad35365b..1bc8b09456 100644 --- a/dtool/src/dtoolbase/memoryHook.cxx +++ b/dtool/src/dtoolbase/memoryHook.cxx @@ -51,6 +51,9 @@ #define USE_DL_PREFIX 1 #define NO_MALLINFO 1 +#ifdef _DEBUG + #define DEBUG +#endif #include "dlmalloc.h" #include "dlmalloc_src.cxx" @@ -77,6 +80,9 @@ #define USE_DL_PREFIX 1 #define NO_MALLINFO 1 +#ifdef _DEBUG + #define MALLOC_DEBUG 2 +#endif #include "ptmalloc2_smp_src.cxx" #define call_malloc dlmalloc diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index 1f5df13e03..df0eb0495e 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/panda/src/display/graphicsEngine.cxx @@ -175,6 +175,15 @@ GraphicsEngine:: //////////////////////////////////////////////////////////////////// void GraphicsEngine:: set_threading_model(const GraphicsThreadingModel &threading_model) { + if (!Thread::is_threading_supported()) { + if (!threading_model.is_single_threaded()) { + display_cat.warning() + << "Threading model " << threading_model + << " requested but threading is not available. Ignoring.\n"; + return; + } + } + #ifndef THREADED_PIPELINE if (!threading_model.is_single_threaded()) { display_cat.warning() @@ -688,14 +697,6 @@ 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, current_thread); - deletor->flush(); - } - GeomCacheManager::flush_level(); CullTraverser::flush_level(); RenderState::flush_level(); @@ -1960,7 +1961,8 @@ get_window_renderer(const string &name, int pipeline_stage) { thread->set_min_pipeline_stage(pipeline_stage); _pipeline->set_min_stages(pipeline_stage + 1); - thread->start(TP_normal, true); + bool started = thread->start(TP_normal, true); + nassertr(started, thread.p()); _threads[name] = thread; nassertr(thread->get_pipeline_stage() < _pipeline->get_num_stages(), thread.p()); diff --git a/panda/src/express/Sources.pp b/panda/src/express/Sources.pp index a93ef2784a..37baf03b42 100644 --- a/panda/src/express/Sources.pp +++ b/panda/src/express/Sources.pp @@ -32,7 +32,6 @@ nodePointerToBase.h nodePointerToBase.I \ nodePointerTo.h nodePointerTo.I \ nodeReferenceCount.h nodeReferenceCount.I \ - objectDeletor.h objectDeletor.I \ ordered_vector.h ordered_vector.I ordered_vector.T \ password_hash.h \ patchfile.I patchfile.h \ @@ -84,7 +83,6 @@ nodePointerToBase.cxx \ nodePointerTo.cxx \ nodeReferenceCount.cxx \ - objectDeletor.cxx \ ordered_vector.cxx \ password_hash.cxx \ patchfile.cxx \ @@ -142,7 +140,6 @@ nodePointerToBase.h nodePointerToBase.I \ nodePointerTo.h nodePointerTo.I \ nodeReferenceCount.h nodeReferenceCount.I \ - objectDeletor.h objectDeletor.I \ ordered_vector.h ordered_vector.I ordered_vector.T \ password_hash.h \ patchfile.I patchfile.h \ diff --git a/panda/src/express/express_composite1.cxx b/panda/src/express/express_composite1.cxx index 0054fdfad7..da2c52cbd2 100644 --- a/panda/src/express/express_composite1.cxx +++ b/panda/src/express/express_composite1.cxx @@ -19,7 +19,6 @@ #include "nodePointerToBase.cxx" #include "nodePointerTo.cxx" #include "nodeReferenceCount.cxx" -#include "objectDeletor.cxx" #include "ordered_vector.cxx" #include "patchfile.cxx" #include "password_hash.cxx" diff --git a/panda/src/express/nodeReferenceCount.I b/panda/src/express/nodeReferenceCount.I index 631e60f5d5..2c3684a0cf 100644 --- a/panda/src/express/nodeReferenceCount.I +++ b/panda/src/express/nodeReferenceCount.I @@ -147,14 +147,8 @@ get_node_ref_count() const { //////////////////////////////////////////////////////////////////// // Function: NodeReferenceCount::node_ref // Access: Published -// Description: Explicitly increments the reference count. -// -// This function is const, even though it changes the -// object, because generally fiddling with an object's -// reference count isn't considered part of fiddling -// with the object. An object might be const in other -// ways, but we still need to accurately count the -// number of references to it. +// Description: Explicitly increments the node reference count and +// the normal reference count simultaneously. //////////////////////////////////////////////////////////////////// INLINE void NodeReferenceCount:: node_ref() const { @@ -169,42 +163,16 @@ node_ref() const { //////////////////////////////////////////////////////////////////// // Function: NodeReferenceCount::node_unref // Access: Published -// Description: Explicitly decrements the reference count. Note that -// the object will not be implicitly deleted by unref() -// simply because the reference count drops to zero. -// (Having a member function delete itself is -// problematic; plus, we don't have a virtual destructor -// anyway.) However, see the helper function -// unref_delete(). -// -// User code should avoid using ref() and unref() -// directly, which can result in missed reference -// counts. Instead, let a PointerTo object manage the -// reference counting automatically. -// -// This function is const, even though it changes the -// object, because generally fiddling with an object's -// reference count isn't considered part of fiddling -// with the object. An object might be const in other -// ways, but we still need to accurately count the -// number of references to it. +// Description: Explicitly decrements the node reference count and +// the normal reference count simultaneously. // // The return value is true if the new reference count // is nonzero, false if it is zero. //////////////////////////////////////////////////////////////////// INLINE bool NodeReferenceCount:: node_unref() const { -#ifdef _DEBUG - nassertr(test_ref_count_integrity(), 0); -#endif - - // If this assertion fails, you tried to unref an object with a - // zero reference count. Are you using ref() and unref() - // directly? Are you sure you can't use PointerTo's? - nassertr(_node_ref_count > 0, 0); - - unref(); - return AtomicAdjust::dec(((NodeReferenceCount *)this)->_node_ref_count); + node_unref_only(); + return unref(); } //////////////////////////////////////////////////////////////////// @@ -222,6 +190,28 @@ test_ref_count_integrity() const { #endif } +//////////////////////////////////////////////////////////////////// +// Function: NodeReferenceCount::node_unref_only +// Access: Protected +// Description: Decrements the node reference count without affecting +// the normal reference count. Intended to be called by +// derived classes only, presumably to reimplement +// node_unref(). +//////////////////////////////////////////////////////////////////// +INLINE void NodeReferenceCount:: +node_unref_only() const { +#ifdef _DEBUG + nassertv(test_ref_count_integrity()); +#endif + + // If this assertion fails, you tried to unref an object with a + // zero reference count. Are you using ref() and unref() + // directly? Are you sure you can't use PointerTo's? + nassertv(_node_ref_count > 0); + + AtomicAdjust::dec(((NodeReferenceCount *)this)->_node_ref_count); +} + //////////////////////////////////////////////////////////////////// // Function: node_unref_delete // Description: This global helper function will unref the given @@ -235,15 +225,7 @@ test_ref_count_integrity() const { template INLINE void node_unref_delete(RefCountType *ptr) { - ptr->node_unref(); - if (ptr->get_ref_count() == 0) { - ObjectDeletor *deletor = ObjectDeletor::get_global_ptr(); - if (deletor != (ObjectDeletor *)NULL) { - ptr->ref(); - deletor->delete_object(RefCountDeleteWrapper::do_delete, (void *)ptr); - return; - } - + if (!ptr->node_unref()) { delete ptr; } } diff --git a/panda/src/express/nodeReferenceCount.h b/panda/src/express/nodeReferenceCount.h index 10a1dedb15..eee3cb5eb6 100644 --- a/panda/src/express/nodeReferenceCount.h +++ b/panda/src/express/nodeReferenceCount.h @@ -57,6 +57,8 @@ PUBLISHED: INLINE bool test_ref_count_integrity() const; protected: + INLINE void node_unref_only() const; + bool do_test_ref_count_integrity() const; private: diff --git a/panda/src/express/objectDeletor.I b/panda/src/express/objectDeletor.I deleted file mode 100644 index eb4da91de5..0000000000 --- a/panda/src/express/objectDeletor.I +++ /dev/null @@ -1,62 +0,0 @@ -// 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); -} diff --git a/panda/src/express/objectDeletor.cxx b/panda/src/express/objectDeletor.cxx deleted file mode 100644 index e87aa703b0..0000000000 --- a/panda/src/express/objectDeletor.cxx +++ /dev/null @@ -1,85 +0,0 @@ -// 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" -#include "config_express.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; - } -} diff --git a/panda/src/express/objectDeletor.h b/panda/src/express/objectDeletor.h deleted file mode 100644 index 262a799600..0000000000 --- a/panda/src/express/objectDeletor.h +++ /dev/null @@ -1,72 +0,0 @@ -// 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 diff --git a/panda/src/express/referenceCount.I b/panda/src/express/referenceCount.I index 1891560284..998bb02be5 100644 --- a/panda/src/express/referenceCount.I +++ b/panda/src/express/referenceCount.I @@ -348,41 +348,6 @@ 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 -void DeleteWrapper:: -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 -void RefCountDeleteWrapper:: -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 @@ -404,59 +369,11 @@ unref_delete(RefCountType *ptr) { // overloading of the unref() method. 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::do_delete, (void *)ptr); - return; - } - - // If there's no deletor, just delete the pointer now. + // If the reference count has gone to zero, delete the object. 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 -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::do_delete, (void *)ptr); - return; - } - - // If there's no deletor, just delete the pointer now. - delete ptr; -} - - //////////////////////////////////////////////////////////////////// // Function: RefCountProxy::Constructor // Access: Public diff --git a/panda/src/express/referenceCount.h b/panda/src/express/referenceCount.h index 96235d4f50..54ebcd9844 100644 --- a/panda/src/express/referenceCount.h +++ b/panda/src/express/referenceCount.h @@ -105,24 +105,9 @@ private: static TypeHandle _type_handle; }; -template -class DeleteWrapper { -public: - static void do_delete(void *ptr); -}; - -template -class RefCountDeleteWrapper { -public: - static void do_delete(void *ptr); -}; - template INLINE void unref_delete(RefCountType *ptr); -template -INLINE void defer_delete(ObjectType *ptr); - //////////////////////////////////////////////////////////////////// // Class : RefCountProxy // Description : A "proxy" to use to make a reference-countable object diff --git a/panda/src/gobj/geomVertexArrayFormat.cxx b/panda/src/gobj/geomVertexArrayFormat.cxx index f723a6ac84..75d058bdb6 100644 --- a/panda/src/gobj/geomVertexArrayFormat.cxx +++ b/panda/src/gobj/geomVertexArrayFormat.cxx @@ -24,6 +24,7 @@ #include "bamReader.h" #include "bamWriter.h" #include "indirectLess.h" +#include "mutexHolder.h" GeomVertexArrayFormat::Registry *GeomVertexArrayFormat::_registry = NULL; TypeHandle GeomVertexArrayFormat::_type_handle; @@ -186,15 +187,38 @@ operator = (const GeomVertexArrayFormat ©) { //////////////////////////////////////////////////////////////////// GeomVertexArrayFormat:: ~GeomVertexArrayFormat() { - if (is_registered()) { - get_registry()->unregister_format(this); - } + // unref() should have unregistered us. + nassertv(!is_registered()); + Columns::iterator ci; for (ci = _columns.begin(); ci != _columns.end(); ++ci) { delete (*ci); } } +//////////////////////////////////////////////////////////////////// +// Function: GeomVertexArrayFormat::unref +// Access: Published +// Description: This method overrides ReferenceCount::unref() to +// unregister the object when its reference count goes +// to zero. +//////////////////////////////////////////////////////////////////// +bool GeomVertexArrayFormat:: +unref() const { + Registry *registry = get_registry(); + MutexHolder holder(registry->_lock); + + if (ReferenceCount::unref()) { + return true; + } + + if (is_registered()) { + registry->unregister_format((GeomVertexArrayFormat *)this); + } + + return false; +} + //////////////////////////////////////////////////////////////////// // Function: GeomVertexArrayFormat::add_column // Access: Published @@ -759,12 +783,15 @@ register_format(GeomVertexArrayFormat *format) { // a zero reference count and is not added into the map below, it // will be automatically deleted when this function returns. PT(GeomVertexArrayFormat) pt_format = format; - - ArrayFormats::iterator fi = _formats.insert(format).first; - - GeomVertexArrayFormat *new_format = (*fi); - if (!new_format->is_registered()) { - new_format->do_register(); + + GeomVertexArrayFormat *new_format; + { + MutexHolder holder(_lock); + ArrayFormats::iterator fi = _formats.insert(format).first; + new_format = (*fi); + if (!new_format->is_registered()) { + new_format->do_register(); + } } return new_format; @@ -776,6 +803,8 @@ register_format(GeomVertexArrayFormat *format) { // Description: Removes the indicated format from the registry. // Normally this should not be done until the format is // destructing. +// +// The lock should be held prior to calling this method. //////////////////////////////////////////////////////////////////// void GeomVertexArrayFormat::Registry:: unregister_format(GeomVertexArrayFormat *format) { diff --git a/panda/src/gobj/geomVertexArrayFormat.h b/panda/src/gobj/geomVertexArrayFormat.h index 5a8114074c..8d5660aab5 100644 --- a/panda/src/gobj/geomVertexArrayFormat.h +++ b/panda/src/gobj/geomVertexArrayFormat.h @@ -26,6 +26,7 @@ #include "indirectCompareTo.h" #include "pvector.h" #include "pmap.h" +#include "pmutex.h" class GeomVertexFormat; class GeomVertexData; @@ -80,6 +81,8 @@ PUBLISHED: void operator = (const GeomVertexArrayFormat ©); ~GeomVertexArrayFormat(); + bool unref() const; + INLINE bool is_registered() const; INLINE static CPT(GeomVertexArrayFormat) register_format(const GeomVertexArrayFormat *format); @@ -147,6 +150,7 @@ private: void unregister_format(GeomVertexArrayFormat *format); ArrayFormats _formats; + Mutex _lock; }; static Registry *_registry; diff --git a/panda/src/gobj/geomVertexFormat.cxx b/panda/src/gobj/geomVertexFormat.cxx index e3053ac4f9..ba559a5356 100644 --- a/panda/src/gobj/geomVertexFormat.cxx +++ b/panda/src/gobj/geomVertexFormat.cxx @@ -19,7 +19,7 @@ #include "geomVertexFormat.h" #include "geomVertexData.h" #include "geomMunger.h" -#include "mutexHolder.h" +#include "reMutexHolder.h" #include "indent.h" #include "bamReader.h" #include "bamWriter.h" @@ -86,9 +86,31 @@ operator = (const GeomVertexFormat ©) { //////////////////////////////////////////////////////////////////// GeomVertexFormat:: ~GeomVertexFormat() { - if (is_registered()) { - get_registry()->unregister_format(this); + // unref() should have unregistered us. + nassertv(!is_registered()); +} + +//////////////////////////////////////////////////////////////////// +// Function: GeomVertexFormat::unref +// Access: Published +// Description: This method overrides ReferenceCount::unref() to +// unregister the object when its reference count goes +// to zero. +//////////////////////////////////////////////////////////////////// +bool GeomVertexFormat:: +unref() const { + Registry *registry = get_registry(); + ReMutexHolder holder(registry->_lock); + + if (ReferenceCount::unref()) { + return true; } + + if (is_registered()) { + registry->unregister_format((GeomVertexFormat *)this); + } + + return false; } @@ -669,6 +691,7 @@ void GeomVertexFormat:: make_registry() { if (_registry == (Registry *)NULL) { _registry = new Registry; + _registry->make_standard_formats(); } } @@ -897,6 +920,15 @@ fillin(DatagramIterator &scan, BamReader *manager) { //////////////////////////////////////////////////////////////////// GeomVertexFormat::Registry:: Registry() { +} + +//////////////////////////////////////////////////////////////////// +// Function: GeomVertexFormat::Registry::make_standard_formats +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void GeomVertexFormat::Registry:: +make_standard_formats() { _v3 = register_format(new GeomVertexArrayFormat (InternalName::get_vertex(), 3, NT_float32, C_point)); @@ -1016,11 +1048,14 @@ register_format(GeomVertexFormat *format) { // will be automatically deleted when this function returns. PT(GeomVertexFormat) pt_format = format; - Formats::iterator fi = _formats.insert(format).first; - - GeomVertexFormat *new_format = (*fi); - if (!new_format->is_registered()) { - new_format->do_register(); + GeomVertexFormat *new_format; + { + ReMutexHolder holder(_lock); + Formats::iterator fi = _formats.insert(format).first; + new_format = (*fi); + if (!new_format->is_registered()) { + new_format->do_register(); + } } return new_format; @@ -1032,6 +1067,8 @@ register_format(GeomVertexFormat *format) { // Description: Removes the indicated format from the registry. // Normally this should not be done until the format is // destructing. +// +// The lock should be held prior to calling this method. //////////////////////////////////////////////////////////////////// void GeomVertexFormat::Registry:: unregister_format(GeomVertexFormat *format) { diff --git a/panda/src/gobj/geomVertexFormat.h b/panda/src/gobj/geomVertexFormat.h index 7623a6f537..3e763268f6 100644 --- a/panda/src/gobj/geomVertexFormat.h +++ b/panda/src/gobj/geomVertexFormat.h @@ -31,7 +31,7 @@ #include "pset.h" #include "pvector.h" #include "indirectCompareTo.h" -#include "pmutex.h" +#include "reMutex.h" class FactoryParams; class GeomVertexData; @@ -70,6 +70,8 @@ PUBLISHED: void operator = (const GeomVertexFormat ©); virtual ~GeomVertexFormat(); + bool unref() const; + INLINE bool is_registered() const; INLINE static CPT(GeomVertexFormat) register_format(const GeomVertexFormat *format); INLINE static CPT(GeomVertexFormat) register_format(const GeomVertexArrayFormat *format); @@ -213,11 +215,14 @@ private: class EXPCL_PANDA Registry { public: Registry(); + void make_standard_formats(); + CPT(GeomVertexFormat) register_format(GeomVertexFormat *format); INLINE CPT(GeomVertexFormat) register_format(GeomVertexArrayFormat *format); void unregister_format(GeomVertexFormat *format); Formats _formats; + ReMutex _lock; CPT(GeomVertexFormat) _v3; CPT(GeomVertexFormat) _v3n3; diff --git a/panda/src/gobj/internalName.cxx b/panda/src/gobj/internalName.cxx index 87478d5f58..00244ca2bc 100644 --- a/panda/src/gobj/internalName.cxx +++ b/panda/src/gobj/internalName.cxx @@ -66,11 +66,44 @@ InternalName(InternalName *parent, const string &basename) : //////////////////////////////////////////////////////////////////// InternalName:: ~InternalName() { - if (_parent != (const InternalName *)NULL) { +#ifndef NDEBUG + { + // unref() should have removed us from our parent's table already. + MutexHolder holder(_parent->_name_table_lock); NameTable::iterator ni = _parent->_name_table.find(_basename); - nassertv(ni != _parent->_name_table.end()); - _parent->_name_table.erase(ni); + nassertv(ni == _parent->_name_table.end()); } +#endif +} + +//////////////////////////////////////////////////////////////////// +// Function: InternalName::unref +// Access: Published +// Description: This method overrides ReferenceCount::unref() to +// clear the pointer from its parent's table when +// its reference count goes to zero. +//////////////////////////////////////////////////////////////////// +bool InternalName:: +unref() const { + if (_parent == (const InternalName *)NULL) { + // No parent; no problem. This is the root InternalName. + // Actually, this probably shouldn't be destructing, but I guess + // it might at application shutdown. + return TypedWritableReferenceCount::unref(); + } + + MutexHolder holder(_parent->_name_table_lock); + + if (ReferenceCount::unref()) { + return true; + } + + // The reference count has just reached zero. + NameTable::iterator ni = _parent->_name_table.find(_basename); + nassertr(ni != _parent->_name_table.end(), false); + _parent->_name_table.erase(ni); + + return false; } //////////////////////////////////////////////////////////////////// @@ -94,12 +127,14 @@ append(const string &name) { return append(name.substr(0, dot))->append(name.substr(dot + 1)); } + MutexHolder holder(_name_table_lock); + NameTable::iterator ni = _name_table.find(name); if (ni != _name_table.end()) { return (*ni).second; } - PT(InternalName) internal_name = new InternalName(this, name); + InternalName *internal_name = new InternalName(this, name); _name_table[name] = internal_name; return internal_name; } diff --git a/panda/src/gobj/internalName.h b/panda/src/gobj/internalName.h index cd84425547..f26edc47e5 100644 --- a/panda/src/gobj/internalName.h +++ b/panda/src/gobj/internalName.h @@ -24,6 +24,7 @@ #include "typedWritableReferenceCount.h" #include "pointerTo.h" #include "pmap.h" +#include "pmutex.h" class FactoryParams; @@ -48,6 +49,8 @@ private: PUBLISHED: virtual ~InternalName(); + bool unref() const; + INLINE static PT(InternalName) make(const string &name); PT(InternalName) append(const string &basename); @@ -93,6 +96,7 @@ private: typedef phash_map NameTable; NameTable _name_table; + Mutex _name_table_lock; static PT(InternalName) _root; static PT(InternalName) _error; diff --git a/panda/src/pgraph/renderAttrib.cxx b/panda/src/pgraph/renderAttrib.cxx index 67b8e21518..fec96ac2aa 100644 --- a/panda/src/pgraph/renderAttrib.cxx +++ b/panda/src/pgraph/renderAttrib.cxx @@ -21,7 +21,9 @@ #include "bamReader.h" #include "indent.h" #include "config_pgraph.h" +#include "reMutexHolder.h" +ReMutex *RenderAttrib::_attribs_lock = NULL; RenderAttrib::Attribs *RenderAttrib::_attribs = NULL; TypeHandle RenderAttrib::_type_handle; @@ -33,12 +35,7 @@ TypeHandle RenderAttrib::_type_handle; RenderAttrib:: RenderAttrib() { if (_attribs == (Attribs *)NULL) { - // Make sure the global _attribs map is allocated. This only has - // to be done once. We could make this map static, but then we - // run into problems if anyone creates a RenderState object at - // static init time; it also seems to cause problems when the - // Panda shared library is unloaded at application exit time. - _attribs = new Attribs; + init_attribs(); } _saved_entry = _attribs->end(); @@ -73,24 +70,10 @@ operator = (const RenderAttrib &) { //////////////////////////////////////////////////////////////////// RenderAttrib:: ~RenderAttrib() { - if (_saved_entry != _attribs->end()) { - // We cannot make this assertion, because the RenderAttrib has - // already partially destructed--this means we cannot look up the - // object in the map. In fact, the map is temporarily invalid - // until we finish destructing, since we screwed up the ordering - // when we changed the return value of get_type(). - // nassertv(_attribs->find(this) == _saved_entry); + ReMutexHolder holder(*_attribs_lock); - // Note: this isn't thread-safe, because once the derived class - // destructor exits and before this destructor completes, the map - // is invalid, and other threads may inadvertently attempt to read - // the invalid map. To make it thread-safe, we need to move this - // functionality to a separate method, that is to be called from - // *each* derived class's destructor (and then we can put the - // above assert back in). - _attribs->erase(_saved_entry); - _saved_entry = _attribs->end(); - } + // unref() should have cleared this. + nassertv(_saved_entry == _attribs->end()); } //////////////////////////////////////////////////////////////////// @@ -157,6 +140,32 @@ cull_callback(CullTraverser *, const CullTraverserData &) const { return true; } +//////////////////////////////////////////////////////////////////// +// Function: RenderAttrib::unref +// Access: Published +// Description: This method overrides ReferenceCount::unref() to +// clear the pointer from the global object pool when +// its reference count goes to zero. +//////////////////////////////////////////////////////////////////// +bool RenderAttrib:: +unref() const { + // We always have to grab the lock, since we will definitely need to + // be holding it if we happen to drop the reference count to 0. + ReMutexHolder holder(*_attribs_lock); + + if (ReferenceCount::unref()) { + // The reference count is still nonzero. + return true; + } + + // The reference count has just reached zero. Make sure the object + // is removed from the global object pool, before anyone else finds + // it and tries to ref it. + ((RenderAttrib *)this)->release_new(); + + return false; +} + //////////////////////////////////////////////////////////////////// // Function: RenderAttrib::output // Access: Published, Virtual @@ -186,6 +195,8 @@ write(ostream &out, int indent_level) const { //////////////////////////////////////////////////////////////////// int RenderAttrib:: get_num_attribs() { + ReMutexHolder holder(*_attribs_lock); + if (_attribs == (Attribs *)NULL) { return 0; } @@ -201,6 +212,8 @@ get_num_attribs() { //////////////////////////////////////////////////////////////////// void RenderAttrib:: list_attribs(ostream &out) { + ReMutexHolder holder(*_attribs_lock); + out << _attribs->size() << " attribs:\n"; Attribs::const_iterator si; for (si = _attribs->begin(); si != _attribs->end(); ++si) { @@ -219,6 +232,8 @@ list_attribs(ostream &out) { //////////////////////////////////////////////////////////////////// bool RenderAttrib:: validate_attribs() { + ReMutexHolder holder(*_attribs_lock); + if (_attribs->empty()) { return true; } @@ -263,6 +278,8 @@ return_new(RenderAttrib *attrib) { return attrib; } + ReMutexHolder holder(*_attribs_lock); + // This should be a newly allocated pointer, not one that was used // for anything else. nassertr(attrib->_saved_entry == _attribs->end(), attrib); @@ -399,6 +416,26 @@ output_comparefunc(ostream &out, PandaCompareFunc fn) const { } } +//////////////////////////////////////////////////////////////////// +// Function: RenderAttrib::release_new +// Access: Private +// Description: This inverse of return_new, this releases this object +// from the global RenderAttrib table. +// +// You must already be holding _attribs_lock before you +// call this method. +//////////////////////////////////////////////////////////////////// +void RenderAttrib:: +release_new() { + nassertv(_attribs_lock->debug_is_locked()); + + if (_saved_entry != _attribs->end()) { + nassertv(_attribs->find(this) == _saved_entry); + _attribs->erase(_saved_entry); + _saved_entry = _attribs->end(); + } +} + //////////////////////////////////////////////////////////////////// // Function: RenderAttrib::make_default_impl // Access: Protected, Virtual @@ -415,6 +452,29 @@ make_default_impl() const { return (RenderAttrib *)NULL; } +//////////////////////////////////////////////////////////////////// +// Function: RenderAttrib::init_attribs +// Access: Public, Static +// Description: Make sure the global _attribs map is allocated. This +// only has to be done once. We could make this map +// static, but then we run into problems if anyone +// creates a RenderAttrib object at static init time; +// it also seems to cause problems when the Panda shared +// library is unloaded at application exit time. +//////////////////////////////////////////////////////////////////// +void RenderAttrib:: +init_attribs() { + _attribs = new Attribs; + + // TODO: we should have a global Panda mutex to allow us to safely + // create _attribs_lock without a startup race condition. For the + // meantime, this is OK because we guarantee that this method is + // called at static init time, presumably when there is still only + // one thread in the world. + _attribs_lock = new ReMutex("RenderAttrib::_attribs_lock"); + nassertv(Thread::get_current_thread() == Thread::get_main_thread()); +} + //////////////////////////////////////////////////////////////////// // Function: RenderAttrib::write_datagram // Access: Public, Virtual diff --git a/panda/src/pgraph/renderAttrib.h b/panda/src/pgraph/renderAttrib.h index be00594dfe..888a4121d6 100644 --- a/panda/src/pgraph/renderAttrib.h +++ b/panda/src/pgraph/renderAttrib.h @@ -24,6 +24,7 @@ #include "typedWritableReferenceCount.h" #include "pointerTo.h" #include "pset.h" +#include "reMutex.h" class AttribSlots; class GraphicsStateGuardianBase; @@ -80,6 +81,9 @@ public: PUBLISHED: INLINE int compare_to(const RenderAttrib &other) const; + + bool unref() const; + virtual void output(ostream &out) const; virtual void write(ostream &out, int indent_level) const; @@ -179,10 +183,18 @@ protected: virtual RenderAttrib *make_default_impl() const=0; void output_comparefunc(ostream &out, PandaCompareFunc fn) const; +private: + void release_new(); + protected: bool _always_reissue; +public: + static void init_attribs(); + private: + // This mutex protects _attribs. + static ReMutex *_attribs_lock; typedef pset > Attribs; static Attribs *_attribs; diff --git a/panda/src/pgraph/renderEffects.cxx b/panda/src/pgraph/renderEffects.cxx index fef694e4ab..42b83ca4db 100644 --- a/panda/src/pgraph/renderEffects.cxx +++ b/panda/src/pgraph/renderEffects.cxx @@ -83,10 +83,9 @@ RenderEffects:: ~RenderEffects() { // Remove the deleted RenderEffects object from the global pool. ReMutexHolder holder(*_states_lock); - if (_saved_entry != _states->end()) { - _states->erase(_saved_entry); - _saved_entry = _states->end(); - } + + // unref() should have cleared this. + nassertv(_saved_entry == _states->end()); } //////////////////////////////////////////////////////////////////// @@ -385,6 +384,40 @@ get_effect(TypeHandle type) const { return NULL; } +//////////////////////////////////////////////////////////////////// +// Function: RenderEffects::unref +// Access: Published +// Description: This method overrides ReferenceCount::unref() to +// check whether the remaining reference count is +// entirely in the cache, and if so, it checks for and +// breaks a cycle in the cache involving this object. +// This is designed to prevent leaks from cyclical +// references within the cache. +// +// Note that this is not a virtual method, and cannot be +// because ReferenceCount itself declares no virtual +// methods (it avoids the overhead of a virtual function +// pointer). But this doesn't matter, because +// PT(TransformState) is a template class, and will call +// the appropriate method even though it is non-virtual. +//////////////////////////////////////////////////////////////////// +bool RenderEffects:: +unref() const { + ReMutexHolder holder(*_states_lock); + + if (ReferenceCount::unref()) { + // The reference count is still nonzero. + return true; + } + + // The reference count has just reached zero. Make sure the object + // is removed from the global object pool, before anyone else finds + // it and tries to ref it. + ((RenderEffects *)this)->release_new(); + + return false; +} + //////////////////////////////////////////////////////////////////// // Function: RenderEffects::output // Access: Published, Virtual @@ -603,6 +636,26 @@ return_new(RenderEffects *state) { return *(result.first); } +//////////////////////////////////////////////////////////////////// +// Function: RenderEffects::release_new +// Access: Private +// Description: This inverse of return_new, this releases this object +// from the global RenderEffects table. +// +// You must already be holding _states_lock before you +// call this method. +//////////////////////////////////////////////////////////////////// +void RenderEffects:: +release_new() { + nassertv(_states_lock->debug_is_locked()); + + if (_saved_entry != _states->end()) { + nassertv(_states->find(this) == _saved_entry); + _states->erase(_saved_entry); + _saved_entry = _states->end(); + } +} + //////////////////////////////////////////////////////////////////// // Function: RenderEffects::determine_decal // Access: Private @@ -759,6 +812,28 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) { return pi; } +//////////////////////////////////////////////////////////////////// +// Function: RenderEffects::require_fully_complete +// Access: Public, Virtual +// Description: Some objects require all of their nested pointers to +// have been completed before the objects themselves can +// be completed. If this is the case, override this +// method to return true, and be careful with circular +// references (which would make the object unreadable +// from a bam file). +//////////////////////////////////////////////////////////////////// +bool RenderEffects:: +require_fully_complete() const { + // Since we sort _states based on each RenderEffects' operator < + // method, which in turn compares based on each nested RenderEffect + // object's compare_to() method, some of which depend on the + // RenderEffect's pointers having already been completed + // (e.g. CharacterJointEffect), we therefore require each of out our + // nested RenderEffect objects to have been completed before we can + // be completed. + return true; +} + //////////////////////////////////////////////////////////////////// // Function: RenderEffects::change_this // Access: Public, Static diff --git a/panda/src/pgraph/renderEffects.h b/panda/src/pgraph/renderEffects.h index de0b5ebae3..9f5a277d01 100644 --- a/panda/src/pgraph/renderEffects.h +++ b/panda/src/pgraph/renderEffects.h @@ -89,6 +89,8 @@ PUBLISHED: const RenderEffect *get_effect(TypeHandle type) const; + bool unref() const; + void output(ostream &out) const; void write(ostream &out, int indent_level) const; @@ -115,6 +117,8 @@ public: private: static CPT(RenderEffects) return_new(RenderEffects *state); + void release_new(); + void determine_decal(); void determine_show_bounds(); void determine_cull_callback(); @@ -174,6 +178,7 @@ public: static void register_with_read_factory(); virtual void write_datagram(BamWriter *manager, Datagram &dg); virtual int complete_pointers(TypedWritable **plist, BamReader *manager); + virtual bool require_fully_complete() const; static TypedWritable *change_this(TypedWritable *old_ptr, BamReader *manager); virtual void finalize(BamReader *manager); diff --git a/panda/src/pgraph/renderState.I b/panda/src/pgraph/renderState.I index e2a23cd4fe..8b92a1dd3d 100644 --- a/panda/src/pgraph/renderState.I +++ b/panda/src/pgraph/renderState.I @@ -103,11 +103,11 @@ INLINE bool RenderState:: cache_unref() const { #ifdef DO_PSTATS int old_referenced_bits = get_referenced_bits(); - bool result = NodeCachedReferenceCount::cache_unref(); + bool result = do_cache_unref(); consider_update_pstats(old_referenced_bits); return result; #else // DO_PSTATS - return NodeCachedReferenceCount::cache_unref(); + return do_cache_unref(); #endif // DO_PSTATS } @@ -136,11 +136,11 @@ INLINE bool RenderState:: node_unref() const { #ifdef DO_PSTATS int old_referenced_bits = get_referenced_bits(); - bool result = NodeCachedReferenceCount::node_unref(); + bool result = do_node_unref(); consider_update_pstats(old_referenced_bits); return result; #else // DO_PSTATS - return NodeCachedReferenceCount::node_unref(); + return do_node_unref(); #endif // DO_PSTATS } @@ -632,6 +632,31 @@ flush_level() { _cache_counter.flush_level(); } +//////////////////////////////////////////////////////////////////// +// Function: RenderState::do_node_unref +// Access: Private +// Description: Reimplements NodeReferenceCount::node_unref(). We do +// this because we have a non-virtual unref() method. +//////////////////////////////////////////////////////////////////// +INLINE bool RenderState:: +do_node_unref() const { + node_unref_only(); + return unref(); +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::do_cache_unref +// Access: Private +// Description: Reimplements +// CachedTypedWritableReferenceCount::cache_unref(). We +// do this because we have a non-virtual unref() method. +//////////////////////////////////////////////////////////////////// +INLINE bool RenderState:: +do_cache_unref() const { + cache_unref_only(); + return unref(); +} + //////////////////////////////////////////////////////////////////// // Function: RenderState::CompositionCycleDescEntry::Constructor // Access: Public diff --git a/panda/src/pgraph/renderState.cxx b/panda/src/pgraph/renderState.cxx index a20f2569ac..47a2436c7a 100644 --- a/panda/src/pgraph/renderState.cxx +++ b/panda/src/pgraph/renderState.cxx @@ -104,13 +104,10 @@ RenderState:: set_destructing(); ReMutexHolder holder(*_states_lock); - if (_saved_entry != _states->end()) { - nassertv(_states->find(this) == _saved_entry); - _states->erase(_saved_entry); - _saved_entry = _states->end(); - } - - remove_cache_pointers(); + + // unref() should have cleared these. + nassertv(_saved_entry == _states->end()); + nassertv(_composition_cache.empty() && _invert_composition_cache.empty()); // If this was true at the beginning of the destructor, but is no // longer true now, probably we've been double-deleted. @@ -627,46 +624,44 @@ 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. + // We always have to grab the lock, since we will definitely need to + // be holding it if we happen to drop the reference count to 0. + ReMutexHolder holder(*_states_lock); - // 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) { - - if (auto_break_cycles) { - ReMutexHolder holder(*_states_lock); + if (auto_break_cycles) { + if (get_cache_ref_count() > 0 && + get_ref_count() == get_cache_ref_count() + 1) { + // If we are about to remove the one reference that is not in the + // cache, leaving only references in the cache, then we need to + // check for a cycle involving this RenderState and break it if + // it exists. - if (get_cache_ref_count() > 0 && - get_ref_count() == get_cache_ref_count() + 1) { - // If we are about to remove the one reference that is not in the - // cache, leaving only references in the cache, then we need to - // check for a cycle involving this RenderState and break it if - // it exists. - - ++_last_cycle_detect; - if (r_detect_cycles(this, this, 1, _last_cycle_detect, NULL)) { - // Ok, we have a cycle. This will be a leak unless we break the - // cycle by freeing the cache on this object. - if (pgraph_cat.is_debug()) { - pgraph_cat.debug() - << "Breaking cycle involving " << (*this) << "\n"; - } - - ((RenderState *)this)->remove_cache_pointers(); + ++_last_cycle_detect; + if (r_detect_cycles(this, this, 1, _last_cycle_detect, NULL)) { + // Ok, we have a cycle. This will be a leak unless we break the + // cycle by freeing the cache on this object. + if (pgraph_cat.is_debug()) { + pgraph_cat.debug() + << "Breaking cycle involving " << (*this) << "\n"; } + + ((RenderState *)this)->remove_cache_pointers(); } } } - return ReferenceCount::unref(); + if (ReferenceCount::unref()) { + // The reference count is still nonzero. + return true; + } + + // The reference count has just reached zero. Make sure the object + // is removed from the global object pool, before anyone else finds + // it and tries to ref it. + ((RenderState *)this)->release_new(); + ((RenderState *)this)->remove_cache_pointers(); + + return false; } //////////////////////////////////////////////////////////////////// @@ -1371,6 +1366,26 @@ r_detect_cycles(const RenderState *start_state, return false; } +//////////////////////////////////////////////////////////////////// +// Function: RenderState::release_new +// Access: Private +// Description: This inverse of return_new, this releases this object +// from the global RenderState table. +// +// You must already be holding _states_lock before you +// call this method. +//////////////////////////////////////////////////////////////////// +void RenderState:: +release_new() { + nassertv(_states_lock->debug_is_locked()); + + if (_saved_entry != _states->end()) { + nassertv(_states->find(this) == _saved_entry); + _states->erase(_saved_entry); + _saved_entry = _states->end(); + } +} + //////////////////////////////////////////////////////////////////// // Function: RenderState::remove_cache_pointers // Access: Private diff --git a/panda/src/pgraph/renderState.h b/panda/src/pgraph/renderState.h index b818f643d3..9b1e047181 100644 --- a/panda/src/pgraph/renderState.h +++ b/panda/src/pgraph/renderState.h @@ -163,6 +163,9 @@ public: INLINE static void flush_level(); private: + INLINE bool do_cache_unref() const; + INLINE bool do_node_unref() const; + class CompositionCycleDescEntry { public: INLINE CompositionCycleDescEntry(const RenderState *obj, @@ -183,6 +186,7 @@ private: int length, UpdateSeq this_seq, CompositionCycleDesc *cycle_desc); + void release_new(); void remove_cache_pointers(); void determine_bin_index(); diff --git a/panda/src/pgraph/transformState.I b/panda/src/pgraph/transformState.I index 8b69b41f9e..366a12a909 100644 --- a/panda/src/pgraph/transformState.I +++ b/panda/src/pgraph/transformState.I @@ -733,11 +733,11 @@ INLINE bool TransformState:: cache_unref() const { #ifdef DO_PSTATS int old_referenced_bits = get_referenced_bits(); - bool result = NodeCachedReferenceCount::cache_unref(); + bool result = do_cache_unref(); consider_update_pstats(old_referenced_bits); return result; #else // DO_PSTATS - return NodeCachedReferenceCount::cache_unref(); + return do_cache_unref(); #endif // DO_PSTATS } @@ -766,11 +766,11 @@ INLINE bool TransformState:: node_unref() const { #ifdef DO_PSTATS int old_referenced_bits = get_referenced_bits(); - bool result = NodeCachedReferenceCount::node_unref(); + bool result = do_node_unref(); consider_update_pstats(old_referenced_bits); return result; #else // DO_PSTATS - return NodeCachedReferenceCount::node_unref(); + return do_node_unref(); #endif // DO_PSTATS } @@ -785,6 +785,31 @@ flush_level() { _cache_counter.flush_level(); } +//////////////////////////////////////////////////////////////////// +// Function: TransformState::do_node_unref +// Access: Private +// Description: Reimplements NodeReferenceCount::node_unref(). We do +// this because we have a non-virtual unref() method. +//////////////////////////////////////////////////////////////////// +INLINE bool TransformState:: +do_node_unref() const { + node_unref_only(); + return unref(); +} + +//////////////////////////////////////////////////////////////////// +// Function: TransformState::do_cache_unref +// Access: Private +// Description: Reimplements +// CachedTypedWritableReferenceCount::cache_unref(). We +// do this because we have a non-virtual unref() method. +//////////////////////////////////////////////////////////////////// +INLINE bool TransformState:: +do_cache_unref() const { + cache_unref_only(); + return unref(); +} + //////////////////////////////////////////////////////////////////// // Function: TransformState::check_hash // Access: Private diff --git a/panda/src/pgraph/transformState.cxx b/panda/src/pgraph/transformState.cxx index 2211004801..db70f68b0f 100644 --- a/panda/src/pgraph/transformState.cxx +++ b/panda/src/pgraph/transformState.cxx @@ -102,13 +102,10 @@ TransformState:: } ReMutexHolder holder(*_states_lock); - if (_saved_entry != _states->end()) { - nassertv(_states->find(this) == _saved_entry); - _states->erase(_saved_entry); - _saved_entry = _states->end(); - } - - remove_cache_pointers(); + + // unref() should have cleared these. + nassertv(_saved_entry == _states->end()); + nassertv(_composition_cache.empty() && _invert_composition_cache.empty()); // If this was true at the beginning of the destructor, but is no // longer true now, probably we've been double-deleted. @@ -765,48 +762,46 @@ 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. + // We always have to grab the lock, since we will definitely need to + // be holding it if we happen to drop the reference count to 0. + ReMutexHolder holder(*_states_lock); - // 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) { - - if (auto_break_cycles) { - ReMutexHolder holder(*_states_lock); + if (auto_break_cycles) { + if (get_cache_ref_count() > 0 && + get_ref_count() == get_cache_ref_count() + 1) { + // If we are about to remove the one reference that is not in the + // cache, leaving only references in the cache, then we need to + // check for a cycle involving this TransformState and break it if + // it exists. - if (get_cache_ref_count() > 0 && - get_ref_count() == get_cache_ref_count() + 1) { - // If we are about to remove the one reference that is not in the - // cache, leaving only references in the cache, then we need to - // check for a cycle involving this TransformState and break it if - // it exists. - - PStatTimer timer(_transform_break_cycles_pcollector); + PStatTimer timer(_transform_break_cycles_pcollector); - ++_last_cycle_detect; - if (r_detect_cycles(this, this, 1, _last_cycle_detect, NULL)) { - // Ok, we have a cycle. This will be a leak unless we break the - // cycle by freeing the cache on this object. - if (pgraph_cat.is_debug()) { - pgraph_cat.debug() - << "Breaking cycle involving " << (*this) << "\n"; - } - - ((TransformState *)this)->remove_cache_pointers(); + ++_last_cycle_detect; + if (r_detect_cycles(this, this, 1, _last_cycle_detect, NULL)) { + // Ok, we have a cycle. This will be a leak unless we break the + // cycle by freeing the cache on this object. + if (pgraph_cat.is_debug()) { + pgraph_cat.debug() + << "Breaking cycle involving " << (*this) << "\n"; } + + ((TransformState *)this)->remove_cache_pointers(); } } } - return ReferenceCount::unref(); + if (ReferenceCount::unref()) { + // The reference count is still nonzero. + return true; + } + + // The reference count has just reached zero. Make sure the object + // is removed from the global object pool, before anyone else finds + // it and tries to ref it. + ((TransformState *)this)->release_new(); + ((TransformState *)this)->remove_cache_pointers(); + + return false; } //////////////////////////////////////////////////////////////////// @@ -1592,6 +1587,27 @@ r_detect_cycles(const TransformState *start_state, return false; } + +//////////////////////////////////////////////////////////////////// +// Function: TransformState::release_new +// Access: Private +// Description: This inverse of return_new, this releases this object +// from the global TransformState table. +// +// You must already be holding _states_lock before you +// call this method. +//////////////////////////////////////////////////////////////////// +void TransformState:: +release_new() { + nassertv(_states_lock->debug_is_locked()); + + if (_saved_entry != _states->end()) { + nassertv(_states->find(this) == _saved_entry); + _states->erase(_saved_entry); + _saved_entry = _states->end(); + } +} + //////////////////////////////////////////////////////////////////// // Function: TransformState::remove_cache_pointers // Access: Private @@ -1606,7 +1622,7 @@ r_detect_cycles(const TransformState *start_state, void TransformState:: remove_cache_pointers() { nassertv(_states_lock->debug_is_locked()); - + // Fortunately, since we added CompositionCache records in pairs, we // know exactly the set of TransformState objects that have us in their // cache: it's the same set of TransformState objects that we have in diff --git a/panda/src/pgraph/transformState.h b/panda/src/pgraph/transformState.h index 59276c580e..080ed246e6 100644 --- a/panda/src/pgraph/transformState.h +++ b/panda/src/pgraph/transformState.h @@ -195,6 +195,9 @@ public: INLINE static void flush_level(); private: + INLINE bool do_cache_unref() const; + INLINE bool do_node_unref() const; + class CompositionCycleDescEntry { public: INLINE CompositionCycleDescEntry(const TransformState *obj, @@ -215,6 +218,7 @@ private: int length, UpdateSeq this_seq, CompositionCycleDesc *cycle_desc); + void release_new(); void remove_cache_pointers(); private: diff --git a/panda/src/putil/Sources.pp b/panda/src/putil/Sources.pp index f63225fe39..d928b30724 100644 --- a/panda/src/putil/Sources.pp +++ b/panda/src/putil/Sources.pp @@ -32,7 +32,6 @@ config_util.N config_util.h configurable.h \ datagramInputFile.I datagramInputFile.h \ datagramOutputFile.I datagramOutputFile.h \ - deferredDeletor.h \ doubleBitMask.I doubleBitMask.h \ drawMask.h \ factoryBase.I factoryBase.h \ @@ -52,11 +51,9 @@ modifierButtons.I modifierButtons.h mouseButton.h \ mouseData.I mouseData.h nameUniquifier.I nameUniquifier.h \ nodeCachedReferenceCount.h nodeCachedReferenceCount.I \ - nonDeletor.h \ portalMask.h \ pta_double.h \ pta_float.h pta_int.h \ - spamDeletor.h \ sparseArray.I sparseArray.h \ string_utils.I string_utils.N string_utils.h \ stringStreamBuf.I stringStreamBuf.h \ @@ -88,7 +85,6 @@ copyOnWritePointer.cxx \ config_util.cxx configurable.cxx \ datagramInputFile.cxx datagramOutputFile.cxx \ - deferredDeletor.cxx \ doubleBitMask.cxx \ factoryBase.cxx \ factoryParam.cxx factoryParams.cxx \ @@ -101,10 +97,8 @@ modifierButtons.cxx mouseButton.cxx mouseData.cxx \ nameUniquifier.cxx \ nodeCachedReferenceCount.cxx \ - nonDeletor.cxx \ pta_double.cxx pta_float.cxx \ pta_int.cxx pta_ushort.cxx \ - spamDeletor.cxx \ sparseArray.cxx \ string_utils.cxx \ stringStreamBuf.cxx \ @@ -140,7 +134,6 @@ config_util.h configurable.h factory.I factory.h \ datagramInputFile.I datagramInputFile.h \ datagramOutputFile.I datagramOutputFile.h \ - deferredDeletor.h \ doubleBitMask.I doubleBitMask.h \ drawMask.h \ factoryBase.I factoryBase.h factoryParam.I factoryParam.h \ @@ -160,11 +153,9 @@ modifierButtons.h mouseButton.h mouseData.I mouseData.h \ nameUniquifier.I nameUniquifier.h \ nodeCachedReferenceCount.h nodeCachedReferenceCount.I \ - nonDeletor.h \ portalMask.h \ pta_double.h \ pta_float.h pta_int.h pta_ushort.h \ - spamDeletor.h \ sparseArray.I sparseArray.h \ string_utils.I string_utils.h \ stringStreamBuf.I stringStreamBuf.h \ diff --git a/panda/src/putil/cachedTypedWritableReferenceCount.I b/panda/src/putil/cachedTypedWritableReferenceCount.I index 274115aa01..d77d3bde53 100644 --- a/panda/src/putil/cachedTypedWritableReferenceCount.I +++ b/panda/src/putil/cachedTypedWritableReferenceCount.I @@ -144,14 +144,8 @@ get_cache_ref_count() const { //////////////////////////////////////////////////////////////////// // Function: CachedTypedWritableReferenceCount::cache_ref // Access: Published -// Description: Explicitly increments the reference count. -// -// This function is const, even though it changes the -// object, because generally fiddling with an object's -// reference count isn't considered part of fiddling -// with the object. An object might be const in other -// ways, but we still need to accurately count the -// number of references to it. +// Description: Explicitly increments the cache reference count and +// the normal reference count simultaneously. //////////////////////////////////////////////////////////////////// INLINE void CachedTypedWritableReferenceCount:: cache_ref() const { @@ -166,25 +160,8 @@ cache_ref() const { //////////////////////////////////////////////////////////////////// // Function: CachedTypedWritableReferenceCount::cache_unref // Access: Published -// Description: Explicitly decrements the reference count. Note that -// the object will not be implicitly deleted by unref() -// simply because the reference count drops to zero. -// (Having a member function delete itself is -// problematic; plus, we don't have a virtual destructor -// anyway.) However, see the helper function -// unref_delete(). -// -// User code should avoid using ref() and unref() -// directly, which can result in missed reference -// counts. Instead, let a PointerTo object manage the -// reference counting automatically. -// -// This function is const, even though it changes the -// object, because generally fiddling with an object's -// reference count isn't considered part of fiddling -// with the object. An object might be const in other -// ways, but we still need to accurately count the -// number of references to it. +// Description: Explicitly decrements the cache reference count and +// the normal reference count simultaneously. // // The return value is true if the new reference count // is nonzero, false if it is zero. @@ -199,9 +176,9 @@ cache_unref() const { // zero reference count. Are you using ref() and unref() // directly? Are you sure you can't use PointerTo's? nassertr(_cache_ref_count > 0, 0); - - unref(); - return AtomicAdjust::dec(((CachedTypedWritableReferenceCount *)this)->_cache_ref_count); + + AtomicAdjust::dec(((CachedTypedWritableReferenceCount *)this)->_cache_ref_count); + return unref(); } //////////////////////////////////////////////////////////////////// @@ -219,6 +196,28 @@ test_ref_count_integrity() const { #endif } +//////////////////////////////////////////////////////////////////// +// Function: CachedTypedWritableReferenceCount::cache_unref_only +// Access: Protected +// Description: Decrements the cache reference count without affecting +// the normal reference count. Intended to be called by +// derived classes only, presumably to reimplement +// cache_unref(). +//////////////////////////////////////////////////////////////////// +INLINE void CachedTypedWritableReferenceCount:: +cache_unref_only() const { +#ifdef _DEBUG + nassertv(test_ref_count_integrity()); +#endif + + // If this assertion fails, you tried to unref an object with a + // zero reference count. Are you using ref() and unref() + // directly? Are you sure you can't use PointerTo's? + nassertv(_cache_ref_count > 0); + + AtomicAdjust::dec(((CachedTypedWritableReferenceCount *)this)->_cache_ref_count); +} + //////////////////////////////////////////////////////////////////// // Function: cache_unref_delete // Description: This global helper function will unref the given @@ -232,14 +231,7 @@ test_ref_count_integrity() const { template INLINE void cache_unref_delete(RefCountType *ptr) { - ptr->cache_unref(); - if (ptr->get_ref_count() == 0) { - ObjectDeletor *deletor = ObjectDeletor::get_global_ptr(); - if (deletor != (ObjectDeletor *)NULL) { - ptr->ref(); - deletor->delete_object(RefCountDeleteWrapper::do_delete, (void *)ptr); - return; - } + if (!ptr->cache_unref()) { delete ptr; } } diff --git a/panda/src/putil/cachedTypedWritableReferenceCount.h b/panda/src/putil/cachedTypedWritableReferenceCount.h index 2d561fd2d5..1ae7370f38 100644 --- a/panda/src/putil/cachedTypedWritableReferenceCount.h +++ b/panda/src/putil/cachedTypedWritableReferenceCount.h @@ -56,6 +56,7 @@ PUBLISHED: INLINE bool test_ref_count_integrity() const; protected: + INLINE void cache_unref_only() const; bool do_test_ref_count_integrity() const; private: diff --git a/panda/src/putil/config_util.cxx b/panda/src/putil/config_util.cxx index 02001beefb..9cc51d02c1 100644 --- a/panda/src/putil/config_util.cxx +++ b/panda/src/putil/config_util.cxx @@ -44,9 +44,6 @@ #include "writableParam.h" #include "keyboardButton.h" #include "mouseButton.h" -#include "deferredDeletor.h" -#include "nonDeletor.h" -#include "spamDeletor.h" #include "dconfig.h" @@ -179,10 +176,6 @@ init_libputil() { KeyboardButton::init_keyboard_buttons(); MouseButton::init_mouse_buttons(); - DeferredDeletor::register_deletor(); - NonDeletor::register_deletor(); - SpamDeletor::register_deletor(); - register_type(BamReader::_remove_flag, "remove"); BamCacheIndex::register_with_read_factory(); diff --git a/panda/src/putil/deferredDeletor.cxx b/panda/src/putil/deferredDeletor.cxx deleted file mode 100644 index 1ce13f3707..0000000000 --- a/panda/src/putil/deferredDeletor.cxx +++ /dev/null @@ -1,76 +0,0 @@ -// 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); - if (util_cat.is_spam()) { - util_cat.spam() - << "Deferring deleting pointer " << ptr << "\n"; - } - _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() { - Tokens new_tokens; - { - MutexHolder holder(_lock); - _tokens.swap(new_tokens); - } - - Tokens::iterator ti; - for (ti = new_tokens.begin(); ti != new_tokens.end(); ++ti) { - (*ti).do_delete(); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: DeferredDeletor::register_deletor -// Access: Public, Static -// Description: Registers this deletor with the global pool. -//////////////////////////////////////////////////////////////////// -void DeferredDeletor:: -register_deletor() { - register_subclass(new DeferredDeletor, "deferred"); -} diff --git a/panda/src/putil/deferredDeletor.h b/panda/src/putil/deferredDeletor.h deleted file mode 100644 index 40fff034ae..0000000000 --- a/panda/src/putil/deferredDeletor.h +++ /dev/null @@ -1,48 +0,0 @@ -// 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_PANDA DeferredDeletor : public ObjectDeletor { -public: - DeferredDeletor(); - - virtual void delete_object(DeleteFunc *func, void *ptr); - virtual void flush(); - - static void register_deletor(); - -private: - typedef pvector Tokens; - Tokens _tokens; - Mutex _lock; -}; - -#endif diff --git a/panda/src/putil/nodeCachedReferenceCount.I b/panda/src/putil/nodeCachedReferenceCount.I index 682c933eb0..567dabf158 100644 --- a/panda/src/putil/nodeCachedReferenceCount.I +++ b/panda/src/putil/nodeCachedReferenceCount.I @@ -166,42 +166,16 @@ node_ref() const { //////////////////////////////////////////////////////////////////// // Function: NodeCachedReferenceCount::node_unref // Access: Published -// Description: Explicitly decrements the reference count. Note that -// the object will not be implicitly deleted by unref() -// simply because the reference count drops to zero. -// (Having a member function delete itself is -// problematic; plus, we don't have a virtual destructor -// anyway.) However, see the helper function -// unref_delete(). -// -// User code should avoid using ref() and unref() -// directly, which can result in missed reference -// counts. Instead, let a PointerTo object manage the -// reference counting automatically. -// -// This function is const, even though it changes the -// object, because generally fiddling with an object's -// reference count isn't considered part of fiddling -// with the object. An object might be const in other -// ways, but we still need to accurately count the -// number of references to it. +// Description: Explicitly decrements the node reference count and +// the normal reference count simultaneously. // // The return value is true if the new reference count // is nonzero, false if it is zero. //////////////////////////////////////////////////////////////////// INLINE bool NodeCachedReferenceCount:: node_unref() const { -#ifdef _DEBUG - nassertr(test_ref_count_integrity(), 0); -#endif - - // If this assertion fails, you tried to unref an object with a - // zero reference count. Are you using ref() and unref() - // directly? Are you sure you can't use PointerTo's? - nassertr(_node_ref_count > 0, 0); - - unref(); - return AtomicAdjust::dec(((NodeCachedReferenceCount *)this)->_node_ref_count); + node_unref_only(); + return unref(); } //////////////////////////////////////////////////////////////////// @@ -242,3 +216,25 @@ get_referenced_bits() const { return result; } + +//////////////////////////////////////////////////////////////////// +// Function: NodeCachedReferenceCount::node_unref_only +// Access: Protected +// Description: Decrements the node reference count without affecting +// the normal reference count. Intended to be called by +// derived classes only, presumably to reimplement +// node_unref(). +//////////////////////////////////////////////////////////////////// +INLINE void NodeCachedReferenceCount:: +node_unref_only() const { +#ifdef _DEBUG + nassertv(test_ref_count_integrity()); +#endif + + // If this assertion fails, you tried to unref an object with a + // zero reference count. Are you using ref() and unref() + // directly? Are you sure you can't use PointerTo's? + nassertv(_node_ref_count > 0); + + AtomicAdjust::dec(((NodeCachedReferenceCount *)this)->_node_ref_count); +} diff --git a/panda/src/putil/nodeCachedReferenceCount.h b/panda/src/putil/nodeCachedReferenceCount.h index 5f0614ffdc..06601d90a8 100644 --- a/panda/src/putil/nodeCachedReferenceCount.h +++ b/panda/src/putil/nodeCachedReferenceCount.h @@ -84,6 +84,7 @@ PUBLISHED: INLINE int get_referenced_bits() const; protected: + INLINE void node_unref_only() const; bool do_test_ref_count_integrity() const; private: diff --git a/panda/src/putil/nonDeletor.cxx b/panda/src/putil/nonDeletor.cxx deleted file mode 100644 index 9e60c4d33e..0000000000 --- a/panda/src/putil/nonDeletor.cxx +++ /dev/null @@ -1,44 +0,0 @@ -// 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"); -} diff --git a/panda/src/putil/nonDeletor.h b/panda/src/putil/nonDeletor.h deleted file mode 100644 index fb7c3ca797..0000000000 --- a/panda/src/putil/nonDeletor.h +++ /dev/null @@ -1,40 +0,0 @@ -// 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_PANDA NonDeletor : public ObjectDeletor { -public: - virtual void delete_object(DeleteFunc *func, void *ptr); - - static void register_deletor(); -}; - -#endif diff --git a/panda/src/putil/putil_composite1.cxx b/panda/src/putil/putil_composite1.cxx index 6cb85d3009..2f984154bc 100644 --- a/panda/src/putil/putil_composite1.cxx +++ b/panda/src/putil/putil_composite1.cxx @@ -19,7 +19,6 @@ #include "copyOnWritePointer.cxx" #include "datagramInputFile.cxx" #include "datagramOutputFile.cxx" -#include "deferredDeletor.cxx" #include "doubleBitMask.cxx" #include "factoryBase.cxx" #include "factoryParam.cxx" diff --git a/panda/src/putil/putil_composite2.cxx b/panda/src/putil/putil_composite2.cxx index 97befe1b1a..b9f935e82d 100644 --- a/panda/src/putil/putil_composite2.cxx +++ b/panda/src/putil/putil_composite2.cxx @@ -8,12 +8,10 @@ #include "mouseData.cxx" #include "nameUniquifier.cxx" #include "nodeCachedReferenceCount.cxx" -#include "nonDeletor.cxx" #include "pta_double.cxx" #include "pta_float.cxx" #include "pta_int.cxx" #include "pta_ushort.cxx" -#include "spamDeletor.cxx" #include "sparseArray.cxx" #include "string_utils.cxx" #include "stringStreamBuf.cxx" diff --git a/panda/src/putil/spamDeletor.cxx b/panda/src/putil/spamDeletor.cxx deleted file mode 100644 index c347cf31bb..0000000000 --- a/panda/src/putil/spamDeletor.cxx +++ /dev/null @@ -1,45 +0,0 @@ -// Filename: spamDeletor.cxx -// Created by: drose (11Apr07) -// -//////////////////////////////////////////////////////////////////// -// -// 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 "spamDeletor.h" -#include "config_util.h" - -//////////////////////////////////////////////////////////////////// -// Function: SpamDeletor::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 SpamDeletor:: -delete_object(DeleteFunc *func, void *ptr) { - if (util_cat.is_spam()) { - util_cat.spam() - << "Deleting pointer " << ptr << "\n"; - } - (*func)(ptr); -} - -//////////////////////////////////////////////////////////////////// -// Function: SpamDeletor::register_deletor -// Access: Public, Static -// Description: Registers this deletor with the global pool. -//////////////////////////////////////////////////////////////////// -void SpamDeletor:: -register_deletor() { - register_subclass(new SpamDeletor, "spam"); -} diff --git a/panda/src/putil/spamDeletor.h b/panda/src/putil/spamDeletor.h deleted file mode 100644 index 5808488215..0000000000 --- a/panda/src/putil/spamDeletor.h +++ /dev/null @@ -1,39 +0,0 @@ -// Filename: spamDeletor.h -// Created by: drose (11Apr07) -// -//////////////////////////////////////////////////////////////////// -// -// 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 SPAMDELETOR_H -#define SPAMDELETOR_H - -#include "pandabase.h" -#include "objectDeletor.h" - -//////////////////////////////////////////////////////////////////// -// Class : SpamDeletor -// Description : The only purpose of the SpamDeletor is to issue a -// spam Notify message as each object is deleted. Maybe -// it will be useful to track down accidental deletions -// due to PT mismanagement. -//////////////////////////////////////////////////////////////////// -class EXPCL_PANDA SpamDeletor : public ObjectDeletor { -public: - virtual void delete_object(DeleteFunc *func, void *ptr); - - static void register_deletor(); -}; - -#endif