reduced need for read locks

This commit is contained in:
David Rose 2006-05-02 00:48:10 +00:00
parent f6d45f344d
commit c8eb6c5a82
77 changed files with 2333 additions and 335 deletions

View File

@ -94,7 +94,7 @@ void PartBundle::
set_blend_type(BlendType bt) {
nassertv(Thread::get_current_pipeline_stage() == 0);
CDReader cdata(_cycler);
CDLockedReader cdata(_cycler);
if (cdata->_blend_type != bt) {
CDWriter cdataw(_cycler, cdata);
cdataw->_blend_type = bt;
@ -131,7 +131,7 @@ void PartBundle::
clear_control_effects() {
nassertv(Thread::get_current_pipeline_stage() == 0);
CDReader cdata(_cycler);
CDLockedReader cdata(_cycler);
if (!cdata->_blend.empty()) {
CDWriter cdataw(_cycler, cdata);
cdataw->_blend.clear();
@ -299,7 +299,7 @@ control_activated(AnimControl *control) {
nassertv(Thread::get_current_pipeline_stage() == 0);
nassertv(control->get_part() == this);
CDReader cdata(_cycler);
CDLockedReader cdata(_cycler);
// If (and only if) our blend type is BT_single, which means no
// blending, then starting an animation implicitly enables it.
if (cdata->_blend_type == BT_single) {

View File

@ -26,6 +26,10 @@
#include "partSubset.h"
#include "pointerTo.h"
#include "thread.h"
#include "cycleData.h"
#include "cycleDataLockedReader.h"
#include "cycleDataReader.h"
#include "cycleDataWriter.h"
class AnimBundle;
class PartBundleNode;
@ -150,6 +154,7 @@ private:
};
PipelineCycler<CData> _cycler;
typedef CycleDataLockedReader<CData> CDLockedReader;
typedef CycleDataReader<CData> CDReader;
typedef CycleDataWriter<CData> CDWriter;

View File

@ -202,7 +202,7 @@ void DisplayRegion::
set_active(bool active) {
int pipeline_stage = Thread::get_current_pipeline_stage();
nassertv(pipeline_stage == 0);
CDReader cdata(_cycler);
CDLockedReader cdata(_cycler);
if (active != cdata->_active) {
CDWriter cdataw(_cycler, cdata);
@ -222,7 +222,7 @@ set_active(bool active) {
void DisplayRegion::
set_sort(int sort) {
nassertv(Thread::get_current_pipeline_stage() == 0);
CDReader cdata(_cycler);
CDLockedReader cdata(_cycler);
if (sort != cdata->_sort) {
CDWriter cdataw(_cycler, cdata);

View File

@ -28,6 +28,7 @@
#include "sceneSetup.h"
#include "pointerTo.h"
#include "cycleData.h"
#include "cycleDataLockedReader.h"
#include "cycleDataReader.h"
#include "cycleDataWriter.h"
#include "cycleDataStageWriter.h"
@ -176,6 +177,7 @@ private:
};
PipelineCycler<CData> _cycler;
typedef CycleDataLockedReader<CData> CDLockedReader;
typedef CycleDataReader<CData> CDReader;
typedef CycleDataWriter<CData> CDWriter;
typedef CycleDataStageWriter<CData> CDStageWriter;

View File

@ -30,6 +30,9 @@
multifile.I multifile.h \
namable.I \
namable.h nativeNumericData.I nativeNumericData.h \
nodePointerToBase.h nodePointerToBase.I \
nodePointerTo.h nodePointerTo.I \
nodeReferenceCount.h nodeReferenceCount.I \
objectDeletor.h objectDeletor.I \
ordered_vector.h ordered_vector.I ordered_vector.T \
password_hash.h \
@ -80,6 +83,9 @@
memoryUsagePointers.cxx multifile.cxx \
namable.cxx \
nativeNumericData.cxx \
nodePointerToBase.cxx \
nodePointerTo.cxx \
nodeReferenceCount.cxx \
objectDeletor.cxx \
ordered_vector.cxx \
password_hash.cxx \
@ -136,6 +142,9 @@
multifile.I multifile.h \
namable.I \
namable.h nativeNumericData.I nativeNumericData.h \
nodePointerToBase.h nodePointerToBase.I \
nodePointerTo.h nodePointerTo.I \
nodeReferenceCount.h nodeReferenceCount.I \
objectDeletor.h objectDeletor.I \
ordered_vector.h ordered_vector.I ordered_vector.T \
password_hash.h \

View File

@ -18,6 +18,7 @@
#include "config_express.h"
#include "datagram.h"
#include "nodeReferenceCount.h"
#include "referenceCount.h"
#include "textEncoder.h"
#include "typedObject.h"
@ -147,6 +148,7 @@ init_libexpress() {
initialized = true;
Datagram::init_type();
NodeReferenceCount::init_type();
ReferenceCount::init_type();
TextEncoder::init_type();
TypedObject::init_type();

View File

@ -18,6 +18,9 @@
#include "multifile.cxx"
#include "namable.cxx"
#include "nativeNumericData.cxx"
#include "nodePointerToBase.cxx"
#include "nodePointerTo.cxx"
#include "nodeReferenceCount.cxx"
#include "objectDeletor.cxx"
#include "ordered_vector.cxx"
#include "patchfile.cxx"
@ -27,4 +30,3 @@
#include "pointerToBase.cxx"
#include "pointerToVoid.cxx"
#include "profileTimer.cxx"
#include "pta_uchar.cxx"

View File

@ -1,3 +1,4 @@
#include "pta_uchar.cxx"
#include "ramfile.cxx"
#include "referenceCount.cxx"
#include "reversedNumericData.cxx"

View File

@ -0,0 +1,259 @@
// Filename: nodePointerTo.I
// Created by: drose (07May05)
//
////////////////////////////////////////////////////////////////////
//
// 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: NodePointerTo::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE NodePointerTo<T>::
NodePointerTo(To *ptr) : NodePointerToBase<T>(ptr) {
}
////////////////////////////////////////////////////////////////////
// Function: NodePointerTo::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE NodePointerTo<T>::
NodePointerTo(const NodePointerTo<T> &copy) :
NodePointerToBase<T>((const NodePointerToBase<T> &)copy)
{
}
////////////////////////////////////////////////////////////////////
// Function: NodePointerTo::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE NodePointerTo<T>::
~NodePointerTo() {
}
////////////////////////////////////////////////////////////////////
// Function: NodePointerTo::Dereference operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE TYPENAME NodePointerTo<T>::To &NodePointerTo<T>::
operator *() const {
return *((To *)(this->_void_ptr));
}
////////////////////////////////////////////////////////////////////
// Function: NodePointerTo::Member access operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE TYPENAME NodePointerTo<T>::To *NodePointerTo<T>::
operator -> () const {
return (To *)(this->_void_ptr);
}
////////////////////////////////////////////////////////////////////
// Function: NodePointerTo::Typecast operator
// Access: Public
// Description: We also have the typecast operator to automatically
// convert NodePointerTo's to the required kind of actual
// pointer. This introduces ambiguities which the
// compiler will resolve one way or the other, but we
// don't care which way it goes because either will be
// correct.
////////////////////////////////////////////////////////////////////
template<class T>
INLINE NodePointerTo<T>::
operator TYPENAME NodePointerToBase<T>::To *() const {
return (To *)(this->_void_ptr);
}
////////////////////////////////////////////////////////////////////
// Function: NodePointerTo::p
// Access: Public
// Description: Returns an ordinary pointer instead of a NodePointerTo.
// Useful to work around compiler problems, particularly
// for implicit upcasts.
////////////////////////////////////////////////////////////////////
template<class T>
INLINE TYPENAME NodePointerTo<T>::To *NodePointerTo<T>::
p() const {
return (To *)(this->_void_ptr);
}
////////////////////////////////////////////////////////////////////
// Function: NodePointerTo::Assignment operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE NodePointerTo<T> &NodePointerTo<T>::
operator = (To *ptr) {
reassign(ptr);
return *this;
}
////////////////////////////////////////////////////////////////////
// Function: NodePointerTo::Assignment operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE NodePointerTo<T> &NodePointerTo<T>::
operator = (const NodePointerTo<T> &copy) {
reassign((const NodePointerToBase<T> &)copy);
return *this;
}
////////////////////////////////////////////////////////////////////
// Function: NodeConstPointerTo::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE NodeConstPointerTo<T>::
NodeConstPointerTo(const TYPENAME NodeConstPointerTo<T>::To *ptr) :
NodePointerToBase<T>((TYPENAME NodeConstPointerTo<T>::To *)ptr)
{
}
////////////////////////////////////////////////////////////////////
// Function: NodeConstPointerTo::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE NodeConstPointerTo<T>::
NodeConstPointerTo(const NodePointerTo<T> &copy) :
NodePointerToBase<T>((const NodePointerToBase<T> &)copy)
{
}
////////////////////////////////////////////////////////////////////
// Function: NodeConstPointerTo::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE NodeConstPointerTo<T>::
NodeConstPointerTo(const NodeConstPointerTo<T> &copy) :
NodePointerToBase<T>((const NodePointerToBase<T> &)copy)
{
}
////////////////////////////////////////////////////////////////////
// Function: NodeConstPointerTo::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE NodeConstPointerTo<T>::
~NodeConstPointerTo() {
}
////////////////////////////////////////////////////////////////////
// Function: NodeConstPointerTo::Dereference operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE const TYPENAME NodeConstPointerTo<T>::To &NodeConstPointerTo<T>::
operator *() const {
return *((To *)(this->_void_ptr));
}
////////////////////////////////////////////////////////////////////
// Function: NodeConstPointerTo::Member access operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE const TYPENAME NodeConstPointerTo<T>::To *NodeConstPointerTo<T>::
operator -> () const {
return (To *)(this->_void_ptr);
}
////////////////////////////////////////////////////////////////////
// Function: NodeConstPointerTo::Typecast operator
// Access: Public
// Description: We also have the typecast operator to automatically
// convert NodeConstPointerTo's to the required kind of actual
// pointer. This introduces ambiguities which the
// compiler will resolve one way or the other, but we
// don't care which way it goes because either will be
// correct.
////////////////////////////////////////////////////////////////////
template<class T>
INLINE NodeConstPointerTo<T>::
operator const TYPENAME NodePointerToBase<T>::To *() const {
return (To *)(this->_void_ptr);
}
////////////////////////////////////////////////////////////////////
// Function: NodeConstPointerTo::p
// Access: Public
// Description: Returns an ordinary pointer instead of a NodeConstPointerTo.
// Useful to work around compiler problems, particularly
// for implicit upcasts.
////////////////////////////////////////////////////////////////////
template<class T>
INLINE const TYPENAME NodeConstPointerTo<T>::To *NodeConstPointerTo<T>::
p() const {
return (To *)(this->_void_ptr);
}
////////////////////////////////////////////////////////////////////
// Function: NodeConstPointerTo::Assignment operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE NodeConstPointerTo<T> &NodeConstPointerTo<T>::
operator = (const To *ptr) {
reassign((To *)ptr);
return *this;
}
////////////////////////////////////////////////////////////////////
// Function: NodeConstPointerTo::Assignment operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE NodeConstPointerTo<T> &NodeConstPointerTo<T>::
operator = (const NodePointerTo<T> &copy) {
reassign((const NodePointerToBase<T> &)copy);
return *this;
}
////////////////////////////////////////////////////////////////////
// Function: NodeConstPointerTo::Assignment operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE NodeConstPointerTo<T> &NodeConstPointerTo<T>::
operator = (const NodeConstPointerTo<T> &copy) {
reassign((const NodePointerToBase<T> &)copy);
return *this;
}

View File

@ -0,0 +1,19 @@
// Filename: nodePointerTo.cxx
// Created by: drose (07May05)
//
////////////////////////////////////////////////////////////////////
//
// 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 "nodePointerTo.h"

View File

@ -0,0 +1,81 @@
// Filename: nodePointerTo.h
// Created by: drose (07May05)
//
////////////////////////////////////////////////////////////////////
//
// 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 NODEPOINTERTO_H
#define NODEPOINTERTO_H
#include "pandabase.h"
#include "nodePointerToBase.h"
////////////////////////////////////////////////////////////////////
// Class : NodePointerTo
// Description : This implements the special NodePointerTo template
// class, which works just like PointerTo except it
// manages the objects node_ref_count instead of the
// normal ref_count.
////////////////////////////////////////////////////////////////////
template <class T>
class NodePointerTo : public NodePointerToBase<T> {
public:
typedef TYPENAME NodePointerToBase<T>::To To;
INLINE NodePointerTo(To *ptr = (To *)NULL);
INLINE NodePointerTo(const NodePointerTo<T> &copy);
INLINE ~NodePointerTo();
INLINE To &operator *() const;
INLINE To *operator -> () const;
INLINE operator TYPENAME NodePointerToBase<T>::To *() const;
INLINE To *p() const;
INLINE NodePointerTo<T> &operator = (To *ptr);
INLINE NodePointerTo<T> &operator = (const NodePointerTo<T> &copy);
};
////////////////////////////////////////////////////////////////////
// Class : NodeConstPointerTo
// Description : A NodeConstPointerTo is similar to a NodePointerTo,
// except it keeps a const pointer to the thing.
////////////////////////////////////////////////////////////////////
template <class T>
class NodeConstPointerTo : public NodePointerToBase<T> {
public:
typedef TYPENAME NodePointerToBase<T>::To To;
INLINE NodeConstPointerTo(const To *ptr = (const To *)NULL);
INLINE NodeConstPointerTo(const NodePointerTo<T> &copy);
INLINE NodeConstPointerTo(const NodeConstPointerTo<T> &copy);
INLINE ~NodeConstPointerTo();
INLINE const To &operator *() const;
INLINE const To *operator -> () const;
INLINE operator const TYPENAME NodePointerToBase<T>::To *() const;
INLINE const To *p() const;
INLINE NodeConstPointerTo<T> &operator = (const To *ptr);
INLINE NodeConstPointerTo<T> &operator = (const NodePointerTo<T> &copy);
INLINE NodeConstPointerTo<T> &operator = (const NodeConstPointerTo<T> &copy);
};
#define NPT(type) NodePointerTo< type >
#define NCPT(type) NodeConstPointerTo< type >
#include "nodePointerTo.I"
#endif

View File

@ -0,0 +1,135 @@
// Filename: nodePointerToBase.I
// Created by: drose (07May05)
//
////////////////////////////////////////////////////////////////////
//
// 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: NodePointerToBase::Constructor
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE NodePointerToBase<T>::
NodePointerToBase(To *ptr) {
reassign(ptr);
}
////////////////////////////////////////////////////////////////////
// Function: NodePointerToBase::Copy Constructor
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE NodePointerToBase<T>::
NodePointerToBase(const NodePointerToBase<T> &copy) {
reassign(copy);
}
////////////////////////////////////////////////////////////////////
// Function: NodePointerToBase::Destructor
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE NodePointerToBase<T>::
~NodePointerToBase() {
reassign((To *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: NodePointerToBase::reassign
// Access: Protected
// Description: This is the main work of the NodePointerTo family. When
// the pointer is reassigned, decrement the old
// reference count and increment the new one.
////////////////////////////////////////////////////////////////////
template<class T>
void NodePointerToBase<T>::
reassign(To *ptr) {
if (ptr != (To *)_void_ptr) {
// First save the old pointer; we won't delete it until we have
// assigned the new one. We do this just in case there are
// cascading effects from deleting this pointer that might
// inadvertently delete the new one. (Don't laugh--it's
// happened!)
To *old_ptr = (To *)_void_ptr;
_void_ptr = (void *)ptr;
if (ptr != (To *)NULL) {
ptr->node_ref();
#ifdef DO_MEMORY_USAGE
if (MemoryUsage::get_track_memory_usage()) {
// Make sure the MemoryUsage record knows what the TypeHandle
// is, if we know it ourselves.
TypeHandle type = get_type_handle(To);
if (type == TypeHandle::none()) {
do_init_type(To);
type = get_type_handle(To);
}
if (type != TypeHandle::none()) {
MemoryUsage::update_type(ptr, type);
}
}
#endif
}
// Now delete the old pointer.
if (old_ptr != (To *)NULL) {
node_unref_delete(old_ptr);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: NodePointerToBase::reassign
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE void NodePointerToBase<T>::
reassign(const NodePointerToBase<To> &copy) {
reassign((To *)copy._void_ptr);
}
////////////////////////////////////////////////////////////////////
// Function: NodePointerToBase::clear
// Access: Published
// Description: A convenient way to set the NodePointerTo object to NULL.
// (Assignment to a NULL pointer also works, of course.)
////////////////////////////////////////////////////////////////////
template<class T>
INLINE void NodePointerToBase<T>::
clear() {
reassign((To *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: NodePointerToBase::output
// Access: Published
// Description: A handy function to output NodePointerTo's as a hex
// pointer followed by a reference count.
////////////////////////////////////////////////////////////////////
template<class T>
INLINE void NodePointerToBase<T>::
output(ostream &out) const {
out << _void_ptr;
if (_void_ptr != (void *)NULL) {
out << ":" << ((To *)_void_ptr)->get_node_ref_count() << "/"
<< ((To *)_void_ptr)->get_ref_count();
}
}

View File

@ -0,0 +1,19 @@
// Filename: nodePointerToBase.cxx
// Created by: drose (07May05)
//
////////////////////////////////////////////////////////////////////
//
// 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 "nodePointerToBase.h"

View File

@ -0,0 +1,70 @@
// Filename: nodePointerToBase.h
// Created by: drose (07May05)
//
////////////////////////////////////////////////////////////////////
//
// 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 NODEPOINTERTOBASE_H
#define NODEPOINTERTOBASE_H
#include "pandabase.h"
#include "pointerToVoid.h"
#include "memoryUsage.h"
#include "config_express.h"
////////////////////////////////////////////////////////////////////
// Class : NodePointerToBase
// Description : This is similar to PointerToBase, but it manages
// objects of type NodeReferenceCount or
// NodeCachedReferenceCount, and it updates the
// node_ref_count instead of the regular ref_count. It
// is intended for use only in PandaNode, to hold a
// pointer to RenderState and TransformState, although
// it could be used by any object that wanted to
// maintain a separate reference count for reporting
// purposes.
////////////////////////////////////////////////////////////////////
template <class T>
class NodePointerToBase : public PointerToVoid {
public:
typedef T To;
protected:
INLINE NodePointerToBase(To *ptr);
INLINE NodePointerToBase(const NodePointerToBase<T> &copy);
INLINE ~NodePointerToBase();
void reassign(To *ptr);
INLINE void reassign(const NodePointerToBase<To> &copy);
// No assignment or retrieval functions are declared in
// NodePointerToBase, because we will have to specialize on const
// vs. non-const later.
PUBLISHED:
INLINE void clear();
void output(ostream &out) const;
};
template<class T>
INLINE ostream &operator <<(ostream &out, const NodePointerToBase<T> &pointer) {
pointer.output(out);
return out;
}
#include "nodePointerToBase.I"
#endif

View File

@ -0,0 +1,295 @@
// Filename: nodeReferenceCount.I
// Created by: drose (01May06)
//
////////////////////////////////////////////////////////////////////
//
// 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 .
//
////////////////////////////////////////////////////////////////////
template<class Base>
TypeHandle NodeRefCountObj<Base>::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: NodeReferenceCount::Constructor
// Access: Protected
// Description: The ReferenceCount constructor is protected because
// you almost never want to create just a ReferenceCount
// object by itself, and it's probably a mistake if you
// try.
//
// ReferenceCount doesn't store any useful information
// in its own right; its only purpose is to add
// reference-counting to some other class via
// inheritance.
////////////////////////////////////////////////////////////////////
INLINE NodeReferenceCount::
NodeReferenceCount() {
_node_ref_count = 0;
}
////////////////////////////////////////////////////////////////////
// Function: NodeReferenceCount::Copy Constructor
// Access: Protected
// Description: The copies of reference-counted objects do not
// themselves inherit the reference count!
//
// This copy constructor is protected because you almost
// never want to create just a ReferenceCount object by
// itself, and it's probably a mistake if you try.
////////////////////////////////////////////////////////////////////
INLINE NodeReferenceCount::
NodeReferenceCount(const NodeReferenceCount &copy) : ReferenceCount(copy) {
_node_ref_count = 0;
}
////////////////////////////////////////////////////////////////////
// Function: NodeReferenceCount::Copy Assignment Operator
// Access: Protected
// Description: The copies of reference-counted objects do not
// themselves inherit the reference count!
//
// This copy assignment operator is protected because
// you almost never want to copy just a ReferenceCount
// object by itself, and it's probably a mistake if you
// try. Instead, this should only be called from a
// derived class that implements this operator and then
// calls up the inheritance chain.
////////////////////////////////////////////////////////////////////
INLINE void NodeReferenceCount::
operator = (const NodeReferenceCount &copy) {
nassertv(this != NULL);
// If this assertion fails, our own pointer was recently deleted.
// Possibly you used a real pointer instead of a PointerTo at some
// point, and the object was deleted when the PointerTo went out of
// scope. Maybe you tried to create an automatic (local variable)
// instance of a class that derives from ReferenceCount. Or maybe
// your headers are out of sync, and you need to make clean in
// direct or some higher tree.
nassertv(_node_ref_count != -100);
ReferenceCount::operator = (copy);
}
////////////////////////////////////////////////////////////////////
// Function: NodeReferenceCount::Destructor
// Access: Protected
// Description: The ReferenceCount destructor is protected to
// discourage users from accidentally trying to delete a
// ReferenceCount pointer directly. This is almost
// always a bad idea, since the destructor is not
// virtual, and you've almost certainly got some pointer
// to something that inherits from ReferenceCount, not
// just a plain old ReferenceCount object.
////////////////////////////////////////////////////////////////////
INLINE NodeReferenceCount::
~NodeReferenceCount() {
nassertv(this != NULL);
// If this assertion fails, we're trying to delete an object that
// was just deleted. Possibly you used a real pointer instead of a
// PointerTo at some point, and the object was deleted when the
// PointerTo went out of scope. Maybe you tried to create an
// automatic (local variable) instance of a class that derives from
// ReferenceCount. Or maybe your headers are out of sync, and you
// need to make clean in direct or some higher tree.
nassertv(_node_ref_count != -100);
// If this assertion fails, the reference counts are all screwed
// up altogether. Maybe some errant code stomped all over memory
// somewhere.
nassertv(_node_ref_count >= 0);
// If this assertion fails, someone tried to delete this object
// while its reference count was still positive. Maybe you tried
// to point a PointerTo at a static object (a local variable,
// instead of one allocated via new)? The test below against 0x7f
// is supposed to check for that, but it's a pretty hokey test.
// Another possibility is you inadvertently omitted a copy
// constructor for a ReferenceCount object, and then bitwise
// copied a dynamically allocated value--reference count and
// all--onto a locally allocated one.
nassertv(_node_ref_count == 0);
#ifndef NDEBUG
// Ok, all clear to delete. Now set the reference count to -100,
// so we'll have a better chance of noticing if we happen to have
// a stray pointer to it still out there.
_node_ref_count = -100;
#endif
}
////////////////////////////////////////////////////////////////////
// Function: NodeReferenceCount::get_node_ref_count
// Access: Published
// Description: Returns the current reference count.
////////////////////////////////////////////////////////////////////
INLINE int NodeReferenceCount::
get_node_ref_count() const {
#ifdef _DEBUG
test_ref_count_integrity();
#endif
return AtomicAdjust::get(_node_ref_count);
}
////////////////////////////////////////////////////////////////////
// Function: NodeReferenceCount::node_ref
// Access: Published
// Description: Explicitly increments the reference count.
//
// This function is const, even though it changes the
// object, because generally fiddling with an object's
// reference count isn't considered part of fiddling
// with the object. An object might be const in other
// ways, but we still need to accurately count the
// number of references to it.
////////////////////////////////////////////////////////////////////
INLINE void NodeReferenceCount::
node_ref() const {
#ifdef _DEBUG
nassertv(test_ref_count_integrity());
#endif
ref();
AtomicAdjust::inc(((NodeReferenceCount *)this)->_node_ref_count);
}
////////////////////////////////////////////////////////////////////
// Function: NodeReferenceCount::node_unref
// Access: Published
// Description: Explicitly decrements the reference count. Note that
// the object will not be implicitly deleted by unref()
// simply because the reference count drops to zero.
// (Having a member function delete itself is
// problematic; plus, we don't have a virtual destructor
// anyway.) However, see the helper function
// unref_delete().
//
// User code should avoid using ref() and unref()
// directly, which can result in missed reference
// counts. Instead, let a PointerTo object manage the
// reference counting automatically.
//
// This function is const, even though it changes the
// object, because generally fiddling with an object's
// reference count isn't considered part of fiddling
// with the object. An object might be const in other
// ways, but we still need to accurately count the
// number of references to it.
//
// The return value is true if the new reference count
// is nonzero, false if it is zero.
////////////////////////////////////////////////////////////////////
INLINE bool NodeReferenceCount::
node_unref() const {
#ifdef _DEBUG
nassertr(test_ref_count_integrity(), 0);
#endif
// If this assertion fails, you tried to unref an object with a
// zero reference count. Are you using ref() and unref()
// directly? Are you sure you can't use PointerTo's?
nassertr(_node_ref_count > 0, 0);
unref();
return AtomicAdjust::dec(((NodeReferenceCount *)this)->_node_ref_count);
}
////////////////////////////////////////////////////////////////////
// Function: NodeReferenceCount::test_ref_count_integrity
// Access: Published
// Description: Does some easy checks to make sure that the reference
// count isn't completely bogus.
////////////////////////////////////////////////////////////////////
INLINE bool NodeReferenceCount::
test_ref_count_integrity() const {
#ifndef NDEBUG
return do_test_ref_count_integrity();
#else
return true;
#endif
}
////////////////////////////////////////////////////////////////////
// Function: node_unref_delete
// Description: This global helper function will unref the given
// ReferenceCount object, and if the reference count
// reaches zero, automatically delete it. It can't be a
// member function because it's usually a bad idea to
// delete an object from within its own member function.
// It's a template function so the destructor doesn't
// have to be virtual.
////////////////////////////////////////////////////////////////////
template<class RefCountType>
INLINE void
node_unref_delete(RefCountType *ptr) {
ptr->node_unref();
if (ptr->get_ref_count() == 0) {
ObjectDeletor *deletor = ObjectDeletor::get_global_ptr();
if (deletor != (ObjectDeletor *)NULL) {
ptr->ref();
deletor->delete_object(RefCountDeleteWrapper<RefCountType>::do_delete, (void *)ptr);
return;
}
delete ptr;
}
}
////////////////////////////////////////////////////////////////////
// Function: NodeRefCountObj::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class Base>
INLINE NodeRefCountObj<Base>::
NodeRefCountObj() {
}
////////////////////////////////////////////////////////////////////
// Function: NodeRefCountObj::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class Base>
INLINE NodeRefCountObj<Base>::
NodeRefCountObj(const Base &copy) : Base(copy) {
}
////////////////////////////////////////////////////////////////////
// Function: NodeRefCountObj::init_type
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class Base>
void NodeRefCountObj<Base>::
init_type() {
#if defined(HAVE_RTTI) && !defined(__EDG__)
// If we have RTTI, we can determine the name of the base type.
string base_name = typeid(Base).name();
#else
string base_name = "unknown";
#endif
TypeHandle base_type = register_dynamic_type(base_name);
ReferenceCount::init_type();
_type_handle =
register_dynamic_type("NodeRefCountObj<" + base_name + ">",
base_type, ReferenceCount::get_class_type());
}

View File

@ -0,0 +1,48 @@
// Filename: nodeReferenceCount.cxx
// Created by: drose (01May06)
//
////////////////////////////////////////////////////////////////////
//
// 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 "nodeReferenceCount.h"
TypeHandle NodeReferenceCount::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: NodeReferenceCount::do_test_ref_count_integrity
// Access: Protected
// Description: Does some easy checks to make sure that the reference
// count isn't completely bogus.
////////////////////////////////////////////////////////////////////
bool NodeReferenceCount::
do_test_ref_count_integrity() const {
nassertr(this != NULL, false);
// If this assertion fails, we're trying to delete an object that
// was just deleted. Possibly you used a real pointer instead of a
// PointerTo at some point, and the object was deleted when the
// PointerTo went out of scope. Maybe you tried to create an
// automatic (local variable) instance of a class that derives from
// ReferenceCount. Or maybe your headers are out of sync, and you
// need to make clean in direct or some higher tree.
nassertr(_node_ref_count != -100, false);
// If this assertion fails, the reference counts are all screwed
// up altogether. Maybe some errant code stomped all over memory
// somewhere.
nassertr(_node_ref_count >= 0, false);
return ReferenceCount::do_test_ref_count_integrity();
}

View File

@ -0,0 +1,107 @@
// Filename: nodeReferenceCount.h
// Created by: drose (01May06)
//
////////////////////////////////////////////////////////////////////
//
// 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 NODEREFERENCECOUNT_H
#define NODEREFERENCECOUNT_H
#include "pandabase.h"
#include "referenceCount.h"
#include "objectDeletor.h"
////////////////////////////////////////////////////////////////////
// Class : NodeReferenceCount
// Description : This class specializes ReferenceCount to add an
// additional counter, called node_ref_count, for the
// purposes of counting the number of times the object
// is referenced by a "node", whatever that may mean in
// context.
//
// The new methods node_ref() and node_unref()
// automatically increment and decrement the primary
// reference count as well. There also exists a
// NodePointerTo<> class to maintain the node_ref
// counters automatically.
//
// See also CachedTypedWritableReferenceCount, which is
// similar in principle, as well as
// NodeCachedReferenceCount, which combines both of
// these.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEXPRESS NodeReferenceCount : public ReferenceCount {
protected:
INLINE NodeReferenceCount();
INLINE NodeReferenceCount(const NodeReferenceCount &copy);
INLINE void operator = (const NodeReferenceCount &copy);
INLINE ~NodeReferenceCount();
PUBLISHED:
INLINE int get_node_ref_count() const;
INLINE void node_ref() const;
INLINE bool node_unref() const;
INLINE bool test_ref_count_integrity() const;
protected:
bool do_test_ref_count_integrity() const;
private:
PN_int32 _node_ref_count;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
ReferenceCount::init_type();
register_type(_type_handle, "NodeReferenceCount",
ReferenceCount::get_class_type());
}
private:
static TypeHandle _type_handle;
};
template<class RefCountType>
INLINE void node_unref_delete(RefCountType *ptr);
////////////////////////////////////////////////////////////////////
// Class : NodeRefCountObj
// Description : This works like RefCountObj, but it inherits from
// NodeReferenceCount instead of ReferenceCount.
////////////////////////////////////////////////////////////////////
template<class Base>
class NodeRefCountObj : public NodeReferenceCount, public Base {
public:
INLINE NodeRefCountObj();
INLINE NodeRefCountObj(const Base &copy);
ALLOC_DELETED_CHAIN(NodeRefCountObj<Base>);
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type();
private:
static TypeHandle _type_handle;
};
#include "nodeReferenceCount.I"
#endif

View File

@ -30,7 +30,7 @@ pvector<Element> ConstPointerToArray<Element>::_empty_array;
template<class Element>
INLINE PointerToArray<Element>::
PointerToArray() :
PointerToBase<RefCountObj<pvector<Element> > >((RefCountObj<pvector<Element> > *)NULL)
PointerToBase<NodeRefCountObj<pvector<Element> > >((NodeRefCountObj<pvector<Element> > *)NULL)
{
}
@ -52,7 +52,7 @@ PointerToArray<Element>::empty_array(size_type n) {
template<class Element>
INLINE PointerToArray<Element>::
PointerToArray(size_type n, const Element &value) :
PointerToBase<RefCountObj<pvector<Element> > >(new RefCountObj<pvector<Element> >) {
PointerToBase<NodeRefCountObj<pvector<Element> > >(new NodeRefCountObj<pvector<Element> >) {
((To *)(this->_void_ptr))->reserve(n);
insert(begin(), n, value);
}
@ -65,7 +65,7 @@ PointerToArray(size_type n, const Element &value) :
template<class Element>
INLINE PointerToArray<Element>::
PointerToArray(const PointerToArray<Element> &copy) :
PointerToBase<RefCountObj<pvector<Element> > >(copy)
PointerToBase<NodeRefCountObj<pvector<Element> > >(copy)
{
}
@ -145,7 +145,7 @@ template<class Element>
INLINE TYPENAME PointerToArray<Element>::size_type PointerToArray<Element>::
max_size() const {
nassertd((this->_void_ptr) != NULL) {
((PointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
((PointerToArray<Element> *)this)->reassign(new NodeRefCountObj<pvector<Element> >);
}
return ((To *)(this->_void_ptr))->max_size();
}
@ -170,7 +170,7 @@ template<class Element>
INLINE void PointerToArray<Element>::
reserve(TYPENAME PointerToArray<Element>::size_type n) {
if ((this->_void_ptr) == NULL) {
reassign(new RefCountObj<pvector<Element> >);
reassign(new NodeRefCountObj<pvector<Element> >);
}
((To *)(this->_void_ptr))->reserve(n);
}
@ -196,7 +196,7 @@ template<class Element>
INLINE TYPENAME PointerToArray<Element>::reference PointerToArray<Element>::
front() const {
nassertd((this->_void_ptr) != NULL) {
((PointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
((PointerToArray<Element> *)this)->reassign(new NodeRefCountObj<pvector<Element> >);
}
nassertd(!((To *)(this->_void_ptr))->empty()) {
((To *)(this->_void_ptr))->push_back(Element());
@ -213,7 +213,7 @@ template<class Element>
INLINE TYPENAME PointerToArray<Element>::reference PointerToArray<Element>::
back() const {
nassertd((this->_void_ptr) != NULL) {
((PointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
((PointerToArray<Element> *)this)->reassign(new NodeRefCountObj<pvector<Element> >);
}
nassertd(!((To *)(this->_void_ptr))->empty()) {
((To *)(this->_void_ptr))->push_back(Element());
@ -230,7 +230,7 @@ template<class Element>
INLINE TYPENAME PointerToArray<Element>::iterator PointerToArray<Element>::
insert(iterator position, const Element &x) {
if ((this->_void_ptr) == NULL) {
reassign(new RefCountObj<pvector<Element> >);
reassign(new NodeRefCountObj<pvector<Element> >);
position = end();
}
nassertr(position >= ((To *)(this->_void_ptr))->begin() &&
@ -247,7 +247,7 @@ template<class Element>
INLINE void PointerToArray<Element>::
insert(iterator position, size_type n, const Element &x) {
if ((this->_void_ptr) == NULL) {
reassign(new RefCountObj<pvector<Element> >);
reassign(new NodeRefCountObj<pvector<Element> >);
position = end();
}
nassertv(position >= ((To *)(this->_void_ptr))->begin() &&
@ -293,7 +293,7 @@ template<class Element>
INLINE TYPENAME PointerToArray<Element>::reference PointerToArray<Element>::
operator [](size_type n) const {
nassertd((this->_void_ptr) != NULL) {
((PointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
((PointerToArray<Element> *)this)->reassign(new NodeRefCountObj<pvector<Element> >);
}
nassertd(!((To *)(this->_void_ptr))->empty()) {
((To *)(this->_void_ptr))->push_back(Element());
@ -354,7 +354,7 @@ template<class Element>
INLINE void PointerToArray<Element>::
push_back(const Element &x) {
if ((this->_void_ptr) == NULL) {
reassign(new RefCountObj<pvector<Element> >);
reassign(new NodeRefCountObj<pvector<Element> >);
}
((To *)(this->_void_ptr))->push_back(x);
}
@ -368,7 +368,7 @@ template<class Element>
INLINE void PointerToArray<Element>::
pop_back() {
nassertd((this->_void_ptr) != NULL) {
((PointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
((PointerToArray<Element> *)this)->reassign(new NodeRefCountObj<pvector<Element> >);
}
nassertv(!((To *)(this->_void_ptr))->empty());
((To *)(this->_void_ptr))->pop_back();
@ -385,7 +385,7 @@ template<class Element>
INLINE void PointerToArray<Element>::
make_empty() {
nassertd((this->_void_ptr) != NULL) {
((PointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
((PointerToArray<Element> *)this)->reassign(new NodeRefCountObj<pvector<Element> >);
}
nassertv(!((To *)(this->_void_ptr))->empty());
((To *)(this->_void_ptr))->clear();
@ -429,7 +429,7 @@ template<class Element>
INLINE pvector<Element> &PointerToArray<Element>::
v() const {
if ((this->_void_ptr) == NULL) {
((PointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
((PointerToArray<Element> *)this)->reassign(new NodeRefCountObj<pvector<Element> >);
}
return *((To *)(this->_void_ptr));
}
@ -468,6 +468,43 @@ get_ref_count() const {
return ((this->_void_ptr) == NULL) ? 0 : ((To *)(this->_void_ptr))->get_ref_count();
}
////////////////////////////////////////////////////////////////////
// Function: PointerToArray::get_node_ref_count
// Access: Public
// Description: Returns the node_ref of the underlying vector.
////////////////////////////////////////////////////////////////////
template<class Element>
INLINE int PointerToArray<Element>::
get_node_ref_count() const {
return ((this->_void_ptr) == NULL) ? 0 : ((To *)(this->_void_ptr))->get_node_ref_count();
}
////////////////////////////////////////////////////////////////////
// Function: PointerToArray::node_ref
// Access: Public
// Description: Increments the node_ref of the underlying vector.
////////////////////////////////////////////////////////////////////
template<class Element>
INLINE void PointerToArray<Element>::
node_ref() const {
if ((this->_void_ptr) == NULL) {
((PointerToArray<Element> *)this)->reassign(new NodeRefCountObj<pvector<Element> >);
}
((To *)(this->_void_ptr))->node_ref();
}
////////////////////////////////////////////////////////////////////
// Function: PointerToArray::node_unref
// Access: Public
// Description: Decrements the node_ref of the underlying vector.
////////////////////////////////////////////////////////////////////
template<class Element>
INLINE bool PointerToArray<Element>::
node_unref() const {
nassertr((this->_void_ptr) != NULL, true);
return ((To *)(this->_void_ptr))->node_unref();
}
////////////////////////////////////////////////////////////////////
// Function: PointerToArray::Assignment operator
// Access: Public
@ -475,7 +512,7 @@ get_ref_count() const {
////////////////////////////////////////////////////////////////////
template<class Element>
INLINE PointerToArray<Element> &PointerToArray<Element>::
operator = (RefCountObj<pvector<Element> > *ptr) {
operator = (NodeRefCountObj<pvector<Element> > *ptr) {
reassign(ptr);
return *this;
}
@ -502,7 +539,7 @@ operator = (const PointerToArray<Element> &copy) {
template<class Element>
INLINE void PointerToArray<Element>::
clear() {
reassign((RefCountObj<pvector<Element> > *)NULL);
reassign((NodeRefCountObj<pvector<Element> > *)NULL);
}
@ -515,7 +552,7 @@ clear() {
template<class Element>
INLINE ConstPointerToArray<Element>::
ConstPointerToArray() :
PointerToBase<RefCountObj<pvector<Element> > >((RefCountObj<pvector<Element> > *)NULL)
PointerToBase<NodeRefCountObj<pvector<Element> > >((NodeRefCountObj<pvector<Element> > *)NULL)
{
}
@ -527,7 +564,7 @@ ConstPointerToArray() :
template<class Element>
INLINE ConstPointerToArray<Element>::
ConstPointerToArray(const PointerToArray<Element> &copy) :
PointerToBase<RefCountObj<pvector<Element> > >(copy)
PointerToBase<NodeRefCountObj<pvector<Element> > >(copy)
{
}
@ -539,7 +576,7 @@ ConstPointerToArray(const PointerToArray<Element> &copy) :
template<class Element>
INLINE ConstPointerToArray<Element>::
ConstPointerToArray(const ConstPointerToArray<Element> &copy) :
PointerToBase<RefCountObj<pvector<Element> > >(copy)
PointerToBase<NodeRefCountObj<pvector<Element> > >(copy)
{
}
@ -619,7 +656,7 @@ template<class Element>
INLINE TYPENAME ConstPointerToArray<Element>::size_type ConstPointerToArray<Element>::
max_size() const {
nassertd((this->_void_ptr) != NULL) {
((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
((ConstPointerToArray<Element> *)this)->reassign(new NodeRefCountObj<pvector<Element> >);
}
return ((To *)(this->_void_ptr))->max_size();
}
@ -644,7 +681,7 @@ template<class Element>
INLINE TYPENAME ConstPointerToArray<Element>::size_type ConstPointerToArray<Element>::
capacity() const {
nassertd((this->_void_ptr) != NULL) {
((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
((ConstPointerToArray<Element> *)this)->reassign(new NodeRefCountObj<pvector<Element> >);
}
return ((To *)(this->_void_ptr))->capacity();
}
@ -658,7 +695,7 @@ template<class Element>
INLINE TYPENAME ConstPointerToArray<Element>::reference ConstPointerToArray<Element>::
front() const {
nassertd((this->_void_ptr) != NULL) {
((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
((ConstPointerToArray<Element> *)this)->reassign(new NodeRefCountObj<pvector<Element> >);
}
nassertd(!((To *)(this->_void_ptr))->empty()) {
((To *)(this->_void_ptr))->push_back(Element());
@ -675,7 +712,7 @@ template<class Element>
INLINE TYPENAME ConstPointerToArray<Element>::reference ConstPointerToArray<Element>::
back() const {
nassertd((this->_void_ptr) != NULL) {
((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
((ConstPointerToArray<Element> *)this)->reassign(new NodeRefCountObj<pvector<Element> >);
}
nassertd(!((To *)(this->_void_ptr))->empty()) {
((To *)(this->_void_ptr))->push_back(Element());
@ -693,7 +730,7 @@ template<class Element>
INLINE TYPENAME ConstPointerToArray<Element>::reference ConstPointerToArray<Element>::
operator [](size_type n) const {
nassertd((this->_void_ptr) != NULL) {
((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
((ConstPointerToArray<Element> *)this)->reassign(new NodeRefCountObj<pvector<Element> >);
}
nassertd(!((To *)(this->_void_ptr))->empty()) {
((To *)(this->_void_ptr))->push_back(Element());
@ -767,7 +804,7 @@ template<class Element>
INLINE const pvector<Element> &ConstPointerToArray<Element>::
v() const {
nassertd((this->_void_ptr) != NULL) {
((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
((ConstPointerToArray<Element> *)this)->reassign(new NodeRefCountObj<pvector<Element> >);
}
return *(To *)(this->_void_ptr);
}
@ -783,6 +820,43 @@ get_ref_count() const {
return ((this->_void_ptr) == NULL) ? 0 : ((To *)(this->_void_ptr))->get_ref_count();
}
////////////////////////////////////////////////////////////////////
// Function: ConstPointerToArray::get_node_ref_count
// Access: Public
// Description: Returns the node_ref of the underlying vector.
////////////////////////////////////////////////////////////////////
template<class Element>
INLINE int ConstPointerToArray<Element>::
get_node_ref_count() const {
return ((this->_void_ptr) == NULL) ? 0 : ((To *)(this->_void_ptr))->get_node_ref_count();
}
////////////////////////////////////////////////////////////////////
// Function: ConstPointerToArray::node_ref
// Access: Public
// Description: Increments the node_ref of the underlying vector.
////////////////////////////////////////////////////////////////////
template<class Element>
INLINE void ConstPointerToArray<Element>::
node_ref() const {
if ((this->_void_ptr) == NULL) {
((PointerToArray<Element> *)this)->reassign(new NodeRefCountObj<pvector<Element> >);
}
((To *)(this->_void_ptr))->node_ref();
}
////////////////////////////////////////////////////////////////////
// Function: ConstPointerToArray::node_unref
// Access: Public
// Description: Decrements the node_ref of the underlying vector.
////////////////////////////////////////////////////////////////////
template<class Element>
INLINE bool ConstPointerToArray<Element>::
node_unref() const {
nassertr((this->_void_ptr) != NULL, true);
return ((To *)(this->_void_ptr))->node_unref();
}
////////////////////////////////////////////////////////////////////
// Function: ConstPointerToArray::Assignment operator
// Access: Public
@ -790,7 +864,7 @@ get_ref_count() const {
////////////////////////////////////////////////////////////////////
template<class Element>
INLINE ConstPointerToArray<Element> &ConstPointerToArray<Element>::
operator = (RefCountObj<pvector<Element> > *ptr) {
operator = (NodeRefCountObj<pvector<Element> > *ptr) {
reassign(ptr);
return *this;
}
@ -829,6 +903,6 @@ operator = (const ConstPointerToArray<Element> &copy) {
template<class Element>
INLINE void ConstPointerToArray<Element>::
clear() {
reassign((RefCountObj<pvector<Element> > *)NULL);
reassign((NodeRefCountObj<pvector<Element> > *)NULL);
}

View File

@ -70,7 +70,7 @@
#include "pandabase.h"
#include "referenceCount.h"
#include "nodeReferenceCount.h"
#include "pointerTo.h"
#include "pvector.h"
@ -87,11 +87,21 @@
// element. This is actually implemented as an STL
// vector, using the RefCountObj class to wrap it up
// with a reference count.
//
// We actually inherit from NodeRefCountObj these days,
// which adds node_ref() and node_unref() to the
// standard ref() and unref(). This is particularly
// useful for GeomVertexArrayData; other classes may or
// may not find this additional counter useful, but
// since it adds relatively little overhead (compared
// with what is presumably a largish array), we go ahead
// and add it here, even though it is inherited by many
// different parts of the system that may not use it.
////////////////////////////////////////////////////////////////////
template <class Element>
class PointerToArray : public PointerToBase<RefCountObj<pvector<Element> > > {
class PointerToArray : public PointerToBase<NodeRefCountObj<pvector<Element> > > {
public:
typedef TYPENAME PointerToBase<RefCountObj<pvector<Element> > >::To To;
typedef TYPENAME PointerToBase<NodeRefCountObj<pvector<Element> > >::To To;
typedef TYPENAME pvector<Element>::value_type value_type;
typedef TYPENAME pvector<Element>::reference reference;
typedef TYPENAME pvector<Element>::const_reference const_reference;
@ -176,9 +186,13 @@ public:
INLINE int get_ref_count() const;
INLINE int get_node_ref_count() const;
INLINE void node_ref() const;
INLINE bool node_unref() const;
// Reassignment is by pointer, not memberwise as with a vector.
INLINE PointerToArray<Element> &
operator = (RefCountObj<pvector<Element> > *ptr);
operator = (NodeRefCountObj<pvector<Element> > *ptr);
INLINE PointerToArray<Element> &
operator = (const PointerToArray<Element> &copy);
INLINE void clear();
@ -198,9 +212,9 @@ private:
// may not be modified.
////////////////////////////////////////////////////////////////////
template <class Element>
class ConstPointerToArray : public PointerToBase<RefCountObj<pvector<Element> > > {
class ConstPointerToArray : public PointerToBase<NodeRefCountObj<pvector<Element> > > {
public:
typedef TYPENAME PointerToBase<RefCountObj<pvector<Element> > >::To To;
typedef TYPENAME PointerToBase<NodeRefCountObj<pvector<Element> > >::To To;
typedef TYPENAME pvector<Element>::value_type value_type;
typedef TYPENAME pvector<Element>::const_reference reference;
typedef TYPENAME pvector<Element>::const_reference const_reference;
@ -258,9 +272,13 @@ public:
INLINE int get_ref_count() const;
INLINE int get_node_ref_count() const;
INLINE void node_ref() const;
INLINE bool node_unref() const;
// Reassignment is by pointer, not memberwise as with a vector.
INLINE ConstPointerToArray<Element> &
operator = (RefCountObj<pvector<Element> > *ptr);
operator = (NodeRefCountObj<pvector<Element> > *ptr);
INLINE ConstPointerToArray<Element> &
operator = (const PointerToArray<Element> &copy);
INLINE ConstPointerToArray<Element> &

View File

@ -69,7 +69,7 @@ get_geom_rendering() const {
////////////////////////////////////////////////////////////////////
INLINE Geom::UsageHint Geom::
get_usage_hint() const {
CDReader cdata(_cycler);
CDLockedReader cdata(_cycler);
if (!cdata->_got_usage_hint) {
CDWriter cdataw(((Geom *)this)->_cycler, cdata, false);
((Geom *)this)->reset_usage_hint(cdataw);
@ -463,7 +463,7 @@ INLINE GeomPipelineReader::
GeomPipelineReader(const Geom *object, Thread *current_thread) :
_object(object),
_current_thread(current_thread),
_cdata(object->_cycler.read(current_thread))
_cdata(object->_cycler.read_unlocked(current_thread))
{
#ifdef _DEBUG
nassertv(_object->test_ref_count_nonzero());
@ -506,7 +506,7 @@ INLINE GeomPipelineReader::
nassertv(_cdata->test_ref_count_nonzero());
#endif // DO_PIPELINING
#endif // _DEBUG
_object->_cycler.release_read(_cdata);
// _object->_cycler.release_read(_cdata);
#ifdef _DEBUG
_object = NULL;
@ -534,19 +534,6 @@ get_current_thread() const {
return _current_thread;
}
////////////////////////////////////////////////////////////////////
// Function: GeomPipelineReader::check_usage_hint
// Access: Public
// Description: Ensures that the Geom's usage_hint cache has been
// computed.
////////////////////////////////////////////////////////////////////
INLINE void GeomPipelineReader::
check_usage_hint() const {
if (!_cdata->_got_usage_hint) {
((Geom *)_object)->reset_usage_hint((Geom::CData *)_cdata);
}
}
////////////////////////////////////////////////////////////////////
// Function: GeomPipelineReader::get_primitive_type
// Access: Public

View File

@ -729,7 +729,7 @@ check_valid(const GeomVertexData *vertex_data) const {
////////////////////////////////////////////////////////////////////
CPT(BoundingVolume) Geom::
get_bounds(Thread *current_thread) const {
CDReader cdata(_cycler, current_thread);
CDLockedReader cdata(_cycler, current_thread);
if (cdata->_internal_bounds_stale) {
CDWriter cdataw(((Geom *)this)->_cycler, cdata, false);
if (cdataw->_user_bounds != (BoundingVolume *)NULL) {
@ -1346,6 +1346,35 @@ fillin(DatagramIterator &scan, BamReader *manager) {
_modified = Geom::get_next_modified();
}
////////////////////////////////////////////////////////////////////
// Function: GeomPipelineReader::check_usage_hint
// Access: Public
// Description: Ensures that the Geom's usage_hint cache has been
// computed.
////////////////////////////////////////////////////////////////////
void GeomPipelineReader::
check_usage_hint() const {
if (!_cdata->_got_usage_hint) {
// We'll need to get a fresh pointer, since another thread might
// already have modified the pointer on the object since we
// queried it.
{
Geom::CDWriter fresh_cdata(((Geom *)_object)->_cycler, _current_thread);
if (!fresh_cdata->_got_usage_hint) {
// The cache is still stale. We have to do the work of
// freshening it.
((Geom *)_object)->reset_usage_hint(fresh_cdata);
nassertv(fresh_cdata->_got_usage_hint);
}
// Save the new pointer, and then let the lock release itself.
((GeomPipelineReader *)this)->_cdata = fresh_cdata;
}
}
nassertv(_cdata->_got_usage_hint);
}
////////////////////////////////////////////////////////////////////
// Function: GeomPipelineReader::check_valid
// Access: Public

View File

@ -22,6 +22,7 @@
#include "pandabase.h"
#include "typedWritableReferenceCount.h"
#include "cycleData.h"
#include "cycleDataLockedReader.h"
#include "cycleDataReader.h"
#include "cycleDataWriter.h"
#include "cycleDataStageReader.h"
@ -261,6 +262,7 @@ private:
};
PipelineCycler<CData> _cycler;
typedef CycleDataLockedReader<CData> CDLockedReader;
typedef CycleDataReader<CData> CDReader;
typedef CycleDataWriter<CData> CDWriter;
typedef CycleDataStageReader<CData> CDStageReader;
@ -330,7 +332,7 @@ public:
INLINE const Geom *get_object() const;
INLINE Thread *get_current_thread() const;
INLINE void check_usage_hint() const;
void check_usage_hint() const;
INLINE PrimitiveType get_primitive_type() const;
INLINE ShadeModel get_shade_model() const;
@ -350,7 +352,7 @@ public:
private:
const Geom *_object;
Thread *_current_thread;
const Geom::CData *_cdata;
CPT(Geom::CData) _cdata;
};
INLINE ostream &operator << (ostream &out, const Geom &obj);

View File

@ -82,10 +82,9 @@ record(Thread *current_thread) {
////////////////////////////////////////////////////////////////////
void GeomCacheEntry::
refresh(Thread *current_thread) {
nassertv(_next != (GeomCacheEntry *)NULL && _prev != (GeomCacheEntry *)NULL);
GeomCacheManager *cache_mgr = GeomCacheManager::get_global_ptr();
MutexHolder holder(cache_mgr->_lock);
nassertv(_next != (GeomCacheEntry *)NULL && _prev != (GeomCacheEntry *)NULL);
remove_from_list();
insert_before(cache_mgr->_list);

View File

@ -478,7 +478,7 @@ GeomPrimitivePipelineReader(const GeomPrimitive *object,
Thread *current_thread) :
_object(object),
_current_thread(current_thread),
_cdata(object->_cycler.read(current_thread)),
_cdata(object->_cycler.read_unlocked(current_thread)),
_vertices_reader(NULL)
{
nassertv(_object->test_ref_count_nonzero());
@ -529,7 +529,7 @@ INLINE GeomPrimitivePipelineReader::
nassertv(_cdata->test_ref_count_nonzero());
#endif // DO_PIPELINING
#endif // _DEBUG
_object->_cycler.release_read(_cdata);
// _object->_cycler.release_read(_cdata);
#ifdef _DEBUG
_vertices_reader = NULL;
@ -558,19 +558,6 @@ get_current_thread() const {
return _current_thread;
}
////////////////////////////////////////////////////////////////////
// Function: GeomPrimitivePipelineReader::check_minmax
// Access: Public
// Description: Ensures that the primitive's minmax cache has been
// computed.
////////////////////////////////////////////////////////////////////
INLINE void GeomPrimitivePipelineReader::
check_minmax() const {
if (!_cdata->_got_minmax) {
((GeomPrimitive *)_object)->recompute_minmax((GeomPrimitive::CData *)_cdata);
}
}
////////////////////////////////////////////////////////////////////
// Function: GeomPrimitivePipelineReader::get_shade_model
// Access: Public

View File

@ -1491,6 +1491,34 @@ fillin(DatagramIterator &scan, BamReader *manager) {
_got_minmax = false;
}
////////////////////////////////////////////////////////////////////
// Function: GeomPrimitivePipelineReader::check_minmax
// Access: Public
// Description: Ensures that the primitive's minmax cache has been
// computed.
////////////////////////////////////////////////////////////////////
void GeomPrimitivePipelineReader::
check_minmax() const {
if (!_cdata->_got_minmax) {
// We'll need to get a fresh pointer, since another thread might
// already have modified the pointer on the object since we
// queried it.
{
GeomPrimitive::CDWriter fresh_cdata(((GeomPrimitive *)_object)->_cycler, _current_thread);
if (!fresh_cdata->_got_minmax) {
// The cache is still stale. We have to do the work of
// freshening it.
((GeomPrimitive *)_object)->recompute_minmax(fresh_cdata);
nassertv(fresh_cdata->_got_minmax);
}
// Save the new pointer, and then let the lock release itself.
((GeomPrimitivePipelineReader *)this)->_cdata = fresh_cdata;
}
}
nassertv(_cdata->_got_minmax);
}
////////////////////////////////////////////////////////////////////
// Function: GeomPrimitivePipelineReader::get_first_vertex

View File

@ -309,7 +309,7 @@ public:
INLINE const GeomPrimitive *get_object() const;
INLINE Thread *get_current_thread() const;
INLINE void check_minmax() const;
void check_minmax() const;
INLINE ShadeModel get_shade_model() const;
INLINE UsageHint get_usage_hint() const;
@ -334,7 +334,7 @@ public:
private:
const GeomPrimitive *_object;
Thread *_current_thread;
const GeomPrimitive::CData *_cdata;
CPT(GeomPrimitive::CData) _cdata;
GeomVertexArrayDataPipelineReader *_vertices_reader;
};

View File

@ -183,6 +183,7 @@ INLINE GeomVertexArrayData::CData::
CData() :
_usage_hint(UH_unspecified)
{
_data.node_ref();
}
////////////////////////////////////////////////////////////////////
@ -196,6 +197,7 @@ CData(const GeomVertexArrayData::CData &copy) :
_data(copy._data),
_modified(copy._modified)
{
_data.node_ref();
}
////////////////////////////////////////////////////////////////////
@ -293,7 +295,7 @@ GeomVertexArrayDataPipelineReader(const GeomVertexArrayData *object,
Thread *current_thread) :
GeomVertexArrayDataPipelineBase((GeomVertexArrayData *)object,
current_thread,
(GeomVertexArrayData::CData *)object->_cycler.read(current_thread))
(GeomVertexArrayData::CData *)object->_cycler.read_unlocked(current_thread))
{
#ifdef _DEBUG
nassertv(_object->test_ref_count_nonzero());
@ -338,7 +340,7 @@ INLINE GeomVertexArrayDataPipelineReader::
nassertv(_cdata->test_ref_count_nonzero());
#endif // DO_PIPELINING
#endif // _DEBUG
_object->_cycler.release_read(_cdata);
// _object->_cycler.release_read(_cdata);
#ifdef _DEBUG
_object = NULL;

View File

@ -432,6 +432,9 @@ finalize(BamReader *manager) {
// Now is the time to endian-reverse the data.
cdata->_data = reverse_data_endianness(cdata->_data);
}
// Now is also the time to node_ref the data.
cdata->_data.node_ref();
}
////////////////////////////////////////////////////////////////////
@ -470,6 +473,16 @@ fillin(DatagramIterator &scan, BamReader *manager) {
manager->read_cdata(scan, _cycler, this);
}
////////////////////////////////////////////////////////////////////
// Function: GeomVertexArrayData::CData::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
GeomVertexArrayData::CData::
~CData() {
_data.node_unref();
}
////////////////////////////////////////////////////////////////////
// Function: GeomVertexArrayData::CData::make_copy
// Access: Public, Virtual
@ -520,7 +533,7 @@ set_num_rows(int n) {
int delta = n - (_cdata->_data.size() / stride);
if (delta != 0) {
if (_cdata->_data.get_ref_count() > 1) {
if (_cdata->_data.get_node_ref_count() > 1) {
// Copy-on-write: the data is already reffed somewhere else,
// so we're just going to make a copy.
PTA_uchar new_data;
@ -528,7 +541,9 @@ set_num_rows(int n) {
new_data.insert(new_data.end(), n * stride, 0);
memcpy(new_data, _cdata->_data,
min((size_t)(n * stride), _cdata->_data.size()));
_cdata->_data.node_unref();
_cdata->_data = new_data;
_cdata->_data.node_ref();
} else {
// We've got the only reference to the data, so we can change
@ -557,13 +572,16 @@ set_num_rows(int n) {
////////////////////////////////////////////////////////////////////
PTA_uchar GeomVertexArrayDataPipelineWriter::
modify_data() {
// Perform copy-on-write: if the reference count on the vertex data
// is greater than 1, assume some other GeomVertexData has the same
// pointer, so make a copy of it first.
if (_cdata->_data.get_ref_count() > 1) {
// Perform copy-on-write: if the *node* reference count on the
// vertex data is greater than 1, assume some other
// GeomVertexArrayData has the same pointer, so make a copy of it
// first.
if (_cdata->_data.get_node_ref_count() > 1) {
PTA_uchar orig_data = _cdata->_data;
_cdata->_data.node_unref();
_cdata->_data = PTA_uchar();
_cdata->_data.v() = orig_data.v();
_cdata->_data.node_ref();
}
_cdata->_modified = Geom::get_next_modified();
@ -577,6 +595,8 @@ modify_data() {
////////////////////////////////////////////////////////////////////
void GeomVertexArrayDataPipelineWriter::
set_data(CPTA_uchar array) {
_cdata->_data.node_unref();
_cdata->_data = (PTA_uchar &)array;
_cdata->_data.node_ref();
_cdata->_modified = Geom::get_next_modified();
}

View File

@ -120,6 +120,7 @@ private:
public:
INLINE CData();
INLINE CData(const CData &copy);
virtual ~CData();
ALLOC_DELETED_CHAIN(CData);
virtual CycleData *make_copy() const;
virtual void write_datagram(BamWriter *manager, Datagram &dg,
@ -207,7 +208,7 @@ public:
protected:
GeomVertexArrayData *_object;
Thread *_current_thread;
GeomVertexArrayData::CData *_cdata;
PT(GeomVertexArrayData::CData) _cdata;
};
////////////////////////////////////////////////////////////////////

View File

@ -590,7 +590,7 @@ INLINE GeomVertexDataPipelineReader::
GeomVertexDataPipelineReader(const GeomVertexData *object,
Thread *current_thread) :
GeomVertexDataPipelineBase((GeomVertexData *)object, current_thread,
(GeomVertexData::CData *)object->_cycler.read(current_thread)),
(GeomVertexData::CData *)object->_cycler.read_unlocked(current_thread)),
_got_array_readers(false)
{
nassertv(_object->test_ref_count_nonzero());
@ -637,7 +637,7 @@ INLINE GeomVertexDataPipelineReader::
nassertv(_cdata->test_ref_count_nonzero());
#endif // DO_PIPELINING
#endif // _DEBUG
_object->_cycler.release_read(_cdata);
// _object->_cycler.release_read(_cdata);
#ifdef _DEBUG
_object = NULL;

View File

@ -243,7 +243,7 @@ set_format(const GeomVertexFormat *format) {
Thread *current_thread = Thread::get_current_thread();
nassertv(format->is_registered());
CDReader cdata(_cycler, current_thread);
CDLockedReader cdata(_cycler, current_thread);
if (format == cdata->_format) {
// Trivially no-op.
@ -902,7 +902,7 @@ set_color(const Colorf &color, int num_components,
////////////////////////////////////////////////////////////////////
CPT(GeomVertexData) GeomVertexData::
animate_vertices(Thread *current_thread) const {
CDReader cdata(_cycler, current_thread);
CDLockedReader cdata(_cycler, current_thread);
if (cdata->_format->get_animation().get_animation_type() != AT_panda) {
return this;
@ -1812,13 +1812,14 @@ set_num_rows(int n) {
if (color_array >= 0 && orig_color_rows < n) {
// We have just added some rows, fill the "color" column with
// (1, 1, 1, 1), for the programmer's convenience.
GeomVertexArrayData *array_data = _cdata->_arrays[color_array];
GeomVertexArrayDataPipelineWriter *array_writer = _array_writers[color_array];
const GeomVertexArrayFormat *array_format = array_writer->get_array_format();
const GeomVertexColumn *column =
array_data->get_array_format()->get_column(InternalName::get_color());
int stride = array_data->get_array_format()->get_stride();
array_format->get_column(InternalName::get_color());
int stride = array_format->get_stride();
unsigned char *start =
array_data->modify_data() + column->get_start();
unsigned char *stop = start + array_data->get_data_size_bytes();
array_writer->modify_data() + column->get_start();
unsigned char *stop = start + array_writer->get_data_size_bytes();
unsigned char *pointer = start + stride * orig_color_rows;
int num_values = column->get_num_values();

View File

@ -31,6 +31,7 @@
#include "sliderTable.h"
#include "internalName.h"
#include "cycleData.h"
#include "cycleDataLockedReader.h"
#include "cycleDataReader.h"
#include "cycleDataWriter.h"
#include "cycleDataStageReader.h"
@ -257,6 +258,7 @@ private:
};
PipelineCycler<CData> _cycler;
typedef CycleDataLockedReader<CData> CDLockedReader;
typedef CycleDataReader<CData> CDReader;
typedef CycleDataWriter<CData> CDWriter;
typedef CycleDataStageReader<CData> CDStageReader;
@ -341,7 +343,7 @@ public:
protected:
GeomVertexData *_object;
Thread *_current_thread;
GeomVertexData::CData *_cdata;
PT(GeomVertexData::CData) _cdata;
};
////////////////////////////////////////////////////////////////////

View File

@ -147,6 +147,7 @@ GeomVertexReader(const GeomVertexReader &copy) :
_current_thread(copy._current_thread),
_packer(copy._packer),
_stride(copy._stride),
_data(copy._data),
_pointer_begin(copy._pointer_begin),
_pointer_end(copy._pointer_end),
_pointer(copy._pointer),
@ -167,6 +168,7 @@ operator = (const GeomVertexReader &copy) {
_current_thread = copy._current_thread;
_packer = copy._packer;
_stride = copy._stride;
_data = copy._data;
_pointer_begin = copy._pointer_begin;
_pointer_end = copy._pointer_end;
_pointer = copy._pointer;
@ -510,7 +512,8 @@ get_packer() const {
////////////////////////////////////////////////////////////////////
INLINE void GeomVertexReader::
set_pointer(int row, const GeomVertexArrayDataPipelineReader *array_reader) {
_pointer_begin = array_reader->get_data();
_data = array_reader->get_data();
_pointer_begin = _data;
_pointer_end = _pointer_begin + array_reader->get_data_size_bytes();
quick_set_pointer(row);
}
@ -526,7 +529,12 @@ INLINE void GeomVertexReader::
quick_set_pointer(int row) {
nassertv(has_column());
#ifdef _DEBUG
#if defined(_DEBUG) && !defined(HAVE_THREADS)
// Make sure we still have the same pointer as stored the array. We
// only perform this test in debug mode, because it is expensive,
// and only in single-threaded mode, because in threaded mode
// another thread might have reallocated the other pointer outside
// of our control anyway.
if (_vertex_data != (const GeomVertexData *)NULL) {
const GeomVertexArrayData *array_data = _vertex_data->get_array(_array);
nassertv(_pointer_begin == array_data->get_data());

View File

@ -143,6 +143,7 @@ private:
GeomVertexColumn::Packer *_packer;
int _stride;
CPTA_uchar _data;
const unsigned char *_pointer_begin;
const unsigned char *_pointer_end;
const unsigned char *_pointer;

View File

@ -145,6 +145,7 @@ GeomVertexWriter(const GeomVertexWriter &copy) :
_current_thread(copy._current_thread),
_packer(copy._packer),
_stride(copy._stride),
_data(copy._data),
_pointer_begin(copy._pointer_begin),
_pointer_end(copy._pointer_end),
_pointer(copy._pointer),
@ -165,6 +166,7 @@ operator = (const GeomVertexWriter &copy) {
_current_thread = copy._current_thread;
_packer = copy._packer;
_stride = copy._stride;
_data = copy._data;
_pointer_begin = copy._pointer_begin;
_pointer_end = copy._pointer_end;
_pointer = copy._pointer;
@ -813,7 +815,8 @@ get_packer() const {
////////////////////////////////////////////////////////////////////
INLINE void GeomVertexWriter::
set_pointer(int row, GeomVertexArrayDataPipelineWriter *array_writer) {
_pointer_begin = array_writer->modify_data();
_data = array_writer->modify_data();
_pointer_begin = _data;
_pointer_end = _pointer_begin + array_writer->get_data_size_bytes();
quick_set_pointer(row);
}
@ -829,7 +832,12 @@ INLINE void GeomVertexWriter::
quick_set_pointer(int row) {
nassertv(has_column());
#ifdef _DEBUG
#if defined(_DEBUG) && !defined(HAVE_THREADS)
// Make sure we still have the same pointer as stored the array. We
// only perform this test in debug mode, because it is expensive,
// and only in single-threaded mode, because in threaded mode
// another thread might have reallocated the other pointer outside
// of our control anyway.
if (_vertex_data != (const GeomVertexData *)NULL) {
const GeomVertexArrayData *array_data = _vertex_data->get_array(_array);
nassertv(_pointer_begin == array_data->get_data());

View File

@ -181,6 +181,7 @@ private:
GeomVertexColumn::Packer *_packer;
int _stride;
PTA_uchar _data;
unsigned char *_pointer_begin;
unsigned char *_pointer_end;
unsigned char *_pointer;

View File

@ -211,7 +211,7 @@ set_weight(int n, float weight) {
////////////////////////////////////////////////////////////////////
INLINE void TransformBlend::
update_blend(Thread *current_thread) const {
CDReader cdata(_cycler, current_thread);
CDLockedReader cdata(_cycler, current_thread);
if (cdata->_global_modified != VertexTransform::get_global_modified(current_thread)) {
CDWriter cdataw(((TransformBlend *)this)->_cycler, cdata, false);
((TransformBlend *)this)->recompute_result(cdataw, current_thread);
@ -290,7 +290,7 @@ transform_vector(LVector3f &vector, Thread *current_thread) const {
////////////////////////////////////////////////////////////////////
INLINE UpdateSeq TransformBlend::
get_modified(Thread *current_thread) const {
CDReader cdata(_cycler, current_thread);
CDLockedReader cdata(_cycler, current_thread);
if (cdata->_global_modified != VertexTransform::get_global_modified(current_thread)) {
CDWriter cdataw(((TransformBlend *)this)->_cycler, cdata, false);
((TransformBlend *)this)->recompute_result(cdataw, current_thread);

View File

@ -25,6 +25,7 @@
#include "pvector.h"
#include "ordered_vector.h"
#include "cycleData.h"
#include "cycleDataLockedReader.h"
#include "cycleDataReader.h"
#include "cycleDataWriter.h"
#include "pipelineCycler.h"
@ -114,6 +115,7 @@ private:
};
PipelineCycler<CData> _cycler;
typedef CycleDataLockedReader<CData> CDLockedReader;
typedef CycleDataReader<CData> CDReader;
typedef CycleDataWriter<CData> CDWriter;

View File

@ -48,7 +48,7 @@ get_blend(int n) const {
////////////////////////////////////////////////////////////////////
INLINE UpdateSeq TransformBlendTable::
get_modified(Thread *current_thread) const {
CDReader cdata(_cycler);
CDLockedReader cdata(_cycler);
if (cdata->_global_modified != VertexTransform::get_global_modified(current_thread)) {
CDWriter cdataw(((TransformBlendTable *)this)->_cycler, cdata, false);
((TransformBlendTable *)this)->recompute_modified(cdataw, current_thread);

View File

@ -28,6 +28,7 @@
#include "pmap.h"
#include "indirectLess.h"
#include "cycleData.h"
#include "cycleDataLockedReader.h"
#include "cycleDataReader.h"
#include "cycleDataWriter.h"
#include "pipelineCycler.h"
@ -115,6 +116,7 @@ private:
};
PipelineCycler<CData> _cycler;
typedef CycleDataLockedReader<CData> CDLockedReader;
typedef CycleDataReader<CData> CDReader;
typedef CycleDataWriter<CData> CDWriter;

View File

@ -133,7 +133,7 @@ get_next(int pipeline_stage, Thread *current_thread) const {
////////////////////////////////////////////////////////////////////
bool NodePathComponent::
fix_length(int pipeline_stage, Thread *current_thread) {
CDStageReader cdata(_cycler, pipeline_stage, current_thread);
CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
int length_should_be = 1;
if (cdata->_next != (NodePathComponent *)NULL) {

View File

@ -27,6 +27,7 @@
#include "cycleData.h"
#include "cycleDataReader.h"
#include "cycleDataWriter.h"
#include "cycleDataLockedStageReader.h"
#include "cycleDataStageReader.h"
#include "cycleDataStageWriter.h"
#include "pmutex.h"
@ -100,6 +101,7 @@ private:
PipelineCycler<CData> _cycler;
typedef CycleDataReader<CData> CDReader;
typedef CycleDataWriter<CData> CDWriter;
typedef CycleDataLockedStageReader<CData> CDLockedStageReader;
typedef CycleDataStageReader<CData> CDStageReader;
typedef CycleDataStageWriter<CData> CDStageWriter;

View File

@ -1161,7 +1161,7 @@ INLINE PandaNodePipelineReader::
PandaNodePipelineReader(const PandaNode *object, Thread *current_thread) :
_object(object),
_current_thread(current_thread),
_cdata(object->_cycler.read(current_thread))
_cdata(object->_cycler.read_unlocked(current_thread))
{
#ifdef _DEBUG
nassertv(_object->test_ref_count_nonzero());
@ -1182,9 +1182,11 @@ PandaNodePipelineReader(const PandaNodePipelineReader &copy) :
_current_thread(copy._current_thread),
_cdata(copy._cdata)
{
/*
if (_cdata != (PandaNode::CData *)NULL) {
_object->_cycler.increment_read(_cdata);
}
*/
}
////////////////////////////////////////////////////////////////////
@ -1196,16 +1198,20 @@ INLINE void PandaNodePipelineReader::
operator = (const PandaNodePipelineReader &copy) {
nassertv(_current_thread == copy._current_thread);
/*
if (_cdata != (PandaNode::CData *)NULL) {
_object->_cycler.release_read(_cdata);
}
*/
_object = copy._object;
_cdata = copy._cdata;
/*
if (_cdata != (PandaNode::CData *)NULL) {
_object->_cycler.increment_read(_cdata);
}
*/
}
////////////////////////////////////////////////////////////////////
@ -1215,9 +1221,11 @@ operator = (const PandaNodePipelineReader &copy) {
////////////////////////////////////////////////////////////////////
INLINE PandaNodePipelineReader::
~PandaNodePipelineReader() {
/*
if (_cdata != (PandaNode::CData *)NULL) {
_object->_cycler.release_read(_cdata);
}
*/
#ifdef _DEBUG
_object = NULL;
@ -1253,30 +1261,12 @@ get_current_thread() const {
////////////////////////////////////////////////////////////////////
INLINE void PandaNodePipelineReader::
release() {
/*
if (_cdata != (PandaNode::CData *)NULL) {
_object->_cycler.release_read(_cdata);
_cdata = NULL;
}
}
////////////////////////////////////////////////////////////////////
// Function: PandaNodePipelineReader::check_bounds
// Access: Public
// Description: Ensures that the bounding volume is properly computed
// on this node.
////////////////////////////////////////////////////////////////////
INLINE void PandaNodePipelineReader::
check_bounds() const {
nassertv(_cdata != (PandaNode::CData *)NULL);
if (_cdata->_last_update != _cdata->_next_update) {
// The cache is stale; it needs to be rebuilt.
// We should technically drop _cdata while we do this operation,
// but at the moment, it doesn't really matter.
int pipeline_stage = _current_thread->get_pipeline_stage();
PandaNode::CDStageReader fresh_cdata(_object->_cycler, pipeline_stage, _current_thread);
((PandaNode *)_object)->update_bounds(pipeline_stage, fresh_cdata);
}
*/
}
////////////////////////////////////////////////////////////////////

View File

@ -1404,8 +1404,7 @@ copy_tags(PandaNode *other) {
Thread *current_thread = Thread::get_current_thread();
OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
CDStageWriter cdataw(_cycler, pipeline_stage, current_thread);
CDStageReader cdatar(other->_cycler, pipeline_stage,
current_thread);
CDStageReader cdatar(other->_cycler, pipeline_stage, current_thread);
TagData::const_iterator ti;
for (ti = cdatar->_tag_data.begin();
@ -1565,7 +1564,7 @@ DrawMask PandaNode::
get_net_draw_control_mask() const {
Thread *current_thread = Thread::get_current_thread();
int pipeline_stage = current_thread->get_pipeline_stage();
CDStageReader cdata(_cycler, pipeline_stage, current_thread);
CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
if (cdata->_last_update != cdata->_next_update) {
// The cache is stale; it needs to be rebuilt.
CDStageWriter cdataw =
@ -1595,7 +1594,7 @@ DrawMask PandaNode::
get_net_draw_show_mask() const {
Thread *current_thread = Thread::get_current_thread();
int pipeline_stage = current_thread->get_pipeline_stage();
CDStageReader cdata(_cycler, pipeline_stage, current_thread);
CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
if (cdata->_last_update != cdata->_next_update) {
// The cache is stale; it needs to be rebuilt.
CDStageWriter cdataw =
@ -1667,7 +1666,7 @@ get_legal_collide_mask() const {
CollideMask PandaNode::
get_net_collide_mask(Thread *current_thread) const {
int pipeline_stage = current_thread->get_pipeline_stage();
CDStageReader cdata(_cycler, pipeline_stage, current_thread);
CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
if (cdata->_last_update != cdata->_next_update) {
// The cache is stale; it needs to be rebuilt.
CDStageWriter cdataw =
@ -1687,7 +1686,7 @@ get_net_collide_mask(Thread *current_thread) const {
CPT(RenderAttrib) PandaNode::
get_off_clip_planes(Thread *current_thread) const {
int pipeline_stage = current_thread->get_pipeline_stage();
CDStageReader cdata(_cycler, pipeline_stage, current_thread);
CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
if (cdata->_last_update != cdata->_next_update) {
// The cache is stale; it needs to be rebuilt.
CDStageWriter cdataw =
@ -1808,7 +1807,7 @@ set_bound(const BoundingVolume *volume) {
CPT(BoundingVolume) PandaNode::
get_bounds(Thread *current_thread) const {
int pipeline_stage = current_thread->get_pipeline_stage();
CDStageReader cdata(_cycler, pipeline_stage, current_thread);
CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
if (cdata->_last_update != cdata->_next_update) {
// The cache is stale; it needs to be rebuilt.
CPT(BoundingVolume) result;
@ -1900,7 +1899,7 @@ as_light() {
////////////////////////////////////////////////////////////////////
CPT(BoundingVolume) PandaNode::
get_internal_bounds(int pipeline_stage, Thread *current_thread) const {
CDStageReader cdata(_cycler, pipeline_stage, current_thread);
CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
if (cdata->_internal_bounds_stale) {
CDStageWriter cdataw(((PandaNode *)this)->_cycler, pipeline_stage, cdata);
if (cdataw->_user_bounds != (BoundingVolume *)NULL) {
@ -2868,7 +2867,7 @@ r_list_descendants(ostream &out, int indent_level) const {
// released. The new value is returned.
////////////////////////////////////////////////////////////////////
PandaNode::CDStageWriter PandaNode::
update_bounds(int pipeline_stage, PandaNode::CDStageReader &cdata) {
update_bounds(int pipeline_stage, PandaNode::CDLockedStageReader &cdata) {
// We might need to try this a couple of times, in case someone else
// steps on our result.
if (drawmask_cat.is_debug()) {
@ -2878,24 +2877,20 @@ update_bounds(int pipeline_stage, PandaNode::CDStageReader &cdata) {
Thread *current_thread = cdata.get_current_thread();
do {
// Grab the last_update counter, then release the lock.
// Grab the last_update counter.
UpdateSeq last_update = cdata->_last_update;
UpdateSeq next_update = cdata->_next_update;
nassertr(last_update != next_update, CDStageWriter(_cycler, pipeline_stage, cdata));
_cycler.release_read_stage(pipeline_stage, cdata.take_pointer());
// Start with a clean slate, or at least with the contents of the
// node itself.
CollideMask net_collide_mask;
CollideMask net_collide_mask = cdata->_into_collide_mask;
DrawMask net_draw_control_mask, net_draw_show_mask;
DrawMask draw_control_mask, draw_show_mask;
draw_control_mask = net_draw_control_mask = cdata->_draw_control_mask;
draw_show_mask = net_draw_show_mask = cdata->_draw_show_mask;
bool renderable = is_renderable();
{
CDStageReader cdata(_cycler, pipeline_stage, current_thread);
net_collide_mask = cdata->_into_collide_mask;
draw_control_mask = net_draw_control_mask = cdata->_draw_control_mask;
draw_show_mask = net_draw_show_mask = cdata->_draw_show_mask;
}
if (!renderable) {
// This is not a "renderable" node. This means that this node
// does not itself contribute any bits to net_draw_show_mask or
@ -2914,15 +2909,18 @@ update_bounds(int pipeline_stage, PandaNode::CDStageReader &cdata) {
<< "\ndraw_show_mask = " << draw_show_mask
<< "\n";
}
CPT(RenderAttrib) off_clip_planes;
{
CDStageReader cdata(_cycler, pipeline_stage, current_thread);
off_clip_planes = cdata->_state->get_clip_plane();
}
CPT(RenderAttrib) off_clip_planes = cdata->_state->get_clip_plane();
if (off_clip_planes == (RenderAttrib *)NULL) {
off_clip_planes = ClipPlaneAttrib::make();
}
// Also get the list of the node's children.
Children children(cdata);
// Now that we've got all the data we need from the node, we can
// release the lock.
_cycler.release_read_stage(pipeline_stage, cdata.take_pointer());
// We need to keep references to the bounding volumes, since in a
// threaded environment the pointers might go away while we're
// working (since we're not holding a lock on our set of children
@ -2937,7 +2935,6 @@ update_bounds(int pipeline_stage, PandaNode::CDStageReader &cdata) {
child_volumes.push_back(internal_bounds);
// Now expand those contents to include all of our children.
Children children = get_children(current_thread);
int num_children = children.get_num_children();
for (int i = 0; i < num_children; ++i) {
@ -2945,7 +2942,7 @@ update_bounds(int pipeline_stage, PandaNode::CDStageReader &cdata) {
const ClipPlaneAttrib *orig_cp = DCAST(ClipPlaneAttrib, off_clip_planes);
CDStageReader child_cdata(child->_cycler, pipeline_stage, current_thread);
CDLockedStageReader child_cdata(child->_cycler, pipeline_stage, current_thread);
if (child_cdata->_last_update != child_cdata->_next_update) {
// Child needs update.
CDStageWriter child_cdataw = child->update_bounds(pipeline_stage, child_cdata);
@ -3089,7 +3086,7 @@ update_bounds(int pipeline_stage, PandaNode::CDStageReader &cdata) {
// We need to go around again. Release the write lock, and grab
// the read lock back.
cdata = CDStageReader(_cycler, pipeline_stage, current_thread);
cdata = CDLockedStageReader(_cycler, pipeline_stage, current_thread);
if (cdata->_last_update == cdata->_next_update) {
// Someone else has computed the cache for us while we were
@ -3633,3 +3630,41 @@ fillin_down_list(PandaNode::Down &down_list,
down_list.push_back(DownConnection(NULL, sort));
}
}
////////////////////////////////////////////////////////////////////
// Function: PandaNodePipelineReader::check_bounds
// Access: Public
// Description: Ensures that the bounding volume is properly computed
// on this node.
////////////////////////////////////////////////////////////////////
void PandaNodePipelineReader::
check_bounds() const {
if (_cdata->_last_update != _cdata->_next_update) {
// The cache is stale; it needs to be rebuilt.
// We'll need to get a fresh read pointer, since another thread
// might already have modified the pointer on the object since we
// queried it.
{
int pipeline_stage = _current_thread->get_pipeline_stage();
PandaNode::CDLockedStageReader fresh_cdata(_object->_cycler, pipeline_stage, _current_thread);
if (fresh_cdata->_last_update == fresh_cdata->_next_update) {
// What luck, some other thread has already freshened the
// cache for us. Save the new pointer, and let the lock
// release itself.
((PandaNodePipelineReader *)this)->_cdata = fresh_cdata;
} else {
// No, the cache is still stale. We have to do the work of
// freshening it.
PandaNode::CDStageWriter cdataw = ((PandaNode *)_object)->update_bounds(pipeline_stage, fresh_cdata);
nassertv(cdataw->_last_update == cdataw->_next_update);
// As above, we save the new pointer, and then let the lock
// release itself.
((PandaNodePipelineReader *)this)->_cdata = cdataw;
}
}
}
nassertv(_cdata->_last_update == _cdata->_next_update);
}

View File

@ -24,6 +24,7 @@
#include "cycleData.h"
#include "cycleDataReader.h"
#include "cycleDataWriter.h"
#include "cycleDataLockedStageReader.h"
#include "cycleDataStageReader.h"
#include "cycleDataStageWriter.h"
#include "pipelineCycler.h"
@ -505,10 +506,11 @@ private:
PipelineCycler<CData> _cycler;
typedef CycleDataReader<CData> CDReader;
typedef CycleDataWriter<CData> CDWriter;
typedef CycleDataLockedStageReader<CData> CDLockedStageReader;
typedef CycleDataStageReader<CData> CDStageReader;
typedef CycleDataStageWriter<CData> CDStageWriter;
CDStageWriter update_bounds(int pipeline_stage, CDStageReader &cdata);
CDStageWriter update_bounds(int pipeline_stage, CDLockedStageReader &cdata);
static DrawMask _overall_bit;
@ -631,7 +633,7 @@ public:
INLINE void release();
INLINE void check_bounds() const;
void check_bounds() const;
INLINE void compose_draw_mask(DrawMask &running_draw_mask) const;
INLINE bool compare_draw_mask(DrawMask running_draw_mask,
@ -671,7 +673,7 @@ public:
private:
const PandaNode *_object;
Thread *_current_thread;
const PandaNode::CData *_cdata;
CPT(PandaNode::CData) _cdata;
};
INLINE ostream &operator << (ostream &out, const PandaNode &node) {

View File

@ -222,7 +222,7 @@ compute_internal_bounds(int pipeline_stage, Thread *current_thread) const {
////////////////////////////////////////////////////////////////////
PT(Geom) PlaneNode::
get_viz(CullTraverser *trav, CullTraverserData &data) {
CDReader cdata(_cycler);
CDLockedReader cdata(_cycler);
// Figure out whether we are looking at the front or the back of the
// plane.

View File

@ -26,6 +26,7 @@
#include "updateSeq.h"
#include "geom.h"
#include "cycleData.h"
#include "cycleDataLockedReader.h"
#include "cycleDataReader.h"
#include "cycleDataWriter.h"
#include "cycleDataStageReader.h"
@ -97,6 +98,7 @@ private:
};
PipelineCycler<CData> _cycler;
typedef CycleDataLockedReader<CData> CDLockedReader;
typedef CycleDataReader<CData> CDReader;
typedef CycleDataWriter<CData> CDWriter;
typedef CycleDataStageReader<CData> CDStageReader;

View File

@ -22,6 +22,8 @@
conditionVarSpinlockImpl.h conditionVarSpinlockImpl.I \
config_pipeline.h \
cycleData.h cycleData.I \
cycleDataLockedReader.h cycleDataLockedReader.I \
cycleDataLockedStageReader.h cycleDataLockedStageReader.I \
cycleDataReader.h cycleDataReader.I \
cycleDataStageReader.h cycleDataStageReader.I \
cycleDataStageWriter.h cycleDataStageWriter.I \
@ -62,6 +64,8 @@
conditionVarSpinlockImpl.cxx \
config_pipeline.cxx \
cycleData.cxx \
cycleDataLockedReader.cxx \
cycleDataLockedStageReader.cxx \
cycleDataReader.cxx \
cycleDataStageReader.cxx \
cycleDataStageWriter.cxx \
@ -100,6 +104,8 @@
conditionVarSpinlockImpl.h conditionVarSpinlockImpl.I \
config_pipeline.h \
cycleData.h cycleData.I \
cycleDataLockedReader.h cycleDataLockedReader.I \
cycleDataLockedStageReader.h cycleDataLockedStageReader.I \
cycleDataReader.h cycleDataReader.I \
cycleDataStageReader.h cycleDataStageReader.I \
cycleDataStageWriter.h cycleDataStageWriter.I \

View File

@ -21,7 +21,7 @@
#include "pandabase.h"
#include "typeHandle.h"
#include "referenceCount.h"
#include "nodeReferenceCount.h"
class BamWriter;
class BamReader;
@ -40,8 +40,11 @@ class DatagramIterator;
// If we are compiling in pipelining support, we maintain a pointer to
// a CycleData object in each containing class, instead of the object
// itself. Thus, it should be a ReferenceCount object.
class EXPCL_PANDA CycleData : public ReferenceCount
// itself. Thus, it should be a ReferenceCount object. Furthermore,
// since we want to make a distinction between references within the
// cycler, and references outside the cycler
// (e.g. GeomPipelineReader), we make it a NodeReferenceCount.
class EXPCL_PANDA CycleData : public NodeReferenceCount
#else // !DO_PIPELINING

View File

@ -0,0 +1,242 @@
// Filename: cycleDataLockedReader.I
// Created by: drose (30Apr06)
//
////////////////////////////////////////////////////////////////////
//
// 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 .
//
////////////////////////////////////////////////////////////////////
#ifdef DO_PIPELINING
// This is the implementation for full support of pipelining (as well
// as the sanity-check only implementation).
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedReader::Constructor (full)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataLockedReader<CycleDataType>::
CycleDataLockedReader(const PipelineCycler<CycleDataType> &cycler,
Thread *current_thread) :
_cycler(&cycler),
_current_thread(current_thread)
{
_pointer = _cycler->read(_current_thread);
nassertv(_pointer != (const CycleDataType *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedReader::Copy Constructor (full)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataLockedReader<CycleDataType>::
CycleDataLockedReader(const CycleDataLockedReader<CycleDataType> &copy) :
_cycler(copy._cycler),
_current_thread(copy._current_thread),
_pointer(copy._pointer)
{
nassertv(_pointer != (const CycleDataType *)NULL);
_cycler->increment_read(_pointer);
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedReader::Copy Assignment (full)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE void CycleDataLockedReader<CycleDataType>::
operator = (const CycleDataLockedReader<CycleDataType> &copy) {
nassertv(_pointer == (CycleDataType *)NULL);
nassertv(_current_thread == copy._current_thread);
_cycler = copy._cycler;
_pointer = copy._pointer;
nassertv(_pointer != (const CycleDataType *)NULL);
_cycler->increment_read(_pointer);
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedReader::Destructor (full)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataLockedReader<CycleDataType>::
~CycleDataLockedReader() {
if (_pointer != NULL) {
_cycler->release_read(_pointer);
}
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedReader::operator -> (full)
// Access: Public
// Description: This provides an indirect member access to the actual
// CycleData data.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE const CycleDataType *CycleDataLockedReader<CycleDataType>::
operator -> () const {
nassertr(_pointer != (const CycleDataType *)NULL, _cycler->cheat());
return _pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedReader::Typecast pointer (full)
// Access: Public
// Description: This allows the CycleDataLockedReader to be passed to any
// function that expects a const CycleDataType pointer.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataLockedReader<CycleDataType>::
operator const CycleDataType * () const {
nassertr(_pointer != (const CycleDataType *)NULL, _cycler->cheat());
return _pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedReader::take_pointer (full)
// Access: Public
// Description: This is intended to be called only from
// CycleDataWriter when it elevates the pointer from
// read to write status. This function returns the
// reader's pointer and relinquishes ownership of the
// pointer, rendering the reader invalid for future
// reads.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE const CycleDataType *CycleDataLockedReader<CycleDataType>::
take_pointer() {
const CycleDataType *pointer = _pointer;
_pointer = (CycleDataType *)NULL;
nassertr(pointer != (const CycleDataType *)NULL, _cycler->cheat());
return pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedReader::get_current_thread (full)
// Access: Public
// Description: Returns the Thread pointer of the currently-executing
// thread, as passed to the constructor of this object.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE Thread *CycleDataLockedReader<CycleDataType>::
get_current_thread() const {
return _current_thread;
}
#else // !DO_PIPELINING
// This is the trivial, do-nothing implementation.
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedReader::Constructor (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataLockedReader<CycleDataType>::
CycleDataLockedReader(const PipelineCycler<CycleDataType> &cycler, Thread *) {
_pointer = cycler.cheat();
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedReader::Copy Constructor (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataLockedReader<CycleDataType>::
CycleDataLockedReader(const CycleDataLockedReader<CycleDataType> &copy) :
_pointer(copy._pointer)
{
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedReader::Copy Assignment (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE void CycleDataLockedReader<CycleDataType>::
operator = (const CycleDataLockedReader<CycleDataType> &copy) {
_pointer = copy._pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedReader::Destructor (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataLockedReader<CycleDataType>::
~CycleDataLockedReader() {
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedReader::operator -> (trivial)
// Access: Public
// Description: This provides an indirect member access to the actual
// CycleData data.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE const CycleDataType *CycleDataLockedReader<CycleDataType>::
operator -> () const {
return _pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedReader::Typecast pointer (trivial)
// Access: Public
// Description: This allows the CycleDataLockedReader to be passed to any
// function that expects a const CycleDataType pointer.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataLockedReader<CycleDataType>::
operator const CycleDataType * () const {
return _pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedReader::take_pointer (trivial)
// Access: Public
// Description: This is intended to be called only from
// CycleDataWriter when it elevates the pointer from
// read to write status. This function returns the
// reader's pointer and relinquishes ownership of the
// pointer, rendering the reader invalid for future
// reads.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE const CycleDataType *CycleDataLockedReader<CycleDataType>::
take_pointer() {
return _pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedReader::get_current_thread (trivial)
// Access: Public
// Description: Returns the Thread pointer of the currently-executing
// thread, as passed to the constructor of this object.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE Thread *CycleDataLockedReader<CycleDataType>::
get_current_thread() const {
return Thread::get_current_thread();
}
#endif // DO_PIPELINING

View File

@ -0,0 +1,19 @@
// Filename: cycleDataLockedReader.cxx
// Created by: drose (30Apr06)
//
////////////////////////////////////////////////////////////////////
//
// 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 "cycleDataLockedReader.h"

View File

@ -0,0 +1,81 @@
// Filename: cycleDataLockedReader.h
// Created by: drose (30Apr06)
//
////////////////////////////////////////////////////////////////////
//
// 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 CYCLEDATALOCKEDREADER_H
#define CYCLEDATALOCKEDREADER_H
#include "pandabase.h"
#include "cycleData.h"
#include "pipelineCycler.h"
#include "thread.h"
////////////////////////////////////////////////////////////////////
// Class : CycleDataLockedReader
// Description : This template class calls PipelineCycler::read() in
// the constructor and PipelineCycler::release_read() in
// the destructor. In the interim, it provides a
// transparent read-only access to the CycleData.
//
// Since a lock is held on the data while the instance
// of this class exists, no other thread may modify any
// stage of the pipeline during that time. Thus, this
// class is appropriate to use for cases in which you
// might want to read and then modify the data. It is
// possible to pass an instance of CycleDataLockedReader
// to the CycleDataWriter constructor, which
// automatically elevates the read lock into a write
// lock.
//
// It exists as a syntactic convenience to access the
// data in the CycleData. It also allows the whole
// system to compile down to nothing if
// SUPPORT_PIPELINING is not defined.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
class CycleDataLockedReader {
public:
INLINE CycleDataLockedReader(const PipelineCycler<CycleDataType> &cycler,
Thread *current_thread = Thread::get_current_thread());
INLINE CycleDataLockedReader(const CycleDataLockedReader<CycleDataType> &copy);
INLINE void operator = (const CycleDataLockedReader<CycleDataType> &copy);
INLINE ~CycleDataLockedReader();
INLINE const CycleDataType *operator -> () const;
INLINE operator const CycleDataType * () const;
INLINE const CycleDataType *take_pointer();
INLINE Thread *get_current_thread() const;
private:
#ifdef DO_PIPELINING
// This is the data stored for a real pipelining implementation.
const PipelineCycler<CycleDataType> *_cycler;
Thread *_current_thread;
const CycleDataType *_pointer;
CycleDataType *_write_pointer;
#else // !DO_PIPELINING
// This is all we need for the trivial, do-nothing implementation.
const CycleDataType *_pointer;
#endif // DO_PIPELINING
};
#include "cycleDataLockedReader.I"
#endif

View File

@ -0,0 +1,247 @@
// Filename: cycleDataLockedStageReader.I
// Created by: drose (30Apr06)
//
////////////////////////////////////////////////////////////////////
//
// 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 .
//
////////////////////////////////////////////////////////////////////
#ifdef DO_PIPELINING
// This is the implementation for full support of pipelining (as well
// as the sanity-check only implementation).
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedStageReader::Constructor (full)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataLockedStageReader<CycleDataType>::
CycleDataLockedStageReader(const PipelineCycler<CycleDataType> &cycler,
int stage, Thread *current_thread) :
_cycler(&cycler),
_current_thread(current_thread),
_stage(stage)
{
_pointer = _cycler->read_stage(_stage, _current_thread);
nassertv(_pointer != (const CycleDataType *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedStageReader::Copy Constructor (full)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataLockedStageReader<CycleDataType>::
CycleDataLockedStageReader(const CycleDataLockedStageReader<CycleDataType> &copy) :
_cycler(copy._cycler),
_current_thread(copy._current_thread),
_pointer(copy._pointer),
_stage(copy._stage)
{
nassertv(_pointer != (const CycleDataType *)NULL);
_cycler->increment_read(_pointer);
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedStageReader::Copy Assignment (full)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE void CycleDataLockedStageReader<CycleDataType>::
operator = (const CycleDataLockedStageReader<CycleDataType> &copy) {
nassertv(_pointer == (CycleDataType *)NULL);
nassertv(_current_thread == copy._current_thread);
_cycler = copy._cycler;
_pointer = copy._pointer;
_stage = copy._stage;
nassertv(_pointer != (const CycleDataType *)NULL);
_cycler->increment_read(_pointer);
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedStageReader::Destructor (full)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataLockedStageReader<CycleDataType>::
~CycleDataLockedStageReader() {
if (_pointer != NULL) {
_cycler->release_read_stage(_stage, _pointer);
}
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedStageReader::operator -> (full)
// Access: Public
// Description: This provides an indirect member access to the actual
// CycleData data.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE const CycleDataType *CycleDataLockedStageReader<CycleDataType>::
operator -> () const {
nassertr(_pointer != (const CycleDataType *)NULL, _cycler->cheat());
return _pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedStageReader::Typecast pointer (full)
// Access: Public
// Description: This allows the CycleDataLockedStageReader to be passed to any
// function that expects a const CycleDataType pointer.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataLockedStageReader<CycleDataType>::
operator const CycleDataType * () const {
nassertr(_pointer != (const CycleDataType *)NULL, _cycler->cheat());
return _pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedStageReader::take_pointer (full)
// Access: Public
// Description: This is intended to be called only from
// CycleDataStageWriter when it elevates the pointer from
// read to write status. This function returns the
// reader's pointer and relinquishes ownership of the
// pointer, rendering the reader invalid for future
// reads.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE const CycleDataType *CycleDataLockedStageReader<CycleDataType>::
take_pointer() {
const CycleDataType *pointer = _pointer;
_pointer = (CycleDataType *)NULL;
nassertr(pointer != (const CycleDataType *)NULL, _cycler->cheat());
return pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedStageReader::get_current_thread (full)
// Access: Public
// Description: Returns the Thread pointer of the currently-executing
// thread, as passed to the constructor of this object.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE Thread *CycleDataLockedStageReader<CycleDataType>::
get_current_thread() const {
return _current_thread;
}
#else // !DO_PIPELINING
// This is the trivial, do-nothing implementation.
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedStageReader::Constructor (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataLockedStageReader<CycleDataType>::
CycleDataLockedStageReader(const PipelineCycler<CycleDataType> &cycler, int,
Thread *) {
_pointer = cycler.cheat();
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedStageReader::Copy Constructor (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataLockedStageReader<CycleDataType>::
CycleDataLockedStageReader(const CycleDataLockedStageReader<CycleDataType> &copy) :
_pointer(copy._pointer)
{
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedStageReader::Copy Assignment (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE void CycleDataLockedStageReader<CycleDataType>::
operator = (const CycleDataLockedStageReader<CycleDataType> &copy) {
_pointer = copy._pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedStageReader::Destructor (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataLockedStageReader<CycleDataType>::
~CycleDataLockedStageReader() {
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedStageReader::operator -> (trivial)
// Access: Public
// Description: This provides an indirect member access to the actual
// CycleData data.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE const CycleDataType *CycleDataLockedStageReader<CycleDataType>::
operator -> () const {
return _pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedStageReader::Typecast pointer (trivial)
// Access: Public
// Description: This allows the CycleDataLockedStageReader to be passed to any
// function that expects a const CycleDataType pointer.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataLockedStageReader<CycleDataType>::
operator const CycleDataType * () const {
return _pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedStageReader::take_pointer (trivial)
// Access: Public
// Description: This is intended to be called only from
// CycleDataStageWriter when it elevates the pointer from
// read to write status. This function returns the
// reader's pointer and relinquishes ownership of the
// pointer, rendering the reader invalid for future
// reads.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE const CycleDataType *CycleDataLockedStageReader<CycleDataType>::
take_pointer() {
return _pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataLockedStageReader::get_current_thread (trivial)
// Access: Public
// Description: Returns the Thread pointer of the currently-executing
// thread, as passed to the constructor of this object.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE Thread *CycleDataLockedStageReader<CycleDataType>::
get_current_thread() const {
return Thread::get_current_thread();
}
#endif // DO_PIPELINING

View File

@ -0,0 +1,19 @@
// Filename: cycleDataLockedStageReader.cxx
// Created by: drose (30Apr06)
//
////////////////////////////////////////////////////////////////////
//
// 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 "cycleDataLockedStageReader.h"

View File

@ -0,0 +1,64 @@
// Filename: cycleDataLockedStageReader.h
// Created by: drose (30Apr06)
//
////////////////////////////////////////////////////////////////////
//
// 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 CYCLEDATALOCKEDSTAGEREADER_H
#define CYCLEDATALOCKEDSTAGEREADER_H
#include "pandabase.h"
#include "cycleData.h"
#include "pipelineCycler.h"
////////////////////////////////////////////////////////////////////
// Class : CycleDataLockedStageReader
// Description : This class is similar to CycleDataLockedReader,
// except it allows reading from a particular stage of
// the pipeline.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
class CycleDataLockedStageReader {
public:
INLINE CycleDataLockedStageReader(const PipelineCycler<CycleDataType> &cycler,
int stage, Thread *current_thread = Thread::get_current_thread());
INLINE CycleDataLockedStageReader(const CycleDataLockedStageReader<CycleDataType> &copy);
INLINE void operator = (const CycleDataLockedStageReader<CycleDataType> &copy);
INLINE ~CycleDataLockedStageReader();
INLINE const CycleDataType *operator -> () const;
INLINE operator const CycleDataType * () const;
INLINE const CycleDataType *take_pointer();
INLINE Thread *get_current_thread() const;
private:
#ifdef DO_PIPELINING
// This is the data stored for a real pipelining implementation.
const PipelineCycler<CycleDataType> *_cycler;
Thread *_current_thread;
const CycleDataType *_pointer;
int _stage;
#else // !DO_PIPELINING
// This is all we need for the trivial, do-nothing implementation.
const CycleDataType *_pointer;
#endif // DO_PIPELINING
};
#include "cycleDataLockedStageReader.I"
#endif

View File

@ -32,8 +32,7 @@ CycleDataReader(const PipelineCycler<CycleDataType> &cycler,
_cycler(&cycler),
_current_thread(current_thread)
{
_pointer = _cycler->read(_current_thread);
nassertv(_pointer != (const CycleDataType *)NULL);
_pointer = _cycler->read_unlocked(_current_thread);
}
////////////////////////////////////////////////////////////////////
@ -48,8 +47,6 @@ CycleDataReader(const CycleDataReader<CycleDataType> &copy) :
_current_thread(copy._current_thread),
_pointer(copy._pointer)
{
nassertv(_pointer != (const CycleDataType *)NULL);
_cycler->increment_read(_pointer);
}
////////////////////////////////////////////////////////////////////
@ -60,14 +57,10 @@ CycleDataReader(const CycleDataReader<CycleDataType> &copy) :
template<class CycleDataType>
INLINE void CycleDataReader<CycleDataType>::
operator = (const CycleDataReader<CycleDataType> &copy) {
nassertv(_pointer == (CycleDataType *)NULL);
nassertv(_current_thread == copy._current_thread);
_cycler = copy._cycler;
_pointer = copy._pointer;
nassertv(_pointer != (const CycleDataType *)NULL);
_cycler->increment_read(_pointer);
}
////////////////////////////////////////////////////////////////////
@ -78,9 +71,6 @@ operator = (const CycleDataReader<CycleDataType> &copy) {
template<class CycleDataType>
INLINE CycleDataReader<CycleDataType>::
~CycleDataReader() {
if (_pointer != NULL) {
_cycler->release_read(_pointer);
}
}
////////////////////////////////////////////////////////////////////
@ -92,7 +82,6 @@ INLINE CycleDataReader<CycleDataType>::
template<class CycleDataType>
INLINE const CycleDataType *CycleDataReader<CycleDataType>::
operator -> () const {
nassertr(_pointer != (const CycleDataType *)NULL, _cycler->cheat());
return _pointer;
}
@ -105,29 +94,9 @@ operator -> () const {
template<class CycleDataType>
INLINE CycleDataReader<CycleDataType>::
operator const CycleDataType * () const {
nassertr(_pointer != (const CycleDataType *)NULL, _cycler->cheat());
return _pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataReader::take_pointer (full)
// Access: Public
// Description: This is intended to be called only from
// CycleDataWriter when it elevates the pointer from
// read to write status. This function returns the
// reader's pointer and relinquishes ownership of the
// pointer, rendering the reader invalid for future
// reads.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE const CycleDataType *CycleDataReader<CycleDataType>::
take_pointer() {
const CycleDataType *pointer = _pointer;
_pointer = (CycleDataType *)NULL;
nassertr(pointer != (const CycleDataType *)NULL, _cycler->cheat());
return pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataReader::get_current_thread (full)
// Access: Public
@ -211,22 +180,6 @@ operator const CycleDataType * () const {
return _pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataReader::take_pointer (trivial)
// Access: Public
// Description: This is intended to be called only from
// CycleDataWriter when it elevates the pointer from
// read to write status. This function returns the
// reader's pointer and relinquishes ownership of the
// pointer, rendering the reader invalid for future
// reads.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE const CycleDataType *CycleDataReader<CycleDataType>::
take_pointer() {
return _pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataReader::get_current_thread (trivial)
// Access: Public

View File

@ -27,10 +27,14 @@
////////////////////////////////////////////////////////////////////
// Class : CycleDataReader
// Description : This template class calls PipelineCycler::read() in
// the constructor and PipelineCycler::release_read() in
// the destructor. In the interim, it provides a
// transparent read-only access to the CycleData.
// Description : This template class calls
// PipelineCycler::read_unlocked(), and then provides a
// transparent read-only access to the CycleData. It is
// used to access the data quickly, without holding a
// lock, for a thread that does not intend to modify the
// data and write it back out. For cases where the data
// might be subsequently modified, you should use
// CycleDataLockedReader.
//
// It exists as a syntactic convenience to access the
// data in the CycleData. It also allows the whole
@ -50,7 +54,6 @@ public:
INLINE const CycleDataType *operator -> () const;
INLINE operator const CycleDataType * () const;
INLINE const CycleDataType *take_pointer();
INLINE Thread *get_current_thread() const;
private:

View File

@ -34,8 +34,7 @@ CycleDataStageReader(const PipelineCycler<CycleDataType> &cycler,
_current_thread(current_thread),
_stage(stage)
{
_pointer = _cycler->read_stage(_stage, _current_thread);
nassertv(_pointer != (const CycleDataType *)NULL);
_pointer = _cycler->read_stage_unlocked(_stage);
}
////////////////////////////////////////////////////////////////////
@ -51,8 +50,6 @@ CycleDataStageReader(const CycleDataStageReader<CycleDataType> &copy) :
_pointer(copy._pointer),
_stage(copy._stage)
{
nassertv(_pointer != (const CycleDataType *)NULL);
_cycler->increment_read(_pointer);
}
////////////////////////////////////////////////////////////////////
@ -63,15 +60,11 @@ CycleDataStageReader(const CycleDataStageReader<CycleDataType> &copy) :
template<class CycleDataType>
INLINE void CycleDataStageReader<CycleDataType>::
operator = (const CycleDataStageReader<CycleDataType> &copy) {
nassertv(_pointer == (CycleDataType *)NULL);
nassertv(_current_thread == copy._current_thread);
_cycler = copy._cycler;
_pointer = copy._pointer;
_stage = copy._stage;
nassertv(_pointer != (const CycleDataType *)NULL);
_cycler->increment_read(_pointer);
}
////////////////////////////////////////////////////////////////////
@ -82,9 +75,6 @@ operator = (const CycleDataStageReader<CycleDataType> &copy) {
template<class CycleDataType>
INLINE CycleDataStageReader<CycleDataType>::
~CycleDataStageReader() {
if (_pointer != NULL) {
_cycler->release_read_stage(_stage, _pointer);
}
}
////////////////////////////////////////////////////////////////////
@ -96,7 +86,6 @@ INLINE CycleDataStageReader<CycleDataType>::
template<class CycleDataType>
INLINE const CycleDataType *CycleDataStageReader<CycleDataType>::
operator -> () const {
nassertr(_pointer != (const CycleDataType *)NULL, _cycler->cheat());
return _pointer;
}
@ -109,29 +98,9 @@ operator -> () const {
template<class CycleDataType>
INLINE CycleDataStageReader<CycleDataType>::
operator const CycleDataType * () const {
nassertr(_pointer != (const CycleDataType *)NULL, _cycler->cheat());
return _pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataStageReader::take_pointer (full)
// Access: Public
// Description: This is intended to be called only from
// CycleDataStageWriter when it elevates the pointer from
// read to write status. This function returns the
// reader's pointer and relinquishes ownership of the
// pointer, rendering the reader invalid for future
// reads.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE const CycleDataType *CycleDataStageReader<CycleDataType>::
take_pointer() {
const CycleDataType *pointer = _pointer;
_pointer = (CycleDataType *)NULL;
nassertr(pointer != (const CycleDataType *)NULL, _cycler->cheat());
return pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataStageReader::get_current_thread (full)
// Access: Public
@ -216,22 +185,6 @@ operator const CycleDataType * () const {
return _pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataStageReader::take_pointer (trivial)
// Access: Public
// Description: This is intended to be called only from
// CycleDataStageWriter when it elevates the pointer from
// read to write status. This function returns the
// reader's pointer and relinquishes ownership of the
// pointer, rendering the reader invalid for future
// reads.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE const CycleDataType *CycleDataStageReader<CycleDataType>::
take_pointer() {
return _pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataStageReader::get_current_thread (trivial)
// Access: Public

View File

@ -43,7 +43,6 @@ public:
INLINE const CycleDataType *operator -> () const;
INLINE operator const CycleDataType * () const;
INLINE const CycleDataType *take_pointer();
INLINE Thread *get_current_thread() const;
private:

View File

@ -94,13 +94,13 @@ operator = (const CycleDataStageWriter<CycleDataType> &copy) {
// Function: CycleDataStageWriter::Constructor (full)
// Access: Public
// Description: This flavor of the constructor elevates the pointer
// from the CycleDataStageReader from a read to a write
// from the CycleDataLockedStageReader from a read to a write
// pointer (and invalidates the reader).
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataStageWriter<CycleDataType>::
CycleDataStageWriter(PipelineCycler<CycleDataType> &cycler, int stage,
CycleDataStageReader<CycleDataType> &take_from) :
CycleDataLockedStageReader<CycleDataType> &take_from) :
_cycler(&cycler),
_current_thread(take_from.get_current_thread()),
_stage(stage)
@ -113,13 +113,13 @@ CycleDataStageWriter(PipelineCycler<CycleDataType> &cycler, int stage,
// Function: CycleDataStageWriter::Constructor (full)
// Access: Public
// Description: This flavor of the constructor elevates the pointer
// from the CycleDataStageReader from a read to a write
// from the CycleDataLockedStageReader from a read to a write
// pointer (and invalidates the reader).
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataStageWriter<CycleDataType>::
CycleDataStageWriter(PipelineCycler<CycleDataType> &cycler, int stage,
CycleDataStageReader<CycleDataType> &take_from,
CycleDataLockedStageReader<CycleDataType> &take_from,
bool force_to_0) :
_cycler(&cycler),
_current_thread(take_from.get_current_thread()),
@ -245,13 +245,13 @@ operator = (const CycleDataStageWriter<CycleDataType> &copy) {
// Function: CycleDataStageWriter::Constructor (trivial)
// Access: Public
// Description: This flavor of the constructor elevates the pointer
// from the CycleDataStageReader from a read to a write
// from the CycleDataLockedStageReader from a read to a write
// pointer (and invalidates the reader).
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataStageWriter<CycleDataType>::
CycleDataStageWriter(PipelineCycler<CycleDataType> &, int,
CycleDataStageReader<CycleDataType> &take_from) :
CycleDataLockedStageReader<CycleDataType> &take_from) :
_pointer((CycleDataType *)take_from.take_pointer())
{
}
@ -260,13 +260,13 @@ CycleDataStageWriter(PipelineCycler<CycleDataType> &, int,
// Function: CycleDataStageWriter::Constructor (trivial)
// Access: Public
// Description: This flavor of the constructor elevates the pointer
// from the CycleDataStageReader from a read to a write
// from the CycleDataLockedStageReader from a read to a write
// pointer (and invalidates the reader).
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataStageWriter<CycleDataType>::
CycleDataStageWriter(PipelineCycler<CycleDataType> &, int,
CycleDataStageReader<CycleDataType> &take_from,
CycleDataLockedStageReader<CycleDataType> &take_from,
bool) :
_pointer((CycleDataType *)take_from.take_pointer())
{

View File

@ -23,7 +23,7 @@
#include "cycleData.h"
#include "pipelineCycler.h"
#include "cycleDataStageReader.h"
#include "cycleDataLockedStageReader.h"
////////////////////////////////////////////////////////////////////
// Class : CycleDataStageWriter
@ -46,9 +46,9 @@ public:
INLINE void operator = (const CycleDataStageWriter<CycleDataType> &copy);
INLINE CycleDataStageWriter(PipelineCycler<CycleDataType> &cycler, int stage,
CycleDataStageReader<CycleDataType> &take_from);
CycleDataLockedStageReader<CycleDataType> &take_from);
INLINE CycleDataStageWriter(PipelineCycler<CycleDataType> &cycler, int stage,
CycleDataStageReader<CycleDataType> &take_from,
CycleDataLockedStageReader<CycleDataType> &take_from,
bool force_to_0);
INLINE ~CycleDataStageWriter();

View File

@ -95,13 +95,13 @@ operator = (const CycleDataWriter<CycleDataType> &copy) {
// Function: CycleDataWriter::Constructor (full)
// Access: Public
// Description: This flavor of the constructor elevates the pointer
// from the CycleDataReader from a read to a write
// from the CycleDataLockedReader from a read to a write
// pointer (and invalidates the reader).
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataWriter<CycleDataType>::
CycleDataWriter(PipelineCycler<CycleDataType> &cycler,
CycleDataReader<CycleDataType> &take_from) :
CycleDataLockedReader<CycleDataType> &take_from) :
_cycler(&cycler),
_current_thread(take_from.get_current_thread())
{
@ -112,7 +112,7 @@ CycleDataWriter(PipelineCycler<CycleDataType> &cycler,
// Function: CycleDataWriter::Constructor (full)
// Access: Public
// Description: This flavor of the constructor elevates the pointer
// from the CycleDataReader from a read to a write
// from the CycleDataLockedReader from a read to a write
// pointer (and invalidates the reader). It also
// propagates the pointer back upstream; see
// PipelineCycler::write_upstream().
@ -120,7 +120,7 @@ CycleDataWriter(PipelineCycler<CycleDataType> &cycler,
template<class CycleDataType>
INLINE CycleDataWriter<CycleDataType>::
CycleDataWriter(PipelineCycler<CycleDataType> &cycler,
CycleDataReader<CycleDataType> &take_from,
CycleDataLockedReader<CycleDataType> &take_from,
bool force_to_0) :
_cycler(&cycler),
_current_thread(take_from.get_current_thread())
@ -245,13 +245,13 @@ operator = (const CycleDataWriter<CycleDataType> &copy) {
// Function: CycleDataWriter::Constructor (trivial)
// Access: Public
// Description: This flavor of the constructor elevates the pointer
// from the CycleDataReader from a read to a write
// from the CycleDataLockedReader from a read to a write
// pointer (and invalidates the reader).
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataWriter<CycleDataType>::
CycleDataWriter(PipelineCycler<CycleDataType> &,
CycleDataReader<CycleDataType> &take_from) :
CycleDataLockedReader<CycleDataType> &take_from) :
_pointer((CycleDataType *)take_from.take_pointer())
{
}
@ -260,7 +260,7 @@ CycleDataWriter(PipelineCycler<CycleDataType> &,
// Function: CycleDataWriter::Constructor (trivial)
// Access: Public
// Description: This flavor of the constructor elevates the pointer
// from the CycleDataReader from a read to a write
// from the CycleDataLockedReader from a read to a write
// pointer (and invalidates the reader). It also
// propagates the pointer back upstream; see
// PipelineCycler::write_upstream().
@ -268,7 +268,7 @@ CycleDataWriter(PipelineCycler<CycleDataType> &,
template<class CycleDataType>
INLINE CycleDataWriter<CycleDataType>::
CycleDataWriter(PipelineCycler<CycleDataType> &,
CycleDataReader<CycleDataType> &take_from,
CycleDataLockedReader<CycleDataType> &take_from,
bool force_to_0) :
_pointer((CycleDataType *)take_from.take_pointer())
{

View File

@ -23,7 +23,7 @@
#include "cycleData.h"
#include "pipelineCycler.h"
#include "cycleDataReader.h"
#include "cycleDataLockedReader.h"
#include "thread.h"
////////////////////////////////////////////////////////////////////
@ -48,8 +48,8 @@ public:
INLINE CycleDataWriter(const CycleDataWriter<CycleDataType> &copy);
INLINE void operator = (const CycleDataWriter<CycleDataType> &copy);
INLINE CycleDataWriter(PipelineCycler<CycleDataType> &cycler, CycleDataReader<CycleDataType> &take_from);
INLINE CycleDataWriter(PipelineCycler<CycleDataType> &cycler, CycleDataReader<CycleDataType> &take_from, bool force_to_0);
INLINE CycleDataWriter(PipelineCycler<CycleDataType> &cycler, CycleDataLockedReader<CycleDataType> &take_from);
INLINE CycleDataWriter(PipelineCycler<CycleDataType> &cycler, CycleDataLockedReader<CycleDataType> &take_from, bool force_to_0);
INLINE ~CycleDataWriter();

View File

@ -56,6 +56,17 @@ operator = (const PipelineCycler<CycleDataType> &copy) {
PipelineCyclerBase::operator = (copy);
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::read_unlocked (dummy or true)
// Access: Public
// Description: See PipelineCyclerBase::read_unlocked().
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE const CycleDataType *PipelineCycler<CycleDataType>::
read_unlocked(Thread *current_thread) const {
return (const CycleDataType *)PipelineCyclerBase::read_unlocked(current_thread);
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::read (dummy or true)
// Access: Public
@ -113,7 +124,18 @@ elevate_read_upstream(const CycleDataType *pointer, bool force_to_0,
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::read (dummy or true)
// Function: PipelineCycler::read_stage_unlocked (dummy or true)
// Access: Public
// Description: See PipelineCyclerBase::read_stage_unlocked().
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE const CycleDataType *PipelineCycler<CycleDataType>::
read_stage_unlocked(int pipeline_stage) const {
return (const CycleDataType *)PipelineCyclerBase::read_stage_unlocked(pipeline_stage);
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::read_stage (dummy or true)
// Access: Public
// Description: See PipelineCyclerBase::read_stage().
////////////////////////////////////////////////////////////////////
@ -227,6 +249,17 @@ operator = (const PipelineCycler<CycleDataType> &copy) {
_typed_data = copy._typed_data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::read_unlocked (trivial)
// Access: Public
// Description: See PipelineCyclerBase::read_unlocked().
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE const CycleDataType *PipelineCycler<CycleDataType>::
read_unlocked(Thread *) const {
return &_typed_data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::read (trivial)
// Access: Public
@ -282,6 +315,17 @@ elevate_read_upstream(const CycleDataType *, bool, Thread *) {
return &_typed_data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::read_stage_unlocked (trivial)
// Access: Public
// Description: See PipelineCyclerBase::read_stage_unlocked().
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE const CycleDataType *PipelineCycler<CycleDataType>::
read_stage_unlocked(int) const {
return &_typed_data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::read_stage (trivial)
// Access: Public

View File

@ -63,12 +63,14 @@ public:
INLINE PipelineCycler(const PipelineCycler<CycleDataType> &copy);
INLINE void operator = (const PipelineCycler<CycleDataType> &copy);
INLINE const CycleDataType *read_unlocked(Thread *current_thread) const;
INLINE const CycleDataType *read(Thread *current_thread) const;
INLINE CycleDataType *write(Thread *current_thread);
INLINE CycleDataType *write_upstream(bool force_to_0, Thread *current_thread);
INLINE CycleDataType *elevate_read(const CycleDataType *pointer, Thread *current_thread);
INLINE CycleDataType *elevate_read_upstream(const CycleDataType *pointer, bool force_to_0, Thread *current_thread);
INLINE const CycleDataType *read_stage_unlocked(int pipeline_stage) const;
INLINE const CycleDataType *read_stage(int pipeline_stage, Thread *current_thread) const;
INLINE CycleDataType *elevate_read_stage(int pipeline_stage, const CycleDataType *pointer, Thread *current_thread);
INLINE CycleDataType *elevate_read_stage_upstream(int pipeline_stage, const CycleDataType *pointer, bool force_to_0, Thread *current_thread);

View File

@ -99,6 +99,26 @@ release() {
_locked = false;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerDummyImpl::read_unlocked
// Access: Public
// Description: Returns a const CycleData pointer, filled with the
// data for the current stage of the pipeline as seen by
// this thread. No lock is made on the contents; there
// is no guarantee that some other thread won't modify
// this object's data while you are working on it.
// (However, the data within the returned CycleData
// object itself is safe from modification; if another
// thread modifies the data, it will perform a
// copy-on-write, and thereby change the pointer stored
// within the object.)
////////////////////////////////////////////////////////////////////
INLINE const CycleData *PipelineCyclerDummyImpl::
read_unlocked(Thread *current_thread) const {
TAU_PROFILE("const CycleData *PipelineCyclerDummyImpl::read_unlocked()", " ", TAU_USER);
return _data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerDummyImpl::read
// Access: Public
@ -294,6 +314,21 @@ get_num_stages() {
return 1;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerDummyImpl::read_stage_unlocked
// Access: Public
// Description: Returns a const CycleData pointer, filled with the
// data for the indicated stage of the pipeline. As in
// read_unlocked(), no lock is held on the returned
// pointer.
////////////////////////////////////////////////////////////////////
INLINE const CycleData *PipelineCyclerDummyImpl::
read_stage_unlocked(int pipeline_stage) const {
TAU_PROFILE("const CycleData *PipelineCyclerDummyImpl::read_stage_unlocked(int)", " ", TAU_USER);
nassertr(pipeline_stage == 0, NULL);
return _data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerDummyImpl::read_stage
// Access: Public
@ -307,7 +342,7 @@ get_num_stages() {
////////////////////////////////////////////////////////////////////
INLINE const CycleData *PipelineCyclerDummyImpl::
read_stage(int pipeline_stage, Thread *) const {
TAU_PROFILE("const CycleData *PipelineCyclerDummyImpl::read_stage(int)", " ", TAU_USER);
TAU_PROFILE("const CycleData *PipelineCyclerDummyImpl::read_stage(int, Thread *)", " ", TAU_USER);
// This function isn't truly const, but it doesn't change the data
// in any meaningful way, so we pretend it is.
nassertr(pipeline_stage == 0, NULL);

View File

@ -55,6 +55,7 @@ public:
INLINE void lock(Thread *current_thread = NULL);
INLINE void release();
INLINE const CycleData *read_unlocked(Thread *current_thread) const;
INLINE const CycleData *read(Thread *current_thread) const;
INLINE void increment_read(const CycleData *pointer) const;
INLINE void release_read(const CycleData *pointer) const;
@ -67,6 +68,7 @@ public:
INLINE void release_write(CycleData *pointer);
INLINE int get_num_stages();
INLINE const CycleData *read_stage_unlocked(int pipeline_stage) const;
INLINE const CycleData *read_stage(int pipeline_stage, Thread *current_thread) const;
INLINE void release_read_stage(int pipeline_stage, const CycleData *pointer) const;
INLINE CycleData *write_stage(int pipeline_stage, Thread *current_thread);

View File

@ -98,6 +98,29 @@ INLINE void PipelineCyclerTrivialImpl::
release() {
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrivialImpl::read_unlocked
// Access: Public
// Description: Returns a const CycleData pointer, filled with the
// data for the current stage of the pipeline as seen by
// this thread. No lock is made on the contents; there
// is no guarantee that some other thread won't modify
// this object's data while you are working on it.
// (However, the data within the returned CycleData
// object itself is safe from modification; if another
// thread modifies the data, it will perform a
// copy-on-write, and thereby change the pointer stored
// within the object.)
////////////////////////////////////////////////////////////////////
INLINE const CycleData *PipelineCyclerTrivialImpl::
read_unlocked(Thread *) const {
#ifdef SIMPLE_STRUCT_POINTERS
return (const CycleData *)this;
#else
return _data;
#endif // SIMPLE_STRUCT_POINTERS
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrivialImpl::read
// Access: Public
@ -265,6 +288,23 @@ get_num_stages() {
return 1;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrivialImpl::read_stage_unlocked
// Access: Public
// Description: Returns a const CycleData pointer, filled with the
// data for the indicated stage of the pipeline. As in
// read_unlocked(), no lock is held on the returned
// pointer.
////////////////////////////////////////////////////////////////////
INLINE const CycleData *PipelineCyclerTrivialImpl::
read_stage_unlocked(int) const {
#ifdef SIMPLE_STRUCT_POINTERS
return (const CycleData *)this;
#else
return _data;
#endif // SIMPLE_STRUCT_POINTERS
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrivialImpl::read_stage
// Access: Public

View File

@ -60,6 +60,7 @@ public:
INLINE void lock(Thread *current_thread = NULL);
INLINE void release();
INLINE const CycleData *read_unlocked(Thread *current_thread) const;
INLINE const CycleData *read(Thread *current_thread) const;
INLINE void increment_read(const CycleData *pointer) const;
INLINE void release_read(const CycleData *pointer) const;
@ -73,6 +74,7 @@ public:
INLINE void release_write(CycleData *pointer);
INLINE int get_num_stages();
INLINE const CycleData *read_stage_unlocked(int pipeline_stage) const;
INLINE const CycleData *read_stage(int pipeline_stage, Thread *current_thread) const;
INLINE void release_read_stage(int pipeline_stage, const CycleData *pointer) const;
INLINE CycleData *write_stage(int pipeline_stage, Thread *current_thread);

View File

@ -55,6 +55,30 @@ release() {
_lock.release();
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrueImpl::read_unlocked
// Access: Public
// Description: Returns a const CycleData pointer, filled with the
// data for the current stage of the pipeline as seen by
// this thread. No lock is made on the contents; there
// is no guarantee that some other thread won't modify
// this object's data while you are working on it.
// (However, the data within the returned CycleData
// object itself is safe from modification; if another
// thread modifies the data, it will perform a
// copy-on-write, and thereby change the pointer stored
// within the object.)
////////////////////////////////////////////////////////////////////
INLINE const CycleData *PipelineCyclerTrueImpl::
read_unlocked(Thread *current_thread) const {
TAU_PROFILE("const CycleData *PipelineCyclerTrueImpl::read_unlocked(Thread *)", " ", TAU_USER);
int pipeline_stage = current_thread->get_pipeline_stage();
#ifdef _DEBUG
nassertr(pipeline_stage >= 0 && pipeline_stage < _num_stages, NULL);
#endif
return _data[pipeline_stage];
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrueImpl::read
// Access: Public
@ -258,6 +282,23 @@ get_num_stages() {
return _num_stages;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrueImpl::read_stage_unlocked
// Access: Public
// Description: Returns a const CycleData pointer, filled with the
// data for the indicated stage of the pipeline. As in
// read_unlocked(), no lock is held on the returned
// pointer.
////////////////////////////////////////////////////////////////////
INLINE const CycleData *PipelineCyclerTrueImpl::
read_stage_unlocked(int pipeline_stage) const {
TAU_PROFILE("const CycleData *PipelineCyclerTrueImpl::read_stage_unlocked(int)", " ", TAU_USER);
#ifdef _DEBUG
nassertr(pipeline_stage >= 0 && pipeline_stage < _num_stages, NULL);
#endif
return _data[pipeline_stage];
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrueImpl::read_stage
// Access: Public
@ -271,7 +312,7 @@ get_num_stages() {
////////////////////////////////////////////////////////////////////
INLINE const CycleData *PipelineCyclerTrueImpl::
read_stage(int pipeline_stage, Thread *current_thread) const {
TAU_PROFILE("const CycleData *PipelineCyclerTrueImpl::read_stage(int)", " ", TAU_USER);
TAU_PROFILE("const CycleData *PipelineCyclerTrueImpl::read_stage(int, Thread *)", " ", TAU_USER);
#ifdef _DEBUG
nassertr(pipeline_stage >= 0 && pipeline_stage < _num_stages, NULL);
#endif
@ -421,7 +462,7 @@ get_write_count() const {
INLINE PT(CycleData) PipelineCyclerTrueImpl::
cycle_2() {
TAU_PROFILE("PT(CycleData) PipelineCyclerTrueImpl::cycle_2()", " ", TAU_USER);
PT(CycleData) last_val = _data[1];
PT(CycleData) last_val = _data[1].p();
nassertr(_lock.debug_is_locked(), last_val);
nassertr(_dirty, last_val);
nassertr(_num_stages == 2, last_val);
@ -445,7 +486,7 @@ cycle_2() {
INLINE PT(CycleData) PipelineCyclerTrueImpl::
cycle_3() {
TAU_PROFILE("PT(CycleData) PipelineCyclerTrueImpl::cycle_3()", " ", TAU_USER);
PT(CycleData) last_val = _data[2];
PT(CycleData) last_val = _data[2].p();
nassertr(_lock.debug_is_locked(), last_val);
nassertr(_dirty, last_val);
nassertr(_num_stages == 3, last_val);

View File

@ -39,7 +39,7 @@ PipelineCyclerTrueImpl(CycleData *initial_data, Pipeline *pipeline) :
}
_num_stages = _pipeline->get_num_stages();
_data = new PT(CycleData)[_num_stages];
_data = new NPT(CycleData)[_num_stages];
for (int i = 0; i < _num_stages; ++i) {
_data[i] = initial_data;
}
@ -63,7 +63,7 @@ PipelineCyclerTrueImpl(const PipelineCyclerTrueImpl &copy) :
_num_stages = _pipeline->get_num_stages();
nassertv(_num_stages == copy._num_stages);
_data = new PT(CycleData)[_num_stages];
_data = new NPT(CycleData)[_num_stages];
// It's no longer critically important that we preserve pointerwise
// equivalence between different stages in the copy, but it doesn't
@ -77,7 +77,7 @@ PipelineCyclerTrueImpl(const PipelineCyclerTrueImpl &copy) :
if (new_pt == NULL) {
new_pt = copy._data[i]->make_copy();
}
_data[i] = new_pt;
_data[i] = new_pt.p();
}
_pipeline->add_cycler(this);
@ -105,7 +105,7 @@ operator = (const PipelineCyclerTrueImpl &copy) {
if (new_pt == NULL) {
new_pt = copy._data[i]->make_copy();
}
_data[i] = new_pt;
_data[i] = new_pt.p();
}
if (copy._dirty && !_dirty) {
@ -152,7 +152,11 @@ write_stage(int pipeline_stage, Thread *current_thread) {
CycleData *old_data = _data[pipeline_stage];
if (old_data->get_ref_count() != 1) {
// Only the node reference count is considered an important count
// for copy-on-write purposes. A standard reference of other than 1
// just means that some code (other that the PipelineCycler) has a
// pointer, which is safe to modify.
if (old_data->get_node_ref_count() != 1) {
// Copy-on-write.
_data[pipeline_stage] = old_data->make_copy();
@ -203,7 +207,7 @@ write_stage_upstream(int pipeline_stage, bool force_to_0, Thread *current_thread
k = pipeline_stage - 1;
while (k >= 0 && (_data[k] == old_data || force_to_0)) {
_data[k] = new_data;
_data[k] = new_data.p();
--k;
}
@ -251,7 +255,7 @@ write_stage_upstream(int pipeline_stage, bool force_to_0, Thread *current_thread
////////////////////////////////////////////////////////////////////
PT(CycleData) PipelineCyclerTrueImpl::
cycle() {
PT(CycleData) last_val = _data[_num_stages - 1];
PT(CycleData) last_val = _data[_num_stages - 1].p();
nassertr(_lock.debug_is_locked(), last_val);
nassertr(_dirty, last_val);
@ -294,7 +298,7 @@ set_num_stages(int num_stages) {
} else {
// To increase the array, we must reallocate it larger.
PT(CycleData) *new_data = new PT(CycleData)[num_stages];
NPT(CycleData) *new_data = new NPT(CycleData)[num_stages];
int i;
for (i = 0; i < _num_stages; ++i) {
new_data[i] = _data[i];

View File

@ -27,6 +27,7 @@
#include "pipelineCyclerLinks.h"
#include "cycleData.h"
#include "pointerTo.h"
#include "nodePointerTo.h"
#include "thread.h"
#include "reMutex.h"
#include "reMutexHolder.h"
@ -61,6 +62,8 @@ public:
INLINE void lock(Thread *current_thread);
INLINE void release();
INLINE const CycleData *read_unlocked(Thread *current_thread) const;
INLINE const CycleData *read(Thread *current_thread) const;
INLINE void increment_read(const CycleData *pointer) const;
INLINE void release_read(const CycleData *pointer) const;
@ -73,6 +76,7 @@ public:
INLINE void release_write(CycleData *pointer);
INLINE int get_num_stages();
INLINE const CycleData *read_stage_unlocked(int pipeline_stage) const;
INLINE const CycleData *read_stage(int pipeline_stage, Thread *current_thread) const;
INLINE void release_read_stage(int pipeline_stage, const CycleData *pointer) const;
CycleData *write_stage(int pipeline_stage, Thread *current_thread);
@ -113,8 +117,8 @@ private:
private:
Pipeline *_pipeline;
// An array of PT(CycleData) objects.
PT(CycleData) *_data;
// An array of NPT(CycleData) objects.
NPT(CycleData) *_data;
int _num_stages;
bool _dirty;

View File

@ -9,6 +9,8 @@
#include "conditionVarSpinlockImpl.cxx"
#include "config_pipeline.cxx"
#include "cycleData.cxx"
#include "cycleDataLockedReader.cxx"
#include "cycleDataLockedStageReader.cxx"
#include "cycleDataReader.cxx"
#include "cycleDataStageReader.cxx"
#include "cycleDataStageWriter.cxx"

View File

@ -46,8 +46,6 @@
modifierButtons.I modifierButtons.h mouseButton.h \
mouseData.I mouseData.h nameUniquifier.I nameUniquifier.h \
nodeCachedReferenceCount.h nodeCachedReferenceCount.I \
nodePointerToBase.h nodePointerToBase.I \
nodePointerTo.h nodePointerTo.I \
nonDeletor.h \
pta_double.h \
pta_float.h pta_int.h \
@ -86,8 +84,6 @@
modifierButtons.cxx mouseButton.cxx mouseData.cxx \
nameUniquifier.cxx \
nodeCachedReferenceCount.cxx \
nodePointerToBase.cxx \
nodePointerTo.cxx \
nonDeletor.cxx \
pta_double.cxx pta_float.cxx \
pta_int.cxx pta_ushort.cxx \
@ -135,8 +131,6 @@
modifierButtons.h mouseButton.h mouseData.I mouseData.h \
nameUniquifier.I nameUniquifier.h \
nodeCachedReferenceCount.h nodeCachedReferenceCount.I \
nodePointerToBase.h nodePointerToBase.I \
nodePointerTo.h nodePointerTo.I \
nonDeletor.h \
pta_double.h \
pta_float.h pta_int.h pta_ushort.h \

View File

@ -242,30 +242,3 @@ get_referenced_bits() const {
return result;
}
////////////////////////////////////////////////////////////////////
// Function: node_unref_delete
// Description: This global helper function will unref the given
// ReferenceCount object, and if the reference count
// reaches zero, automatically delete it. It can't be a
// member function because it's usually a bad idea to
// delete an object from within its own member function.
// It's a template function so the destructor doesn't
// have to be virtual.
////////////////////////////////////////////////////////////////////
template<class RefCountType>
INLINE void
node_unref_delete(RefCountType *ptr) {
ptr->node_unref();
if (ptr->get_ref_count() == 0) {
ObjectDeletor *deletor = ObjectDeletor::get_global_ptr();
if (deletor != (ObjectDeletor *)NULL) {
ptr->ref();
deletor->delete_object(RefCountDeleteWrapper<RefCountType>::do_delete, (void *)ptr);
return;
}
delete ptr;
}
}

View File

@ -22,6 +22,7 @@
#include "pandabase.h"
#include "cachedTypedWritableReferenceCount.h"
#include "nodeReferenceCount.h" // for node_unref_delete()
#include "objectDeletor.h"
////////////////////////////////////////////////////////////////////
@ -32,6 +33,19 @@
// number of times the object is referenced by a "node",
// presumably a PandaNode.
//
// This essentially combines the functionality of
// NodeReferenceCount and
// CachedTypedWritableReferenceCount, so that a
// derivative of this object actually has three
// counters: the standard reference count, the "cache"
// reference count, and the "node" reference count.
// Rather than multiply inheriting from the two
// reference count classes, we inherit only from
// CachedTypedWritableReferenceCount and simply
// duplicate the functionality of NodeReferenceCount, to
// avoid all of the problems associated with multiple
// inheritance.
//
// The intended design is to use this as a base class
// for RenderState and TransformState, both of which are
// held by PandaNodes, and also have caches which are
@ -90,9 +104,6 @@ private:
static TypeHandle _type_handle;
};
template<class RefCountType>
INLINE void node_unref_delete(RefCountType *ptr);
#include "nodeCachedReferenceCount.I"
#endif

View File

@ -3,8 +3,6 @@
#include "mouseData.cxx"
#include "nameUniquifier.cxx"
#include "nodeCachedReferenceCount.cxx"
#include "nodePointerToBase.cxx"
#include "nodePointerTo.cxx"
#include "nonDeletor.cxx"
#include "pta_double.cxx"
#include "pta_float.cxx"