better thread safety

This commit is contained in:
David Rose 2006-04-30 14:42:54 +00:00
parent 31d121e43b
commit b407c2929b
15 changed files with 704 additions and 19 deletions

View File

@ -47,6 +47,8 @@
stringDecoder.h stringDecoder.I \
subStream.I subStream.h subStreamBuf.h \
textEncoder.h textEncoder.I \
threadSafePointerTo.I threadSafePointerTo.h \
threadSafePointerToBase.I threadSafePointerToBase.h \
tokenBoard.I \
tokenBoard.h trueClock.I trueClock.h \
typedReferenceCount.I typedReferenceCount.h typedef.h \
@ -95,6 +97,8 @@
stringDecoder.cxx \
subStream.cxx subStreamBuf.cxx \
textEncoder.cxx \
threadSafePointerTo.cxx \
threadSafePointerToBase.cxx \
trueClock.cxx \
typedReferenceCount.cxx \
unicodeLatinMap.cxx \
@ -149,6 +153,8 @@
stringDecoder.h stringDecoder.I \
subStream.I subStream.h subStreamBuf.h \
textEncoder.h textEncoder.I \
threadSafePointerTo.I threadSafePointerTo.h \
threadSafePointerToBase.I threadSafePointerToBase.h \
tokenBoard.I \
tokenBoard.h trueClock.I trueClock.h \
typedReferenceCount.I typedReferenceCount.h typedef.h \

View File

@ -27,3 +27,4 @@
#include "pointerToBase.cxx"
#include "pointerToVoid.cxx"
#include "profileTimer.cxx"
#include "pta_uchar.cxx"

View File

@ -1,4 +1,3 @@
#include "pta_uchar.cxx"
#include "ramfile.cxx"
#include "referenceCount.cxx"
#include "reversedNumericData.cxx"
@ -8,6 +7,8 @@
#include "subStream.cxx"
#include "subStreamBuf.cxx"
#include "textEncoder.cxx"
#include "threadSafePointerTo.cxx"
#include "threadSafePointerToBase.cxx"
#include "trueClock.cxx"
#include "typedReferenceCount.cxx"
#include "unicodeLatinMap.cxx"

View File

@ -0,0 +1,259 @@
// Filename: threadSafePointerTo.I
// Created by: drose (28Apr06)
//
////////////////////////////////////////////////////////////////////
//
// 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: ThreadSafePointerTo::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE ThreadSafePointerTo<T>::
ThreadSafePointerTo(To *ptr) : ThreadSafePointerToBase<T>(ptr) {
}
////////////////////////////////////////////////////////////////////
// Function: ThreadSafePointerTo::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE ThreadSafePointerTo<T>::
ThreadSafePointerTo(const ThreadSafePointerTo<T> &copy) :
ThreadSafePointerToBase<T>((const ThreadSafePointerToBase<T> &)copy)
{
}
////////////////////////////////////////////////////////////////////
// Function: ThreadSafePointerTo::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE ThreadSafePointerTo<T>::
~ThreadSafePointerTo() {
}
////////////////////////////////////////////////////////////////////
// Function: ThreadSafePointerTo::Dereference operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE TYPENAME ThreadSafePointerTo<T>::To &ThreadSafePointerTo<T>::
operator *() const {
return *((To *)AtomicAdjust::get_ptr(this->_void_ptr));
}
////////////////////////////////////////////////////////////////////
// Function: ThreadSafePointerTo::Member access operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE TYPENAME ThreadSafePointerTo<T>::To *ThreadSafePointerTo<T>::
operator -> () const {
return (To *)AtomicAdjust::get_ptr(this->_void_ptr);
}
////////////////////////////////////////////////////////////////////
// Function: ThreadSafePointerTo::Typecast operator
// Access: Public
// Description: We also have the typecast operator to automatically
// convert ThreadSafePointerTo'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 ThreadSafePointerTo<T>::
operator TYPENAME ThreadSafePointerToBase<T>::To *() const {
return (To *)AtomicAdjust::get_ptr(this->_void_ptr);
}
////////////////////////////////////////////////////////////////////
// Function: ThreadSafePointerTo::p
// Access: Published
// Description: Returns an ordinary pointer instead of a ThreadSafePointerTo.
// Useful to work around compiler problems, particularly
// for implicit upcasts.
////////////////////////////////////////////////////////////////////
template<class T>
INLINE TYPENAME ThreadSafePointerTo<T>::To *ThreadSafePointerTo<T>::
p() const {
return (To *)AtomicAdjust::get_ptr(this->_void_ptr);
}
////////////////////////////////////////////////////////////////////
// Function: ThreadSafePointerTo::Assignment operator
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE ThreadSafePointerTo<T> &ThreadSafePointerTo<T>::
operator = (To *ptr) {
reassign(ptr);
return *this;
}
////////////////////////////////////////////////////////////////////
// Function: ThreadSafePointerTo::Assignment operator
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE ThreadSafePointerTo<T> &ThreadSafePointerTo<T>::
operator = (const ThreadSafePointerTo<T> &copy) {
reassign((const ThreadSafePointerToBase<T> &)copy);
return *this;
}
////////////////////////////////////////////////////////////////////
// Function: ThreadSafeConstPointerTo::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE ThreadSafeConstPointerTo<T>::
ThreadSafeConstPointerTo(const TYPENAME ThreadSafeConstPointerTo<T>::To *ptr) :
ThreadSafePointerToBase<T>((TYPENAME ThreadSafeConstPointerTo<T>::To *)ptr)
{
}
////////////////////////////////////////////////////////////////////
// Function: ThreadSafeConstPointerTo::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE ThreadSafeConstPointerTo<T>::
ThreadSafeConstPointerTo(const ThreadSafePointerTo<T> &copy) :
ThreadSafePointerToBase<T>((const ThreadSafePointerToBase<T> &)copy)
{
}
////////////////////////////////////////////////////////////////////
// Function: ThreadSafeConstPointerTo::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE ThreadSafeConstPointerTo<T>::
~ThreadSafeConstPointerTo() {
}
////////////////////////////////////////////////////////////////////
// Function: ThreadSafeConstPointerTo::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE ThreadSafeConstPointerTo<T>::
ThreadSafeConstPointerTo(const ThreadSafeConstPointerTo<T> &copy) :
ThreadSafePointerToBase<T>((const ThreadSafePointerToBase<T> &)copy)
{
}
////////////////////////////////////////////////////////////////////
// Function: ThreadSafeConstPointerTo::Dereference operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE const TYPENAME ThreadSafeConstPointerTo<T>::To &ThreadSafeConstPointerTo<T>::
operator *() const {
return *((To *)AtomicAdjust::get_ptr(this->_void_ptr));
}
////////////////////////////////////////////////////////////////////
// Function: ThreadSafeConstPointerTo::Member access operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE const TYPENAME ThreadSafeConstPointerTo<T>::To *ThreadSafeConstPointerTo<T>::
operator -> () const {
return (To *)AtomicAdjust::get_ptr(this->_void_ptr);
}
////////////////////////////////////////////////////////////////////
// Function: ThreadSafeConstPointerTo::Typecast operator
// Access: Public
// Description: We also have the typecast operator to automatically
// convert ThreadSafeConstPointerTo'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 ThreadSafeConstPointerTo<T>::
operator const TYPENAME ThreadSafePointerToBase<T>::To *() const {
return (To *)AtomicAdjust::get_ptr(this->_void_ptr);
}
////////////////////////////////////////////////////////////////////
// Function: ThreadSafeConstPointerTo::p
// Access: Published
// Description: Returns an ordinary pointer instead of a ThreadSafeConstPointerTo.
// Useful to work around compiler problems, particularly
// for implicit upcasts.
////////////////////////////////////////////////////////////////////
template<class T>
INLINE const TYPENAME ThreadSafeConstPointerTo<T>::To *ThreadSafeConstPointerTo<T>::
p() const {
return (To *)AtomicAdjust::get_ptr(this->_void_ptr);
}
////////////////////////////////////////////////////////////////////
// Function: ThreadSafeConstPointerTo::Assignment operator
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE ThreadSafeConstPointerTo<T> &ThreadSafeConstPointerTo<T>::
operator = (const To *ptr) {
reassign((To *)ptr);
return *this;
}
////////////////////////////////////////////////////////////////////
// Function: ThreadSafeConstPointerTo::Assignment operator
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE ThreadSafeConstPointerTo<T> &ThreadSafeConstPointerTo<T>::
operator = (const ThreadSafePointerTo<T> &copy) {
reassign((const ThreadSafePointerToBase<T> &)copy);
return *this;
}
////////////////////////////////////////////////////////////////////
// Function: ThreadSafeConstPointerTo::Assignment operator
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE ThreadSafeConstPointerTo<T> &ThreadSafeConstPointerTo<T>::
operator = (const ThreadSafeConstPointerTo<T> &copy) {
reassign((const ThreadSafePointerToBase<T> &)copy);
return *this;
}

View File

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

View File

@ -0,0 +1,113 @@
// Filename: threadSafePointerTo.h
// Created by: drose (28Apr06)
//
////////////////////////////////////////////////////////////////////
//
// 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 THREADSAFEPOINTERTO_H
#define THREADSAFEPOINTERTO_H
#include "pandabase.h"
#include "threadSafePointerToBase.h"
////////////////////////////////////////////////////////////////////
// Class : ThreadSafePointerTo
// Description : This works exactly like PointerTo, except that the
// object is designed to be thread-safe: it is generally
// safe to make unprotected assignments to this pointer,
// in the sense that the last assignment will win and
// the reference counts will be properly maintained.
////////////////////////////////////////////////////////////////////
template <class T>
class ThreadSafePointerTo : public ThreadSafePointerToBase<T> {
public:
typedef TYPENAME ThreadSafePointerToBase<T>::To To;
PUBLISHED:
INLINE ThreadSafePointerTo(To *ptr = (To *)NULL);
INLINE ThreadSafePointerTo(const ThreadSafePointerTo<T> &copy);
INLINE ~ThreadSafePointerTo();
public:
INLINE To &operator *() const;
INLINE To *operator -> () const;
INLINE operator TYPENAME ThreadSafePointerToBase<T>::To *() const;
PUBLISHED:
// When downcasting to a derived class from a ThreadSafePointerTo<BaseClass>,
// C++ would normally require you to cast twice: once to an actual
// BaseClass pointer, and then again to your desired pointer. You
// can use the handy function p() to avoid this first cast and make
// your code look a bit cleaner.
// e.g. instead of (MyType *)(BaseClass *)ptr, use (MyType *)ptr.p()
// If your base class is a derivative of TypedObject, you might want
// to use the DCAST macro defined in typedObject.h instead,
// e.g. DCAST(MyType, ptr). This provides a clean downcast that
// doesn't require .p() or any double-casting, and it can be
// run-time checked for correctness.
INLINE To *p() const;
INLINE ThreadSafePointerTo<T> &operator = (To *ptr);
INLINE ThreadSafePointerTo<T> &operator = (const ThreadSafePointerTo<T> &copy);
// These functions normally wouldn't need to be redefined here, but
// we do so anyway just to help out interrogate (which doesn't seem
// to want to automatically export the ThreadSafePointerToBase class). When
// this works again in interrogate, we can remove these.
INLINE bool is_null() const { return ThreadSafePointerToBase<T>::is_null(); }
INLINE void clear() { ThreadSafePointerToBase<T>::clear(); }
};
////////////////////////////////////////////////////////////////////
// Class : ThreadSafeConstPointerTo
// Description :
////////////////////////////////////////////////////////////////////
template <class T>
class ThreadSafeConstPointerTo : public ThreadSafePointerToBase<T> {
public:
typedef TYPENAME ThreadSafePointerToBase<T>::To To;
PUBLISHED:
INLINE ThreadSafeConstPointerTo(const To *ptr = (const To *)NULL);
INLINE ThreadSafeConstPointerTo(const ThreadSafePointerTo<T> &copy);
INLINE ThreadSafeConstPointerTo(const ThreadSafeConstPointerTo<T> &copy);
INLINE ~ThreadSafeConstPointerTo();
public:
INLINE const To &operator *() const;
INLINE const To *operator -> () const;
INLINE operator const TYPENAME ThreadSafePointerToBase<T>::To *() const;
PUBLISHED:
INLINE const To *p() const;
INLINE ThreadSafeConstPointerTo<T> &operator = (const To *ptr);
INLINE ThreadSafeConstPointerTo<T> &operator = (const ThreadSafePointerTo<T> &copy);
INLINE ThreadSafeConstPointerTo<T> &operator = (const ThreadSafeConstPointerTo<T> &copy);
// This functions normally wouldn't need to be redefined here, but
// we do so anyway just to help out interrogate (which doesn't seem
// to want to automatically export the ThreadSafePointerToBase class). When
// this works again in interrogate, we can remove this.
INLINE void clear() { ThreadSafePointerToBase<T>::clear(); }
};
#define TSPT(type) ThreadSafePointerTo< type >
#define TSCPT(type) ThreadSafeConstPointerTo< type >
#include "threadSafePointerTo.I"
#endif

View File

@ -0,0 +1,157 @@
// Filename: threadSafePointerToBase.I
// Created by: drose (28Apr06)
//
////////////////////////////////////////////////////////////////////
//
// 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: ThreadSafePointerToBase::Constructor
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE ThreadSafePointerToBase<T>::
ThreadSafePointerToBase(To *ptr) {
reassign(ptr);
}
////////////////////////////////////////////////////////////////////
// Function: ThreadSafePointerToBase::Copy Constructor
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE ThreadSafePointerToBase<T>::
ThreadSafePointerToBase(const ThreadSafePointerToBase<T> &copy) {
reassign(copy);
}
////////////////////////////////////////////////////////////////////
// Function: ThreadSafePointerToBase::Destructor
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE ThreadSafePointerToBase<T>::
~ThreadSafePointerToBase() {
reassign((To *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: ThreadSafePointerToBase::reassign
// Access: Protected
// Description: This is the main work of the ThreadSafePointerTo family. When
// the pointer is reassigned, decrement the old
// reference count and increment the new one.
////////////////////////////////////////////////////////////////////
template<class T>
INLINE void ThreadSafePointerToBase<T>::
reassign(To *ptr) {
To *old_ptr = (To *)AtomicAdjust::get_ptr(_void_ptr);
if (ptr == old_ptr) {
return;
}
#ifdef HAVE_THREADS
void *orig_ptr = AtomicAdjust::compare_and_exchange_ptr(_void_ptr, old_ptr, ptr);
while (orig_ptr != old_ptr) {
// Some other thread assigned it first. Try again.
old_ptr = (To *)AtomicAdjust::get_ptr(_void_ptr);
if (ptr == old_ptr) {
return;
}
orig_ptr = AtomicAdjust::compare_and_exchange_ptr(_void_ptr, old_ptr, ptr);
}
#else // HAVE_THREADS
_void_ptr = ptr;
#endif // HAVE_THREADS
if (ptr != (To *)NULL) {
ptr->ref();
#ifdef DO_MEMORY_USAGE
if (MemoryUsage::get_track_memory_usage()) {
update_type(ptr);
}
#endif
}
// Now delete the old pointer.
if (old_ptr != (To *)NULL) {
unref_delete(old_ptr);
}
}
////////////////////////////////////////////////////////////////////
// Function: ThreadSafePointerToBase::reassign
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
template<class T>
INLINE void ThreadSafePointerToBase<T>::
reassign(const ThreadSafePointerToBase<To> &copy) {
reassign((To *)copy._void_ptr);
}
#ifdef DO_MEMORY_USAGE
////////////////////////////////////////////////////////////////////
// Function: ThreadSafePointerToBase::update_type
// Access: Protected
// Description: Ensures that the MemoryUsage record for the pointer
// has the right type of object, if we know the type
// ourselves.
////////////////////////////////////////////////////////////////////
template<class T>
void ThreadSafePointerToBase<T>::
update_type(To *ptr) {
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 // DO_MEMORY_USAGE
////////////////////////////////////////////////////////////////////
// Function: ThreadSafePointerToBase::clear
// Access: Published
// Description: A convenient way to set the ThreadSafePointerTo object to NULL.
// (Assignment to a NULL pointer also works, of course.)
////////////////////////////////////////////////////////////////////
template<class T>
INLINE void ThreadSafePointerToBase<T>::
clear() {
reassign((To *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: ThreadSafePointerToBase::output
// Access: Published
// Description: A handy function to output ThreadSafePointerTo's as a hex
// pointer followed by a reference count.
////////////////////////////////////////////////////////////////////
template<class T>
INLINE void ThreadSafePointerToBase<T>::
output(ostream &out) const {
out << _void_ptr;
if (_void_ptr != (void *)NULL) {
out << ":" << ((To *)_void_ptr)->get_ref_count();
}
}

View File

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

View File

@ -0,0 +1,71 @@
// Filename: threadSafePointerToBase.h
// Created by: drose (28Apr06)
//
////////////////////////////////////////////////////////////////////
//
// 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 THREADSAFEPOINTERTOBASE_H
#define THREADSAFEPOINTERTOBASE_H
#include "pandabase.h"
#include "pointerToVoid.h"
#include "referenceCount.h"
#include "typedef.h"
#include "memoryUsage.h"
#include "config_express.h"
#include "atomicAdjust.h"
////////////////////////////////////////////////////////////////////
// Class : ThreadSafePointerToBase
// Description : This is the base class for ThreadSafePointerTo and
// ThreadSafeConstPointerTo. Don't try to use it
// directly; use either derived class instead.
////////////////////////////////////////////////////////////////////
template <class T>
class ThreadSafePointerToBase : public PointerToVoid {
public:
typedef T To;
protected:
INLINE ThreadSafePointerToBase(To *ptr);
INLINE ThreadSafePointerToBase(const ThreadSafePointerToBase<T> &copy);
INLINE ~ThreadSafePointerToBase();
INLINE void reassign(To *ptr);
INLINE void reassign(const ThreadSafePointerToBase<To> &copy);
#ifdef DO_MEMORY_USAGE
void update_type(To *ptr);
#endif // DO_MEMORY_USAGE
// No assignment or retrieval functions are declared in
// ThreadSafePointerToBase, 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 ThreadSafePointerToBase<T> &pointer) {
pointer.output(out);
return out;
}
#include "threadSafePointerToBase.I"
#endif

View File

@ -26,6 +26,7 @@
#include "bamReader.h"
#include "bamWriter.h"
#include "boundingSphere.h"
#include "mutexHolder.h"
UpdateSeq Geom::_next_modified;
PStatCollector Geom::_draw_primitive_setup_pcollector("Draw:Primitive:Setup");
@ -801,6 +802,7 @@ write(ostream &out, int indent_level) const {
////////////////////////////////////////////////////////////////////
void Geom::
clear_cache() {
MutexHolder holder(_cache_lock);
for (Cache::iterator ci = _cache.begin();
ci != _cache.end();
++ci) {
@ -823,6 +825,7 @@ clear_cache() {
////////////////////////////////////////////////////////////////////
void Geom::
clear_cache_stage(Thread *current_thread) {
MutexHolder holder(_cache_lock);
for (Cache::iterator ci = _cache.begin();
ci != _cache.end();
++ci) {
@ -1240,6 +1243,7 @@ make_copy() const {
////////////////////////////////////////////////////////////////////
void Geom::CacheEntry::
evict_callback() {
MutexHolder holder(_source->_cache_lock);
Cache::iterator ci = _source->_cache.find(this);
nassertv(ci != _source->_cache.end());
nassertv((*ci) == this);

View File

@ -40,6 +40,7 @@
#include "boundingVolume.h"
#include "pStatCollector.h"
#include "deletedChain.h"
#include "pmutex.h"
class GeomContext;
class PreparedGraphicsObjects;
@ -254,6 +255,7 @@ private:
typedef CycleDataStageWriter<CData> CDStageWriter;
Cache _cache;
Mutex _cache_lock;
// This works just like the Texture contexts: each Geom keeps a
// record of all the PGO objects that hold the Geom, and vice-versa.

View File

@ -117,22 +117,27 @@ munge_geom(CPT(Geom) &geom, CPT(GeomVertexData) &data,
Geom::CacheEntry temp_entry(source_data, this);
temp_entry.local_object();
Geom::Cache::const_iterator ci = geom->_cache.find(&temp_entry);
if (ci != geom->_cache.end()) {
entry = (*ci);
nassertv(entry->_source == geom);
geom->_cache_lock.lock();
Geom::Cache::const_iterator ci = geom->_cache.find(&temp_entry);
if (ci == geom->_cache.end()) {
geom->_cache_lock.release();
} else {
entry = (*ci);
geom->_cache_lock.release();
nassertv(entry->_source == geom);
// Here's an element in the cache for this computation. Record a
// cache hit, so this element will stay in the cache a while
// longer.
entry->refresh(current_thread);
// Now check that it's fresh.
Geom::CDCacheReader cdata(entry->_cycler, current_thread);
nassertv(cdata->_source == geom);
if (cdata->_geom_result != (Geom *)NULL &&
geom->get_modified(current_thread) <= cdata->_geom_result->get_modified(current_thread) &&
data->get_modified(current_thread) <= cdata->_data_result->get_modified(current_thread)) {
if (cdata->_source == geom &&
cdata->_geom_result != (Geom *)NULL &&
geom->get_modified(current_thread) <= cdata->_geom_result->get_modified(current_thread) &&
data->get_modified(current_thread) <= cdata->_data_result->get_modified(current_thread)) {
// The cache entry is still good; use it.
geom = cdata->_geom_result;
@ -149,16 +154,23 @@ munge_geom(CPT(Geom) &geom, CPT(GeomVertexData) &data,
// Ok, invoke the munger.
PStatTimer timer(_munge_pcollector, current_thread);
CPT(Geom) orig_geom = geom;
PT(Geom) orig_geom = (Geom *)geom.p();
data = munge_data(data);
munge_geom_impl(geom, data, current_thread);
// Record the new result in the cache.
if (entry == (Geom::CacheEntry *)NULL) {
// Create a new entry for the result.
entry = new Geom::CacheEntry((Geom *)orig_geom.p(), source_data, this);
bool inserted = ((Geom *)orig_geom.p())->_cache.insert(entry).second;
nassertv(inserted);
entry = new Geom::CacheEntry(orig_geom, source_data, this);
{
MutexHolder holder(orig_geom->_cache_lock);
bool inserted = orig_geom->_cache.insert(entry).second;
if (!inserted) {
// Some other thread must have beat us to the punch. Never
// mind.
return;
}
}
// And tell the cache manager about the new entry. (It might
// immediately request a delete from the cache of the thing we

View File

@ -677,9 +677,15 @@ convert_to(const GeomVertexFormat *new_format) const {
CacheEntry temp_entry(new_format);
temp_entry.local_object();
_cache_lock.lock();
Cache::const_iterator ci = _cache.find(&temp_entry);
if (ci != _cache.end()) {
if (ci == _cache.end()) {
_cache_lock.release();
} else {
entry = (*ci);
_cache_lock.release();
nassertr(entry->_source == this, NULL);
// Here's an element in the cache for this computation. Record a
@ -717,8 +723,15 @@ convert_to(const GeomVertexFormat *new_format) const {
if (entry == (CacheEntry *)NULL) {
// Create a new entry for the result.
entry = new CacheEntry((GeomVertexData *)this, new_format);
bool inserted = ((GeomVertexData *)this)->_cache.insert(entry).second;
nassertr(inserted, new_data);
{
MutexHolder holder(_cache_lock);
bool inserted = ((GeomVertexData *)this)->_cache.insert(entry).second;
if (!inserted) {
// Some other thread must have beat us to the punch. Never
// mind.
return new_data;
}
}
// And tell the cache manager about the new entry. (It might
// immediately request a delete from the cache of the thing we
@ -727,7 +740,7 @@ convert_to(const GeomVertexFormat *new_format) const {
}
// Finally, store the cached result on the entry.
CDCacheWriter cdata(entry->_cycler, true);
CDCacheWriter cdata(entry->_cycler, true, current_thread);
cdata->_result = new_data;
return new_data;
@ -1095,6 +1108,7 @@ write(ostream &out, int indent_level) const {
////////////////////////////////////////////////////////////////////
void GeomVertexData::
clear_cache() {
MutexHolder holder(_cache_lock);
for (Cache::iterator ci = _cache.begin();
ci != _cache.end();
++ci) {
@ -1117,6 +1131,7 @@ clear_cache() {
////////////////////////////////////////////////////////////////////
void GeomVertexData::
clear_cache_stage() {
MutexHolder holder(_cache_lock);
for (Cache::iterator ci = _cache.begin();
ci != _cache.end();
++ci) {
@ -1471,6 +1486,7 @@ make_copy() const {
////////////////////////////////////////////////////////////////////
void GeomVertexData::CacheEntry::
evict_callback() {
MutexHolder holder(_source->_cache_lock);
Cache::iterator ci = _source->_cache.find(this);
nassertv(ci != _source->_cache.end());
nassertv((*ci) == this);

View File

@ -252,6 +252,7 @@ private:
typedef CycleDataStageWriter<CData> CDStageWriter;
Cache _cache;
Mutex _cache_lock;
private:
void update_animated_vertices(CData *cdata, Thread *current_thread);

View File

@ -70,7 +70,9 @@ INLINE const CycleData *PipelineCyclerTrueImpl::
read(Thread *current_thread) const {
TAU_PROFILE("const CycleData *PipelineCyclerTrueImpl::read(Thread *)", " ", TAU_USER);
int pipeline_stage = current_thread->get_pipeline_stage();
#ifdef _DEBUG
nassertr(pipeline_stage >= 0 && pipeline_stage < _num_stages, NULL);
#endif
_lock.lock(current_thread);
return _data[pipeline_stage];
}
@ -238,7 +240,7 @@ increment_write(CycleData *pointer) const {
INLINE void PipelineCyclerTrueImpl::
release_write(CycleData *pointer) {
TAU_PROFILE("void PipelineCyclerTrueImpl::release_write(CycleData *)", " ", TAU_USER);
#ifdef NDEBUG
#ifdef _DEBUG
int pipeline_stage = Thread::get_current_pipeline_stage();
return release_write_stage(pipeline_stage, pointer);
#else
@ -270,7 +272,9 @@ 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);
#ifdef _DEBUG
nassertr(pipeline_stage >= 0 && pipeline_stage < _num_stages, NULL);
#endif
_lock.lock(current_thread);
return _data[pipeline_stage];
}