mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 10:54:24 -04:00
better thread protection in reference counts, esp. TransformState etc.
This commit is contained in:
parent
e2bfe71e05
commit
68cd3322a9
@ -51,6 +51,9 @@
|
|||||||
|
|
||||||
#define USE_DL_PREFIX 1
|
#define USE_DL_PREFIX 1
|
||||||
#define NO_MALLINFO 1
|
#define NO_MALLINFO 1
|
||||||
|
#ifdef _DEBUG
|
||||||
|
#define DEBUG
|
||||||
|
#endif
|
||||||
#include "dlmalloc.h"
|
#include "dlmalloc.h"
|
||||||
#include "dlmalloc_src.cxx"
|
#include "dlmalloc_src.cxx"
|
||||||
|
|
||||||
@ -77,6 +80,9 @@
|
|||||||
|
|
||||||
#define USE_DL_PREFIX 1
|
#define USE_DL_PREFIX 1
|
||||||
#define NO_MALLINFO 1
|
#define NO_MALLINFO 1
|
||||||
|
#ifdef _DEBUG
|
||||||
|
#define MALLOC_DEBUG 2
|
||||||
|
#endif
|
||||||
#include "ptmalloc2_smp_src.cxx"
|
#include "ptmalloc2_smp_src.cxx"
|
||||||
|
|
||||||
#define call_malloc dlmalloc
|
#define call_malloc dlmalloc
|
||||||
|
@ -175,6 +175,15 @@ GraphicsEngine::
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void GraphicsEngine::
|
void GraphicsEngine::
|
||||||
set_threading_model(const GraphicsThreadingModel &threading_model) {
|
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
|
#ifndef THREADED_PIPELINE
|
||||||
if (!threading_model.is_single_threaded()) {
|
if (!threading_model.is_single_threaded()) {
|
||||||
display_cat.warning()
|
display_cat.warning()
|
||||||
@ -688,14 +697,6 @@ render_frame() {
|
|||||||
|
|
||||||
#endif // THREADED_PIPELINE && DO_PSTATS
|
#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();
|
GeomCacheManager::flush_level();
|
||||||
CullTraverser::flush_level();
|
CullTraverser::flush_level();
|
||||||
RenderState::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);
|
thread->set_min_pipeline_stage(pipeline_stage);
|
||||||
_pipeline->set_min_stages(pipeline_stage + 1);
|
_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;
|
_threads[name] = thread;
|
||||||
|
|
||||||
nassertr(thread->get_pipeline_stage() < _pipeline->get_num_stages(), thread.p());
|
nassertr(thread->get_pipeline_stage() < _pipeline->get_num_stages(), thread.p());
|
||||||
|
@ -32,7 +32,6 @@
|
|||||||
nodePointerToBase.h nodePointerToBase.I \
|
nodePointerToBase.h nodePointerToBase.I \
|
||||||
nodePointerTo.h nodePointerTo.I \
|
nodePointerTo.h nodePointerTo.I \
|
||||||
nodeReferenceCount.h nodeReferenceCount.I \
|
nodeReferenceCount.h nodeReferenceCount.I \
|
||||||
objectDeletor.h objectDeletor.I \
|
|
||||||
ordered_vector.h ordered_vector.I ordered_vector.T \
|
ordered_vector.h ordered_vector.I ordered_vector.T \
|
||||||
password_hash.h \
|
password_hash.h \
|
||||||
patchfile.I patchfile.h \
|
patchfile.I patchfile.h \
|
||||||
@ -84,7 +83,6 @@
|
|||||||
nodePointerToBase.cxx \
|
nodePointerToBase.cxx \
|
||||||
nodePointerTo.cxx \
|
nodePointerTo.cxx \
|
||||||
nodeReferenceCount.cxx \
|
nodeReferenceCount.cxx \
|
||||||
objectDeletor.cxx \
|
|
||||||
ordered_vector.cxx \
|
ordered_vector.cxx \
|
||||||
password_hash.cxx \
|
password_hash.cxx \
|
||||||
patchfile.cxx \
|
patchfile.cxx \
|
||||||
@ -142,7 +140,6 @@
|
|||||||
nodePointerToBase.h nodePointerToBase.I \
|
nodePointerToBase.h nodePointerToBase.I \
|
||||||
nodePointerTo.h nodePointerTo.I \
|
nodePointerTo.h nodePointerTo.I \
|
||||||
nodeReferenceCount.h nodeReferenceCount.I \
|
nodeReferenceCount.h nodeReferenceCount.I \
|
||||||
objectDeletor.h objectDeletor.I \
|
|
||||||
ordered_vector.h ordered_vector.I ordered_vector.T \
|
ordered_vector.h ordered_vector.I ordered_vector.T \
|
||||||
password_hash.h \
|
password_hash.h \
|
||||||
patchfile.I patchfile.h \
|
patchfile.I patchfile.h \
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
#include "nodePointerToBase.cxx"
|
#include "nodePointerToBase.cxx"
|
||||||
#include "nodePointerTo.cxx"
|
#include "nodePointerTo.cxx"
|
||||||
#include "nodeReferenceCount.cxx"
|
#include "nodeReferenceCount.cxx"
|
||||||
#include "objectDeletor.cxx"
|
|
||||||
#include "ordered_vector.cxx"
|
#include "ordered_vector.cxx"
|
||||||
#include "patchfile.cxx"
|
#include "patchfile.cxx"
|
||||||
#include "password_hash.cxx"
|
#include "password_hash.cxx"
|
||||||
|
@ -147,14 +147,8 @@ get_node_ref_count() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: NodeReferenceCount::node_ref
|
// Function: NodeReferenceCount::node_ref
|
||||||
// Access: Published
|
// Access: Published
|
||||||
// Description: Explicitly increments the reference count.
|
// Description: Explicitly increments the node reference count and
|
||||||
//
|
// the normal reference count simultaneously.
|
||||||
// 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.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
INLINE void NodeReferenceCount::
|
INLINE void NodeReferenceCount::
|
||||||
node_ref() const {
|
node_ref() const {
|
||||||
@ -169,42 +163,16 @@ node_ref() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: NodeReferenceCount::node_unref
|
// Function: NodeReferenceCount::node_unref
|
||||||
// Access: Published
|
// Access: Published
|
||||||
// Description: Explicitly decrements the reference count. Note that
|
// Description: Explicitly decrements the node reference count and
|
||||||
// the object will not be implicitly deleted by unref()
|
// the normal reference count simultaneously.
|
||||||
// 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.
|
|
||||||
//
|
//
|
||||||
// The return value is true if the new reference count
|
// The return value is true if the new reference count
|
||||||
// is nonzero, false if it is zero.
|
// is nonzero, false if it is zero.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
INLINE bool NodeReferenceCount::
|
INLINE bool NodeReferenceCount::
|
||||||
node_unref() const {
|
node_unref() const {
|
||||||
#ifdef _DEBUG
|
node_unref_only();
|
||||||
nassertr(test_ref_count_integrity(), 0);
|
return unref();
|
||||||
#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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -222,6 +190,28 @@ test_ref_count_integrity() const {
|
|||||||
#endif
|
#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
|
// Function: node_unref_delete
|
||||||
// Description: This global helper function will unref the given
|
// Description: This global helper function will unref the given
|
||||||
@ -235,15 +225,7 @@ test_ref_count_integrity() const {
|
|||||||
template<class RefCountType>
|
template<class RefCountType>
|
||||||
INLINE void
|
INLINE void
|
||||||
node_unref_delete(RefCountType *ptr) {
|
node_unref_delete(RefCountType *ptr) {
|
||||||
ptr->node_unref();
|
if (!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<RefCountType>::do_delete, (void *)ptr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete ptr;
|
delete ptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,8 @@ PUBLISHED:
|
|||||||
INLINE bool test_ref_count_integrity() const;
|
INLINE bool test_ref_count_integrity() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
INLINE void node_unref_only() const;
|
||||||
|
|
||||||
bool do_test_ref_count_integrity() const;
|
bool do_test_ref_count_integrity() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -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);
|
|
||||||
}
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
|
|
@ -348,41 +348,6 @@ weak_unref(WeakPointerToVoid *ptv) {
|
|||||||
_weak_list->clear_reference(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
|
// Function: unref_delete
|
||||||
// Description: This global helper function will unref the given
|
// Description: This global helper function will unref the given
|
||||||
@ -404,59 +369,11 @@ unref_delete(RefCountType *ptr) {
|
|||||||
// overloading of the unref() method.
|
// overloading of the unref() method.
|
||||||
|
|
||||||
if (!ptr->unref()) {
|
if (!ptr->unref()) {
|
||||||
// The reference count has reached 0; time to delete the pointer.
|
// If the reference count has gone to zero, delete the object.
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there's no deletor, just delete the pointer now.
|
|
||||||
delete ptr;
|
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
|
// Function: RefCountProxy::Constructor
|
||||||
// Access: Public
|
// Access: Public
|
||||||
|
@ -105,24 +105,9 @@ private:
|
|||||||
static TypeHandle _type_handle;
|
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>
|
template<class RefCountType>
|
||||||
INLINE void unref_delete(RefCountType *ptr);
|
INLINE void unref_delete(RefCountType *ptr);
|
||||||
|
|
||||||
template<class ObjectType>
|
|
||||||
INLINE void defer_delete(ObjectType *ptr);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Class : RefCountProxy
|
// Class : RefCountProxy
|
||||||
// Description : A "proxy" to use to make a reference-countable object
|
// Description : A "proxy" to use to make a reference-countable object
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "bamReader.h"
|
#include "bamReader.h"
|
||||||
#include "bamWriter.h"
|
#include "bamWriter.h"
|
||||||
#include "indirectLess.h"
|
#include "indirectLess.h"
|
||||||
|
#include "mutexHolder.h"
|
||||||
|
|
||||||
GeomVertexArrayFormat::Registry *GeomVertexArrayFormat::_registry = NULL;
|
GeomVertexArrayFormat::Registry *GeomVertexArrayFormat::_registry = NULL;
|
||||||
TypeHandle GeomVertexArrayFormat::_type_handle;
|
TypeHandle GeomVertexArrayFormat::_type_handle;
|
||||||
@ -186,15 +187,38 @@ operator = (const GeomVertexArrayFormat ©) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
GeomVertexArrayFormat::
|
GeomVertexArrayFormat::
|
||||||
~GeomVertexArrayFormat() {
|
~GeomVertexArrayFormat() {
|
||||||
if (is_registered()) {
|
// unref() should have unregistered us.
|
||||||
get_registry()->unregister_format(this);
|
nassertv(!is_registered());
|
||||||
}
|
|
||||||
Columns::iterator ci;
|
Columns::iterator ci;
|
||||||
for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
|
for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
|
||||||
delete (*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
|
// Function: GeomVertexArrayFormat::add_column
|
||||||
// Access: Published
|
// Access: Published
|
||||||
@ -759,12 +783,15 @@ register_format(GeomVertexArrayFormat *format) {
|
|||||||
// a zero reference count and is not added into the map below, it
|
// a zero reference count and is not added into the map below, it
|
||||||
// will be automatically deleted when this function returns.
|
// will be automatically deleted when this function returns.
|
||||||
PT(GeomVertexArrayFormat) pt_format = format;
|
PT(GeomVertexArrayFormat) pt_format = format;
|
||||||
|
|
||||||
ArrayFormats::iterator fi = _formats.insert(format).first;
|
GeomVertexArrayFormat *new_format;
|
||||||
|
{
|
||||||
GeomVertexArrayFormat *new_format = (*fi);
|
MutexHolder holder(_lock);
|
||||||
if (!new_format->is_registered()) {
|
ArrayFormats::iterator fi = _formats.insert(format).first;
|
||||||
new_format->do_register();
|
new_format = (*fi);
|
||||||
|
if (!new_format->is_registered()) {
|
||||||
|
new_format->do_register();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new_format;
|
return new_format;
|
||||||
@ -776,6 +803,8 @@ register_format(GeomVertexArrayFormat *format) {
|
|||||||
// Description: Removes the indicated format from the registry.
|
// Description: Removes the indicated format from the registry.
|
||||||
// Normally this should not be done until the format is
|
// Normally this should not be done until the format is
|
||||||
// destructing.
|
// destructing.
|
||||||
|
//
|
||||||
|
// The lock should be held prior to calling this method.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void GeomVertexArrayFormat::Registry::
|
void GeomVertexArrayFormat::Registry::
|
||||||
unregister_format(GeomVertexArrayFormat *format) {
|
unregister_format(GeomVertexArrayFormat *format) {
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "indirectCompareTo.h"
|
#include "indirectCompareTo.h"
|
||||||
#include "pvector.h"
|
#include "pvector.h"
|
||||||
#include "pmap.h"
|
#include "pmap.h"
|
||||||
|
#include "pmutex.h"
|
||||||
|
|
||||||
class GeomVertexFormat;
|
class GeomVertexFormat;
|
||||||
class GeomVertexData;
|
class GeomVertexData;
|
||||||
@ -80,6 +81,8 @@ PUBLISHED:
|
|||||||
void operator = (const GeomVertexArrayFormat ©);
|
void operator = (const GeomVertexArrayFormat ©);
|
||||||
~GeomVertexArrayFormat();
|
~GeomVertexArrayFormat();
|
||||||
|
|
||||||
|
bool unref() const;
|
||||||
|
|
||||||
INLINE bool is_registered() const;
|
INLINE bool is_registered() const;
|
||||||
INLINE static CPT(GeomVertexArrayFormat) register_format(const GeomVertexArrayFormat *format);
|
INLINE static CPT(GeomVertexArrayFormat) register_format(const GeomVertexArrayFormat *format);
|
||||||
|
|
||||||
@ -147,6 +150,7 @@ private:
|
|||||||
void unregister_format(GeomVertexArrayFormat *format);
|
void unregister_format(GeomVertexArrayFormat *format);
|
||||||
|
|
||||||
ArrayFormats _formats;
|
ArrayFormats _formats;
|
||||||
|
Mutex _lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
static Registry *_registry;
|
static Registry *_registry;
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
#include "geomVertexFormat.h"
|
#include "geomVertexFormat.h"
|
||||||
#include "geomVertexData.h"
|
#include "geomVertexData.h"
|
||||||
#include "geomMunger.h"
|
#include "geomMunger.h"
|
||||||
#include "mutexHolder.h"
|
#include "reMutexHolder.h"
|
||||||
#include "indent.h"
|
#include "indent.h"
|
||||||
#include "bamReader.h"
|
#include "bamReader.h"
|
||||||
#include "bamWriter.h"
|
#include "bamWriter.h"
|
||||||
@ -86,9 +86,31 @@ operator = (const GeomVertexFormat ©) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
GeomVertexFormat::
|
GeomVertexFormat::
|
||||||
~GeomVertexFormat() {
|
~GeomVertexFormat() {
|
||||||
if (is_registered()) {
|
// unref() should have unregistered us.
|
||||||
get_registry()->unregister_format(this);
|
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() {
|
make_registry() {
|
||||||
if (_registry == (Registry *)NULL) {
|
if (_registry == (Registry *)NULL) {
|
||||||
_registry = new Registry;
|
_registry = new Registry;
|
||||||
|
_registry->make_standard_formats();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -897,6 +920,15 @@ fillin(DatagramIterator &scan, BamReader *manager) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
GeomVertexFormat::Registry::
|
GeomVertexFormat::Registry::
|
||||||
Registry() {
|
Registry() {
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: GeomVertexFormat::Registry::make_standard_formats
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void GeomVertexFormat::Registry::
|
||||||
|
make_standard_formats() {
|
||||||
_v3 = register_format(new GeomVertexArrayFormat
|
_v3 = register_format(new GeomVertexArrayFormat
|
||||||
(InternalName::get_vertex(), 3,
|
(InternalName::get_vertex(), 3,
|
||||||
NT_float32, C_point));
|
NT_float32, C_point));
|
||||||
@ -1016,11 +1048,14 @@ register_format(GeomVertexFormat *format) {
|
|||||||
// will be automatically deleted when this function returns.
|
// will be automatically deleted when this function returns.
|
||||||
PT(GeomVertexFormat) pt_format = format;
|
PT(GeomVertexFormat) pt_format = format;
|
||||||
|
|
||||||
Formats::iterator fi = _formats.insert(format).first;
|
GeomVertexFormat *new_format;
|
||||||
|
{
|
||||||
GeomVertexFormat *new_format = (*fi);
|
ReMutexHolder holder(_lock);
|
||||||
if (!new_format->is_registered()) {
|
Formats::iterator fi = _formats.insert(format).first;
|
||||||
new_format->do_register();
|
new_format = (*fi);
|
||||||
|
if (!new_format->is_registered()) {
|
||||||
|
new_format->do_register();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new_format;
|
return new_format;
|
||||||
@ -1032,6 +1067,8 @@ register_format(GeomVertexFormat *format) {
|
|||||||
// Description: Removes the indicated format from the registry.
|
// Description: Removes the indicated format from the registry.
|
||||||
// Normally this should not be done until the format is
|
// Normally this should not be done until the format is
|
||||||
// destructing.
|
// destructing.
|
||||||
|
//
|
||||||
|
// The lock should be held prior to calling this method.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void GeomVertexFormat::Registry::
|
void GeomVertexFormat::Registry::
|
||||||
unregister_format(GeomVertexFormat *format) {
|
unregister_format(GeomVertexFormat *format) {
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
#include "pset.h"
|
#include "pset.h"
|
||||||
#include "pvector.h"
|
#include "pvector.h"
|
||||||
#include "indirectCompareTo.h"
|
#include "indirectCompareTo.h"
|
||||||
#include "pmutex.h"
|
#include "reMutex.h"
|
||||||
|
|
||||||
class FactoryParams;
|
class FactoryParams;
|
||||||
class GeomVertexData;
|
class GeomVertexData;
|
||||||
@ -70,6 +70,8 @@ PUBLISHED:
|
|||||||
void operator = (const GeomVertexFormat ©);
|
void operator = (const GeomVertexFormat ©);
|
||||||
virtual ~GeomVertexFormat();
|
virtual ~GeomVertexFormat();
|
||||||
|
|
||||||
|
bool unref() const;
|
||||||
|
|
||||||
INLINE bool is_registered() const;
|
INLINE bool is_registered() const;
|
||||||
INLINE static CPT(GeomVertexFormat) register_format(const GeomVertexFormat *format);
|
INLINE static CPT(GeomVertexFormat) register_format(const GeomVertexFormat *format);
|
||||||
INLINE static CPT(GeomVertexFormat) register_format(const GeomVertexArrayFormat *format);
|
INLINE static CPT(GeomVertexFormat) register_format(const GeomVertexArrayFormat *format);
|
||||||
@ -213,11 +215,14 @@ private:
|
|||||||
class EXPCL_PANDA Registry {
|
class EXPCL_PANDA Registry {
|
||||||
public:
|
public:
|
||||||
Registry();
|
Registry();
|
||||||
|
void make_standard_formats();
|
||||||
|
|
||||||
CPT(GeomVertexFormat) register_format(GeomVertexFormat *format);
|
CPT(GeomVertexFormat) register_format(GeomVertexFormat *format);
|
||||||
INLINE CPT(GeomVertexFormat) register_format(GeomVertexArrayFormat *format);
|
INLINE CPT(GeomVertexFormat) register_format(GeomVertexArrayFormat *format);
|
||||||
void unregister_format(GeomVertexFormat *format);
|
void unregister_format(GeomVertexFormat *format);
|
||||||
|
|
||||||
Formats _formats;
|
Formats _formats;
|
||||||
|
ReMutex _lock;
|
||||||
|
|
||||||
CPT(GeomVertexFormat) _v3;
|
CPT(GeomVertexFormat) _v3;
|
||||||
CPT(GeomVertexFormat) _v3n3;
|
CPT(GeomVertexFormat) _v3n3;
|
||||||
|
@ -66,11 +66,44 @@ InternalName(InternalName *parent, const string &basename) :
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
InternalName::
|
InternalName::
|
||||||
~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);
|
NameTable::iterator ni = _parent->_name_table.find(_basename);
|
||||||
nassertv(ni != _parent->_name_table.end());
|
nassertv(ni == _parent->_name_table.end());
|
||||||
_parent->_name_table.erase(ni);
|
|
||||||
}
|
}
|
||||||
|
#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));
|
return append(name.substr(0, dot))->append(name.substr(dot + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MutexHolder holder(_name_table_lock);
|
||||||
|
|
||||||
NameTable::iterator ni = _name_table.find(name);
|
NameTable::iterator ni = _name_table.find(name);
|
||||||
if (ni != _name_table.end()) {
|
if (ni != _name_table.end()) {
|
||||||
return (*ni).second;
|
return (*ni).second;
|
||||||
}
|
}
|
||||||
|
|
||||||
PT(InternalName) internal_name = new InternalName(this, name);
|
InternalName *internal_name = new InternalName(this, name);
|
||||||
_name_table[name] = internal_name;
|
_name_table[name] = internal_name;
|
||||||
return internal_name;
|
return internal_name;
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "typedWritableReferenceCount.h"
|
#include "typedWritableReferenceCount.h"
|
||||||
#include "pointerTo.h"
|
#include "pointerTo.h"
|
||||||
#include "pmap.h"
|
#include "pmap.h"
|
||||||
|
#include "pmutex.h"
|
||||||
|
|
||||||
class FactoryParams;
|
class FactoryParams;
|
||||||
|
|
||||||
@ -48,6 +49,8 @@ private:
|
|||||||
|
|
||||||
PUBLISHED:
|
PUBLISHED:
|
||||||
virtual ~InternalName();
|
virtual ~InternalName();
|
||||||
|
bool unref() const;
|
||||||
|
|
||||||
INLINE static PT(InternalName) make(const string &name);
|
INLINE static PT(InternalName) make(const string &name);
|
||||||
PT(InternalName) append(const string &basename);
|
PT(InternalName) append(const string &basename);
|
||||||
|
|
||||||
@ -93,6 +96,7 @@ private:
|
|||||||
|
|
||||||
typedef phash_map<string, InternalName *, string_hash> NameTable;
|
typedef phash_map<string, InternalName *, string_hash> NameTable;
|
||||||
NameTable _name_table;
|
NameTable _name_table;
|
||||||
|
Mutex _name_table_lock;
|
||||||
|
|
||||||
static PT(InternalName) _root;
|
static PT(InternalName) _root;
|
||||||
static PT(InternalName) _error;
|
static PT(InternalName) _error;
|
||||||
|
@ -21,7 +21,9 @@
|
|||||||
#include "bamReader.h"
|
#include "bamReader.h"
|
||||||
#include "indent.h"
|
#include "indent.h"
|
||||||
#include "config_pgraph.h"
|
#include "config_pgraph.h"
|
||||||
|
#include "reMutexHolder.h"
|
||||||
|
|
||||||
|
ReMutex *RenderAttrib::_attribs_lock = NULL;
|
||||||
RenderAttrib::Attribs *RenderAttrib::_attribs = NULL;
|
RenderAttrib::Attribs *RenderAttrib::_attribs = NULL;
|
||||||
TypeHandle RenderAttrib::_type_handle;
|
TypeHandle RenderAttrib::_type_handle;
|
||||||
|
|
||||||
@ -33,12 +35,7 @@ TypeHandle RenderAttrib::_type_handle;
|
|||||||
RenderAttrib::
|
RenderAttrib::
|
||||||
RenderAttrib() {
|
RenderAttrib() {
|
||||||
if (_attribs == (Attribs *)NULL) {
|
if (_attribs == (Attribs *)NULL) {
|
||||||
// Make sure the global _attribs map is allocated. This only has
|
init_attribs();
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
_saved_entry = _attribs->end();
|
_saved_entry = _attribs->end();
|
||||||
|
|
||||||
@ -73,24 +70,10 @@ operator = (const RenderAttrib &) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
RenderAttrib::
|
RenderAttrib::
|
||||||
~RenderAttrib() {
|
~RenderAttrib() {
|
||||||
if (_saved_entry != _attribs->end()) {
|
ReMutexHolder holder(*_attribs_lock);
|
||||||
// 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);
|
|
||||||
|
|
||||||
// Note: this isn't thread-safe, because once the derived class
|
// unref() should have cleared this.
|
||||||
// destructor exits and before this destructor completes, the map
|
nassertv(_saved_entry == _attribs->end());
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -157,6 +140,32 @@ cull_callback(CullTraverser *, const CullTraverserData &) const {
|
|||||||
return true;
|
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
|
// Function: RenderAttrib::output
|
||||||
// Access: Published, Virtual
|
// Access: Published, Virtual
|
||||||
@ -186,6 +195,8 @@ write(ostream &out, int indent_level) const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
int RenderAttrib::
|
int RenderAttrib::
|
||||||
get_num_attribs() {
|
get_num_attribs() {
|
||||||
|
ReMutexHolder holder(*_attribs_lock);
|
||||||
|
|
||||||
if (_attribs == (Attribs *)NULL) {
|
if (_attribs == (Attribs *)NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -201,6 +212,8 @@ get_num_attribs() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void RenderAttrib::
|
void RenderAttrib::
|
||||||
list_attribs(ostream &out) {
|
list_attribs(ostream &out) {
|
||||||
|
ReMutexHolder holder(*_attribs_lock);
|
||||||
|
|
||||||
out << _attribs->size() << " attribs:\n";
|
out << _attribs->size() << " attribs:\n";
|
||||||
Attribs::const_iterator si;
|
Attribs::const_iterator si;
|
||||||
for (si = _attribs->begin(); si != _attribs->end(); ++si) {
|
for (si = _attribs->begin(); si != _attribs->end(); ++si) {
|
||||||
@ -219,6 +232,8 @@ list_attribs(ostream &out) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool RenderAttrib::
|
bool RenderAttrib::
|
||||||
validate_attribs() {
|
validate_attribs() {
|
||||||
|
ReMutexHolder holder(*_attribs_lock);
|
||||||
|
|
||||||
if (_attribs->empty()) {
|
if (_attribs->empty()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -263,6 +278,8 @@ return_new(RenderAttrib *attrib) {
|
|||||||
return attrib;
|
return attrib;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReMutexHolder holder(*_attribs_lock);
|
||||||
|
|
||||||
// This should be a newly allocated pointer, not one that was used
|
// This should be a newly allocated pointer, not one that was used
|
||||||
// for anything else.
|
// for anything else.
|
||||||
nassertr(attrib->_saved_entry == _attribs->end(), attrib);
|
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
|
// Function: RenderAttrib::make_default_impl
|
||||||
// Access: Protected, Virtual
|
// Access: Protected, Virtual
|
||||||
@ -415,6 +452,29 @@ make_default_impl() const {
|
|||||||
return (RenderAttrib *)NULL;
|
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
|
// Function: RenderAttrib::write_datagram
|
||||||
// Access: Public, Virtual
|
// Access: Public, Virtual
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "typedWritableReferenceCount.h"
|
#include "typedWritableReferenceCount.h"
|
||||||
#include "pointerTo.h"
|
#include "pointerTo.h"
|
||||||
#include "pset.h"
|
#include "pset.h"
|
||||||
|
#include "reMutex.h"
|
||||||
|
|
||||||
class AttribSlots;
|
class AttribSlots;
|
||||||
class GraphicsStateGuardianBase;
|
class GraphicsStateGuardianBase;
|
||||||
@ -80,6 +81,9 @@ public:
|
|||||||
|
|
||||||
PUBLISHED:
|
PUBLISHED:
|
||||||
INLINE int compare_to(const RenderAttrib &other) const;
|
INLINE int compare_to(const RenderAttrib &other) const;
|
||||||
|
|
||||||
|
bool unref() const;
|
||||||
|
|
||||||
virtual void output(ostream &out) const;
|
virtual void output(ostream &out) const;
|
||||||
virtual void write(ostream &out, int indent_level) const;
|
virtual void write(ostream &out, int indent_level) const;
|
||||||
|
|
||||||
@ -179,10 +183,18 @@ protected:
|
|||||||
virtual RenderAttrib *make_default_impl() const=0;
|
virtual RenderAttrib *make_default_impl() const=0;
|
||||||
void output_comparefunc(ostream &out, PandaCompareFunc fn) const;
|
void output_comparefunc(ostream &out, PandaCompareFunc fn) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void release_new();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool _always_reissue;
|
bool _always_reissue;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static void init_attribs();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// This mutex protects _attribs.
|
||||||
|
static ReMutex *_attribs_lock;
|
||||||
typedef pset<const RenderAttrib *, indirect_compare_to<const RenderAttrib *> > Attribs;
|
typedef pset<const RenderAttrib *, indirect_compare_to<const RenderAttrib *> > Attribs;
|
||||||
static Attribs *_attribs;
|
static Attribs *_attribs;
|
||||||
|
|
||||||
|
@ -83,10 +83,9 @@ RenderEffects::
|
|||||||
~RenderEffects() {
|
~RenderEffects() {
|
||||||
// Remove the deleted RenderEffects object from the global pool.
|
// Remove the deleted RenderEffects object from the global pool.
|
||||||
ReMutexHolder holder(*_states_lock);
|
ReMutexHolder holder(*_states_lock);
|
||||||
if (_saved_entry != _states->end()) {
|
|
||||||
_states->erase(_saved_entry);
|
// unref() should have cleared this.
|
||||||
_saved_entry = _states->end();
|
nassertv(_saved_entry == _states->end());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -385,6 +384,40 @@ get_effect(TypeHandle type) const {
|
|||||||
return NULL;
|
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
|
// Function: RenderEffects::output
|
||||||
// Access: Published, Virtual
|
// Access: Published, Virtual
|
||||||
@ -603,6 +636,26 @@ return_new(RenderEffects *state) {
|
|||||||
return *(result.first);
|
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
|
// Function: RenderEffects::determine_decal
|
||||||
// Access: Private
|
// Access: Private
|
||||||
@ -759,6 +812,28 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) {
|
|||||||
return pi;
|
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
|
// Function: RenderEffects::change_this
|
||||||
// Access: Public, Static
|
// Access: Public, Static
|
||||||
|
@ -89,6 +89,8 @@ PUBLISHED:
|
|||||||
|
|
||||||
const RenderEffect *get_effect(TypeHandle type) const;
|
const RenderEffect *get_effect(TypeHandle type) const;
|
||||||
|
|
||||||
|
bool unref() const;
|
||||||
|
|
||||||
void output(ostream &out) const;
|
void output(ostream &out) const;
|
||||||
void write(ostream &out, int indent_level) const;
|
void write(ostream &out, int indent_level) const;
|
||||||
|
|
||||||
@ -115,6 +117,8 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
static CPT(RenderEffects) return_new(RenderEffects *state);
|
static CPT(RenderEffects) return_new(RenderEffects *state);
|
||||||
|
void release_new();
|
||||||
|
|
||||||
void determine_decal();
|
void determine_decal();
|
||||||
void determine_show_bounds();
|
void determine_show_bounds();
|
||||||
void determine_cull_callback();
|
void determine_cull_callback();
|
||||||
@ -174,6 +178,7 @@ public:
|
|||||||
static void register_with_read_factory();
|
static void register_with_read_factory();
|
||||||
virtual void write_datagram(BamWriter *manager, Datagram &dg);
|
virtual void write_datagram(BamWriter *manager, Datagram &dg);
|
||||||
virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
|
virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
|
||||||
|
virtual bool require_fully_complete() const;
|
||||||
static TypedWritable *change_this(TypedWritable *old_ptr, BamReader *manager);
|
static TypedWritable *change_this(TypedWritable *old_ptr, BamReader *manager);
|
||||||
virtual void finalize(BamReader *manager);
|
virtual void finalize(BamReader *manager);
|
||||||
|
|
||||||
|
@ -103,11 +103,11 @@ INLINE bool RenderState::
|
|||||||
cache_unref() const {
|
cache_unref() const {
|
||||||
#ifdef DO_PSTATS
|
#ifdef DO_PSTATS
|
||||||
int old_referenced_bits = get_referenced_bits();
|
int old_referenced_bits = get_referenced_bits();
|
||||||
bool result = NodeCachedReferenceCount::cache_unref();
|
bool result = do_cache_unref();
|
||||||
consider_update_pstats(old_referenced_bits);
|
consider_update_pstats(old_referenced_bits);
|
||||||
return result;
|
return result;
|
||||||
#else // DO_PSTATS
|
#else // DO_PSTATS
|
||||||
return NodeCachedReferenceCount::cache_unref();
|
return do_cache_unref();
|
||||||
#endif // DO_PSTATS
|
#endif // DO_PSTATS
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,11 +136,11 @@ INLINE bool RenderState::
|
|||||||
node_unref() const {
|
node_unref() const {
|
||||||
#ifdef DO_PSTATS
|
#ifdef DO_PSTATS
|
||||||
int old_referenced_bits = get_referenced_bits();
|
int old_referenced_bits = get_referenced_bits();
|
||||||
bool result = NodeCachedReferenceCount::node_unref();
|
bool result = do_node_unref();
|
||||||
consider_update_pstats(old_referenced_bits);
|
consider_update_pstats(old_referenced_bits);
|
||||||
return result;
|
return result;
|
||||||
#else // DO_PSTATS
|
#else // DO_PSTATS
|
||||||
return NodeCachedReferenceCount::node_unref();
|
return do_node_unref();
|
||||||
#endif // DO_PSTATS
|
#endif // DO_PSTATS
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -632,6 +632,31 @@ flush_level() {
|
|||||||
_cache_counter.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
|
// Function: RenderState::CompositionCycleDescEntry::Constructor
|
||||||
// Access: Public
|
// Access: Public
|
||||||
|
@ -104,13 +104,10 @@ RenderState::
|
|||||||
set_destructing();
|
set_destructing();
|
||||||
|
|
||||||
ReMutexHolder holder(*_states_lock);
|
ReMutexHolder holder(*_states_lock);
|
||||||
if (_saved_entry != _states->end()) {
|
|
||||||
nassertv(_states->find(this) == _saved_entry);
|
// unref() should have cleared these.
|
||||||
_states->erase(_saved_entry);
|
nassertv(_saved_entry == _states->end());
|
||||||
_saved_entry = _states->end();
|
nassertv(_composition_cache.empty() && _invert_composition_cache.empty());
|
||||||
}
|
|
||||||
|
|
||||||
remove_cache_pointers();
|
|
||||||
|
|
||||||
// If this was true at the beginning of the destructor, but is no
|
// If this was true at the beginning of the destructor, but is no
|
||||||
// longer true now, probably we've been double-deleted.
|
// longer true now, probably we've been double-deleted.
|
||||||
@ -627,46 +624,44 @@ get_override(TypeHandle type) const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool RenderState::
|
bool RenderState::
|
||||||
unref() const {
|
unref() const {
|
||||||
// Most of the time, we won't need to grab the lock. We first check
|
// We always have to grab the lock, since we will definitely need to
|
||||||
// whether we think we will need to grab it. Then, after we have
|
// be holding it if we happen to drop the reference count to 0.
|
||||||
// successfully acquired the lock, we check that the condition is
|
ReMutexHolder holder(*_states_lock);
|
||||||
// still valid.
|
|
||||||
|
|
||||||
// It is possible that, due to some race condition, this condition
|
if (auto_break_cycles) {
|
||||||
// is never seen as true on any one thread. In that case, the cycle
|
if (get_cache_ref_count() > 0 &&
|
||||||
// will not automatically be detected and broken. But since (a)
|
get_ref_count() == get_cache_ref_count() + 1) {
|
||||||
// that will be a relatively rare situation, (b) it will be
|
// If we are about to remove the one reference that is not in the
|
||||||
// expensive to protect against it, and (c) the damage is minimal,
|
// cache, leaving only references in the cache, then we need to
|
||||||
// the race condition is allowed to remain.
|
// check for a cycle involving this RenderState and break it if
|
||||||
if (get_cache_ref_count() > 0 &&
|
// it exists.
|
||||||
get_ref_count() == get_cache_ref_count() + 1) {
|
|
||||||
|
|
||||||
if (auto_break_cycles) {
|
|
||||||
ReMutexHolder holder(*_states_lock);
|
|
||||||
|
|
||||||
if (get_cache_ref_count() > 0 &&
|
++_last_cycle_detect;
|
||||||
get_ref_count() == get_cache_ref_count() + 1) {
|
if (r_detect_cycles(this, this, 1, _last_cycle_detect, NULL)) {
|
||||||
// If we are about to remove the one reference that is not in the
|
// Ok, we have a cycle. This will be a leak unless we break the
|
||||||
// cache, leaving only references in the cache, then we need to
|
// cycle by freeing the cache on this object.
|
||||||
// check for a cycle involving this RenderState and break it if
|
if (pgraph_cat.is_debug()) {
|
||||||
// it exists.
|
pgraph_cat.debug()
|
||||||
|
<< "Breaking cycle involving " << (*this) << "\n";
|
||||||
++_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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
((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;
|
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
|
// Function: RenderState::remove_cache_pointers
|
||||||
// Access: Private
|
// Access: Private
|
||||||
|
@ -163,6 +163,9 @@ public:
|
|||||||
INLINE static void flush_level();
|
INLINE static void flush_level();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
INLINE bool do_cache_unref() const;
|
||||||
|
INLINE bool do_node_unref() const;
|
||||||
|
|
||||||
class CompositionCycleDescEntry {
|
class CompositionCycleDescEntry {
|
||||||
public:
|
public:
|
||||||
INLINE CompositionCycleDescEntry(const RenderState *obj,
|
INLINE CompositionCycleDescEntry(const RenderState *obj,
|
||||||
@ -183,6 +186,7 @@ private:
|
|||||||
int length, UpdateSeq this_seq,
|
int length, UpdateSeq this_seq,
|
||||||
CompositionCycleDesc *cycle_desc);
|
CompositionCycleDesc *cycle_desc);
|
||||||
|
|
||||||
|
void release_new();
|
||||||
void remove_cache_pointers();
|
void remove_cache_pointers();
|
||||||
|
|
||||||
void determine_bin_index();
|
void determine_bin_index();
|
||||||
|
@ -733,11 +733,11 @@ INLINE bool TransformState::
|
|||||||
cache_unref() const {
|
cache_unref() const {
|
||||||
#ifdef DO_PSTATS
|
#ifdef DO_PSTATS
|
||||||
int old_referenced_bits = get_referenced_bits();
|
int old_referenced_bits = get_referenced_bits();
|
||||||
bool result = NodeCachedReferenceCount::cache_unref();
|
bool result = do_cache_unref();
|
||||||
consider_update_pstats(old_referenced_bits);
|
consider_update_pstats(old_referenced_bits);
|
||||||
return result;
|
return result;
|
||||||
#else // DO_PSTATS
|
#else // DO_PSTATS
|
||||||
return NodeCachedReferenceCount::cache_unref();
|
return do_cache_unref();
|
||||||
#endif // DO_PSTATS
|
#endif // DO_PSTATS
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -766,11 +766,11 @@ INLINE bool TransformState::
|
|||||||
node_unref() const {
|
node_unref() const {
|
||||||
#ifdef DO_PSTATS
|
#ifdef DO_PSTATS
|
||||||
int old_referenced_bits = get_referenced_bits();
|
int old_referenced_bits = get_referenced_bits();
|
||||||
bool result = NodeCachedReferenceCount::node_unref();
|
bool result = do_node_unref();
|
||||||
consider_update_pstats(old_referenced_bits);
|
consider_update_pstats(old_referenced_bits);
|
||||||
return result;
|
return result;
|
||||||
#else // DO_PSTATS
|
#else // DO_PSTATS
|
||||||
return NodeCachedReferenceCount::node_unref();
|
return do_node_unref();
|
||||||
#endif // DO_PSTATS
|
#endif // DO_PSTATS
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -785,6 +785,31 @@ flush_level() {
|
|||||||
_cache_counter.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
|
// Function: TransformState::check_hash
|
||||||
// Access: Private
|
// Access: Private
|
||||||
|
@ -102,13 +102,10 @@ TransformState::
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReMutexHolder holder(*_states_lock);
|
ReMutexHolder holder(*_states_lock);
|
||||||
if (_saved_entry != _states->end()) {
|
|
||||||
nassertv(_states->find(this) == _saved_entry);
|
// unref() should have cleared these.
|
||||||
_states->erase(_saved_entry);
|
nassertv(_saved_entry == _states->end());
|
||||||
_saved_entry = _states->end();
|
nassertv(_composition_cache.empty() && _invert_composition_cache.empty());
|
||||||
}
|
|
||||||
|
|
||||||
remove_cache_pointers();
|
|
||||||
|
|
||||||
// If this was true at the beginning of the destructor, but is no
|
// If this was true at the beginning of the destructor, but is no
|
||||||
// longer true now, probably we've been double-deleted.
|
// longer true now, probably we've been double-deleted.
|
||||||
@ -765,48 +762,46 @@ invert_compose(const TransformState *other) const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool TransformState::
|
bool TransformState::
|
||||||
unref() const {
|
unref() const {
|
||||||
// Most of the time, we won't need to grab the lock. We first check
|
// We always have to grab the lock, since we will definitely need to
|
||||||
// whether we think we will need to grab it. Then, after we have
|
// be holding it if we happen to drop the reference count to 0.
|
||||||
// successfully acquired the lock, we check that the condition is
|
ReMutexHolder holder(*_states_lock);
|
||||||
// still valid.
|
|
||||||
|
|
||||||
// It is possible that, due to some race condition, this condition
|
if (auto_break_cycles) {
|
||||||
// is never seen as true on any one thread. In that case, the cycle
|
if (get_cache_ref_count() > 0 &&
|
||||||
// will not automatically be detected and broken. But since (a)
|
get_ref_count() == get_cache_ref_count() + 1) {
|
||||||
// that will be a relatively rare situation, (b) it will be
|
// If we are about to remove the one reference that is not in the
|
||||||
// expensive to protect against it, and (c) the damage is minimal,
|
// cache, leaving only references in the cache, then we need to
|
||||||
// the race condition is allowed to remain.
|
// check for a cycle involving this TransformState and break it if
|
||||||
if (get_cache_ref_count() > 0 &&
|
// it exists.
|
||||||
get_ref_count() == get_cache_ref_count() + 1) {
|
|
||||||
|
|
||||||
if (auto_break_cycles) {
|
|
||||||
ReMutexHolder holder(*_states_lock);
|
|
||||||
|
|
||||||
if (get_cache_ref_count() > 0 &&
|
PStatTimer timer(_transform_break_cycles_pcollector);
|
||||||
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);
|
|
||||||
|
|
||||||
++_last_cycle_detect;
|
++_last_cycle_detect;
|
||||||
if (r_detect_cycles(this, this, 1, _last_cycle_detect, NULL)) {
|
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
|
// Ok, we have a cycle. This will be a leak unless we break the
|
||||||
// cycle by freeing the cache on this object.
|
// cycle by freeing the cache on this object.
|
||||||
if (pgraph_cat.is_debug()) {
|
if (pgraph_cat.is_debug()) {
|
||||||
pgraph_cat.debug()
|
pgraph_cat.debug()
|
||||||
<< "Breaking cycle involving " << (*this) << "\n";
|
<< "Breaking cycle involving " << (*this) << "\n";
|
||||||
}
|
|
||||||
|
|
||||||
((TransformState *)this)->remove_cache_pointers();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
((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;
|
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
|
// Function: TransformState::remove_cache_pointers
|
||||||
// Access: Private
|
// Access: Private
|
||||||
@ -1606,7 +1622,7 @@ r_detect_cycles(const TransformState *start_state,
|
|||||||
void TransformState::
|
void TransformState::
|
||||||
remove_cache_pointers() {
|
remove_cache_pointers() {
|
||||||
nassertv(_states_lock->debug_is_locked());
|
nassertv(_states_lock->debug_is_locked());
|
||||||
|
|
||||||
// Fortunately, since we added CompositionCache records in pairs, we
|
// Fortunately, since we added CompositionCache records in pairs, we
|
||||||
// know exactly the set of TransformState objects that have us in their
|
// 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
|
// cache: it's the same set of TransformState objects that we have in
|
||||||
|
@ -195,6 +195,9 @@ public:
|
|||||||
INLINE static void flush_level();
|
INLINE static void flush_level();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
INLINE bool do_cache_unref() const;
|
||||||
|
INLINE bool do_node_unref() const;
|
||||||
|
|
||||||
class CompositionCycleDescEntry {
|
class CompositionCycleDescEntry {
|
||||||
public:
|
public:
|
||||||
INLINE CompositionCycleDescEntry(const TransformState *obj,
|
INLINE CompositionCycleDescEntry(const TransformState *obj,
|
||||||
@ -215,6 +218,7 @@ private:
|
|||||||
int length, UpdateSeq this_seq,
|
int length, UpdateSeq this_seq,
|
||||||
CompositionCycleDesc *cycle_desc);
|
CompositionCycleDesc *cycle_desc);
|
||||||
|
|
||||||
|
void release_new();
|
||||||
void remove_cache_pointers();
|
void remove_cache_pointers();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -32,7 +32,6 @@
|
|||||||
config_util.N config_util.h configurable.h \
|
config_util.N config_util.h configurable.h \
|
||||||
datagramInputFile.I datagramInputFile.h \
|
datagramInputFile.I datagramInputFile.h \
|
||||||
datagramOutputFile.I datagramOutputFile.h \
|
datagramOutputFile.I datagramOutputFile.h \
|
||||||
deferredDeletor.h \
|
|
||||||
doubleBitMask.I doubleBitMask.h \
|
doubleBitMask.I doubleBitMask.h \
|
||||||
drawMask.h \
|
drawMask.h \
|
||||||
factoryBase.I factoryBase.h \
|
factoryBase.I factoryBase.h \
|
||||||
@ -52,11 +51,9 @@
|
|||||||
modifierButtons.I modifierButtons.h mouseButton.h \
|
modifierButtons.I modifierButtons.h mouseButton.h \
|
||||||
mouseData.I mouseData.h nameUniquifier.I nameUniquifier.h \
|
mouseData.I mouseData.h nameUniquifier.I nameUniquifier.h \
|
||||||
nodeCachedReferenceCount.h nodeCachedReferenceCount.I \
|
nodeCachedReferenceCount.h nodeCachedReferenceCount.I \
|
||||||
nonDeletor.h \
|
|
||||||
portalMask.h \
|
portalMask.h \
|
||||||
pta_double.h \
|
pta_double.h \
|
||||||
pta_float.h pta_int.h \
|
pta_float.h pta_int.h \
|
||||||
spamDeletor.h \
|
|
||||||
sparseArray.I sparseArray.h \
|
sparseArray.I sparseArray.h \
|
||||||
string_utils.I string_utils.N string_utils.h \
|
string_utils.I string_utils.N string_utils.h \
|
||||||
stringStreamBuf.I stringStreamBuf.h \
|
stringStreamBuf.I stringStreamBuf.h \
|
||||||
@ -88,7 +85,6 @@
|
|||||||
copyOnWritePointer.cxx \
|
copyOnWritePointer.cxx \
|
||||||
config_util.cxx configurable.cxx \
|
config_util.cxx configurable.cxx \
|
||||||
datagramInputFile.cxx datagramOutputFile.cxx \
|
datagramInputFile.cxx datagramOutputFile.cxx \
|
||||||
deferredDeletor.cxx \
|
|
||||||
doubleBitMask.cxx \
|
doubleBitMask.cxx \
|
||||||
factoryBase.cxx \
|
factoryBase.cxx \
|
||||||
factoryParam.cxx factoryParams.cxx \
|
factoryParam.cxx factoryParams.cxx \
|
||||||
@ -101,10 +97,8 @@
|
|||||||
modifierButtons.cxx mouseButton.cxx mouseData.cxx \
|
modifierButtons.cxx mouseButton.cxx mouseData.cxx \
|
||||||
nameUniquifier.cxx \
|
nameUniquifier.cxx \
|
||||||
nodeCachedReferenceCount.cxx \
|
nodeCachedReferenceCount.cxx \
|
||||||
nonDeletor.cxx \
|
|
||||||
pta_double.cxx pta_float.cxx \
|
pta_double.cxx pta_float.cxx \
|
||||||
pta_int.cxx pta_ushort.cxx \
|
pta_int.cxx pta_ushort.cxx \
|
||||||
spamDeletor.cxx \
|
|
||||||
sparseArray.cxx \
|
sparseArray.cxx \
|
||||||
string_utils.cxx \
|
string_utils.cxx \
|
||||||
stringStreamBuf.cxx \
|
stringStreamBuf.cxx \
|
||||||
@ -140,7 +134,6 @@
|
|||||||
config_util.h configurable.h factory.I factory.h \
|
config_util.h configurable.h factory.I factory.h \
|
||||||
datagramInputFile.I datagramInputFile.h \
|
datagramInputFile.I datagramInputFile.h \
|
||||||
datagramOutputFile.I datagramOutputFile.h \
|
datagramOutputFile.I datagramOutputFile.h \
|
||||||
deferredDeletor.h \
|
|
||||||
doubleBitMask.I doubleBitMask.h \
|
doubleBitMask.I doubleBitMask.h \
|
||||||
drawMask.h \
|
drawMask.h \
|
||||||
factoryBase.I factoryBase.h factoryParam.I factoryParam.h \
|
factoryBase.I factoryBase.h factoryParam.I factoryParam.h \
|
||||||
@ -160,11 +153,9 @@
|
|||||||
modifierButtons.h mouseButton.h mouseData.I mouseData.h \
|
modifierButtons.h mouseButton.h mouseData.I mouseData.h \
|
||||||
nameUniquifier.I nameUniquifier.h \
|
nameUniquifier.I nameUniquifier.h \
|
||||||
nodeCachedReferenceCount.h nodeCachedReferenceCount.I \
|
nodeCachedReferenceCount.h nodeCachedReferenceCount.I \
|
||||||
nonDeletor.h \
|
|
||||||
portalMask.h \
|
portalMask.h \
|
||||||
pta_double.h \
|
pta_double.h \
|
||||||
pta_float.h pta_int.h pta_ushort.h \
|
pta_float.h pta_int.h pta_ushort.h \
|
||||||
spamDeletor.h \
|
|
||||||
sparseArray.I sparseArray.h \
|
sparseArray.I sparseArray.h \
|
||||||
string_utils.I string_utils.h \
|
string_utils.I string_utils.h \
|
||||||
stringStreamBuf.I stringStreamBuf.h \
|
stringStreamBuf.I stringStreamBuf.h \
|
||||||
|
@ -144,14 +144,8 @@ get_cache_ref_count() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: CachedTypedWritableReferenceCount::cache_ref
|
// Function: CachedTypedWritableReferenceCount::cache_ref
|
||||||
// Access: Published
|
// Access: Published
|
||||||
// Description: Explicitly increments the reference count.
|
// Description: Explicitly increments the cache reference count and
|
||||||
//
|
// the normal reference count simultaneously.
|
||||||
// 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.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
INLINE void CachedTypedWritableReferenceCount::
|
INLINE void CachedTypedWritableReferenceCount::
|
||||||
cache_ref() const {
|
cache_ref() const {
|
||||||
@ -166,25 +160,8 @@ cache_ref() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: CachedTypedWritableReferenceCount::cache_unref
|
// Function: CachedTypedWritableReferenceCount::cache_unref
|
||||||
// Access: Published
|
// Access: Published
|
||||||
// Description: Explicitly decrements the reference count. Note that
|
// Description: Explicitly decrements the cache reference count and
|
||||||
// the object will not be implicitly deleted by unref()
|
// the normal reference count simultaneously.
|
||||||
// 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.
|
|
||||||
//
|
//
|
||||||
// The return value is true if the new reference count
|
// The return value is true if the new reference count
|
||||||
// is nonzero, false if it is zero.
|
// is nonzero, false if it is zero.
|
||||||
@ -199,9 +176,9 @@ cache_unref() const {
|
|||||||
// zero reference count. Are you using ref() and unref()
|
// zero reference count. Are you using ref() and unref()
|
||||||
// directly? Are you sure you can't use PointerTo's?
|
// directly? Are you sure you can't use PointerTo's?
|
||||||
nassertr(_cache_ref_count > 0, 0);
|
nassertr(_cache_ref_count > 0, 0);
|
||||||
|
|
||||||
unref();
|
AtomicAdjust::dec(((CachedTypedWritableReferenceCount *)this)->_cache_ref_count);
|
||||||
return AtomicAdjust::dec(((CachedTypedWritableReferenceCount *)this)->_cache_ref_count);
|
return unref();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -219,6 +196,28 @@ test_ref_count_integrity() const {
|
|||||||
#endif
|
#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
|
// Function: cache_unref_delete
|
||||||
// Description: This global helper function will unref the given
|
// Description: This global helper function will unref the given
|
||||||
@ -232,14 +231,7 @@ test_ref_count_integrity() const {
|
|||||||
template<class RefCountType>
|
template<class RefCountType>
|
||||||
INLINE void
|
INLINE void
|
||||||
cache_unref_delete(RefCountType *ptr) {
|
cache_unref_delete(RefCountType *ptr) {
|
||||||
ptr->cache_unref();
|
if (!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<RefCountType>::do_delete, (void *)ptr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
delete ptr;
|
delete ptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,6 +56,7 @@ PUBLISHED:
|
|||||||
INLINE bool test_ref_count_integrity() const;
|
INLINE bool test_ref_count_integrity() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
INLINE void cache_unref_only() const;
|
||||||
bool do_test_ref_count_integrity() const;
|
bool do_test_ref_count_integrity() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -44,9 +44,6 @@
|
|||||||
#include "writableParam.h"
|
#include "writableParam.h"
|
||||||
#include "keyboardButton.h"
|
#include "keyboardButton.h"
|
||||||
#include "mouseButton.h"
|
#include "mouseButton.h"
|
||||||
#include "deferredDeletor.h"
|
|
||||||
#include "nonDeletor.h"
|
|
||||||
#include "spamDeletor.h"
|
|
||||||
|
|
||||||
#include "dconfig.h"
|
#include "dconfig.h"
|
||||||
|
|
||||||
@ -179,10 +176,6 @@ init_libputil() {
|
|||||||
KeyboardButton::init_keyboard_buttons();
|
KeyboardButton::init_keyboard_buttons();
|
||||||
MouseButton::init_mouse_buttons();
|
MouseButton::init_mouse_buttons();
|
||||||
|
|
||||||
DeferredDeletor::register_deletor();
|
|
||||||
NonDeletor::register_deletor();
|
|
||||||
SpamDeletor::register_deletor();
|
|
||||||
|
|
||||||
register_type(BamReader::_remove_flag, "remove");
|
register_type(BamReader::_remove_flag, "remove");
|
||||||
|
|
||||||
BamCacheIndex::register_with_read_factory();
|
BamCacheIndex::register_with_read_factory();
|
||||||
|
@ -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");
|
|
||||||
}
|
|
@ -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<DeleteToken> Tokens;
|
|
||||||
Tokens _tokens;
|
|
||||||
Mutex _lock;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -166,42 +166,16 @@ node_ref() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: NodeCachedReferenceCount::node_unref
|
// Function: NodeCachedReferenceCount::node_unref
|
||||||
// Access: Published
|
// Access: Published
|
||||||
// Description: Explicitly decrements the reference count. Note that
|
// Description: Explicitly decrements the node reference count and
|
||||||
// the object will not be implicitly deleted by unref()
|
// the normal reference count simultaneously.
|
||||||
// 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.
|
|
||||||
//
|
//
|
||||||
// The return value is true if the new reference count
|
// The return value is true if the new reference count
|
||||||
// is nonzero, false if it is zero.
|
// is nonzero, false if it is zero.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
INLINE bool NodeCachedReferenceCount::
|
INLINE bool NodeCachedReferenceCount::
|
||||||
node_unref() const {
|
node_unref() const {
|
||||||
#ifdef _DEBUG
|
node_unref_only();
|
||||||
nassertr(test_ref_count_integrity(), 0);
|
return unref();
|
||||||
#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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -242,3 +216,25 @@ get_referenced_bits() const {
|
|||||||
|
|
||||||
return result;
|
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);
|
||||||
|
}
|
||||||
|
@ -84,6 +84,7 @@ PUBLISHED:
|
|||||||
INLINE int get_referenced_bits() const;
|
INLINE int get_referenced_bits() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
INLINE void node_unref_only() const;
|
||||||
bool do_test_ref_count_integrity() const;
|
bool do_test_ref_count_integrity() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -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");
|
|
||||||
}
|
|
@ -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
|
|
@ -19,7 +19,6 @@
|
|||||||
#include "copyOnWritePointer.cxx"
|
#include "copyOnWritePointer.cxx"
|
||||||
#include "datagramInputFile.cxx"
|
#include "datagramInputFile.cxx"
|
||||||
#include "datagramOutputFile.cxx"
|
#include "datagramOutputFile.cxx"
|
||||||
#include "deferredDeletor.cxx"
|
|
||||||
#include "doubleBitMask.cxx"
|
#include "doubleBitMask.cxx"
|
||||||
#include "factoryBase.cxx"
|
#include "factoryBase.cxx"
|
||||||
#include "factoryParam.cxx"
|
#include "factoryParam.cxx"
|
||||||
|
@ -8,12 +8,10 @@
|
|||||||
#include "mouseData.cxx"
|
#include "mouseData.cxx"
|
||||||
#include "nameUniquifier.cxx"
|
#include "nameUniquifier.cxx"
|
||||||
#include "nodeCachedReferenceCount.cxx"
|
#include "nodeCachedReferenceCount.cxx"
|
||||||
#include "nonDeletor.cxx"
|
|
||||||
#include "pta_double.cxx"
|
#include "pta_double.cxx"
|
||||||
#include "pta_float.cxx"
|
#include "pta_float.cxx"
|
||||||
#include "pta_int.cxx"
|
#include "pta_int.cxx"
|
||||||
#include "pta_ushort.cxx"
|
#include "pta_ushort.cxx"
|
||||||
#include "spamDeletor.cxx"
|
|
||||||
#include "sparseArray.cxx"
|
#include "sparseArray.cxx"
|
||||||
#include "string_utils.cxx"
|
#include "string_utils.cxx"
|
||||||
#include "stringStreamBuf.cxx"
|
#include "stringStreamBuf.cxx"
|
||||||
|
@ -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");
|
|
||||||
}
|
|
@ -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
|
|
Loading…
x
Reference in New Issue
Block a user