From b407c2929b36dbeb7eedba2490f93038619e82d0 Mon Sep 17 00:00:00 2001 From: David Rose Date: Sun, 30 Apr 2006 14:42:54 +0000 Subject: [PATCH] better thread safety --- panda/src/express/Sources.pp | 6 + panda/src/express/express_composite1.cxx | 1 + panda/src/express/express_composite2.cxx | 3 +- panda/src/express/threadSafePointerTo.I | 259 ++++++++++++++++++ panda/src/express/threadSafePointerTo.cxx | 19 ++ panda/src/express/threadSafePointerTo.h | 113 ++++++++ panda/src/express/threadSafePointerToBase.I | 157 +++++++++++ panda/src/express/threadSafePointerToBase.cxx | 19 ++ panda/src/express/threadSafePointerToBase.h | 71 +++++ panda/src/gobj/geom.cxx | 4 + panda/src/gobj/geom.h | 2 + panda/src/gobj/geomMunger.cxx | 38 ++- panda/src/gobj/geomVertexData.cxx | 24 +- panda/src/gobj/geomVertexData.h | 1 + panda/src/pipeline/pipelineCyclerTrueImpl.I | 6 +- 15 files changed, 704 insertions(+), 19 deletions(-) create mode 100644 panda/src/express/threadSafePointerTo.I create mode 100644 panda/src/express/threadSafePointerTo.cxx create mode 100644 panda/src/express/threadSafePointerTo.h create mode 100644 panda/src/express/threadSafePointerToBase.I create mode 100644 panda/src/express/threadSafePointerToBase.cxx create mode 100644 panda/src/express/threadSafePointerToBase.h diff --git a/panda/src/express/Sources.pp b/panda/src/express/Sources.pp index dc49b1ddf5..e6028b8642 100644 --- a/panda/src/express/Sources.pp +++ b/panda/src/express/Sources.pp @@ -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 \ diff --git a/panda/src/express/express_composite1.cxx b/panda/src/express/express_composite1.cxx index 72f7181cde..2813e50d29 100644 --- a/panda/src/express/express_composite1.cxx +++ b/panda/src/express/express_composite1.cxx @@ -27,3 +27,4 @@ #include "pointerToBase.cxx" #include "pointerToVoid.cxx" #include "profileTimer.cxx" +#include "pta_uchar.cxx" diff --git a/panda/src/express/express_composite2.cxx b/panda/src/express/express_composite2.cxx index 09a4105f31..3ab809ac13 100644 --- a/panda/src/express/express_composite2.cxx +++ b/panda/src/express/express_composite2.cxx @@ -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" diff --git a/panda/src/express/threadSafePointerTo.I b/panda/src/express/threadSafePointerTo.I new file mode 100644 index 0000000000..3b012483d0 --- /dev/null +++ b/panda/src/express/threadSafePointerTo.I @@ -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 +INLINE ThreadSafePointerTo:: +ThreadSafePointerTo(To *ptr) : ThreadSafePointerToBase(ptr) { +} + +//////////////////////////////////////////////////////////////////// +// Function: ThreadSafePointerTo::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE ThreadSafePointerTo:: +ThreadSafePointerTo(const ThreadSafePointerTo ©) : + ThreadSafePointerToBase((const ThreadSafePointerToBase &)copy) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: ThreadSafePointerTo::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE ThreadSafePointerTo:: +~ThreadSafePointerTo() { +} + +//////////////////////////////////////////////////////////////////// +// Function: ThreadSafePointerTo::Dereference operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE TYPENAME ThreadSafePointerTo::To &ThreadSafePointerTo:: +operator *() const { + return *((To *)AtomicAdjust::get_ptr(this->_void_ptr)); +} + +//////////////////////////////////////////////////////////////////// +// Function: ThreadSafePointerTo::Member access operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE TYPENAME ThreadSafePointerTo::To *ThreadSafePointerTo:: +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 +INLINE ThreadSafePointerTo:: +operator TYPENAME ThreadSafePointerToBase::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 +INLINE TYPENAME ThreadSafePointerTo::To *ThreadSafePointerTo:: +p() const { + return (To *)AtomicAdjust::get_ptr(this->_void_ptr); +} + +//////////////////////////////////////////////////////////////////// +// Function: ThreadSafePointerTo::Assignment operator +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE ThreadSafePointerTo &ThreadSafePointerTo:: +operator = (To *ptr) { + reassign(ptr); + return *this; +} + +//////////////////////////////////////////////////////////////////// +// Function: ThreadSafePointerTo::Assignment operator +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE ThreadSafePointerTo &ThreadSafePointerTo:: +operator = (const ThreadSafePointerTo ©) { + reassign((const ThreadSafePointerToBase &)copy); + return *this; +} + +//////////////////////////////////////////////////////////////////// +// Function: ThreadSafeConstPointerTo::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE ThreadSafeConstPointerTo:: +ThreadSafeConstPointerTo(const TYPENAME ThreadSafeConstPointerTo::To *ptr) : + ThreadSafePointerToBase((TYPENAME ThreadSafeConstPointerTo::To *)ptr) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: ThreadSafeConstPointerTo::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE ThreadSafeConstPointerTo:: +ThreadSafeConstPointerTo(const ThreadSafePointerTo ©) : + ThreadSafePointerToBase((const ThreadSafePointerToBase &)copy) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: ThreadSafeConstPointerTo::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE ThreadSafeConstPointerTo:: +~ThreadSafeConstPointerTo() { +} + +//////////////////////////////////////////////////////////////////// +// Function: ThreadSafeConstPointerTo::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE ThreadSafeConstPointerTo:: +ThreadSafeConstPointerTo(const ThreadSafeConstPointerTo ©) : + ThreadSafePointerToBase((const ThreadSafePointerToBase &)copy) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: ThreadSafeConstPointerTo::Dereference operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE const TYPENAME ThreadSafeConstPointerTo::To &ThreadSafeConstPointerTo:: +operator *() const { + return *((To *)AtomicAdjust::get_ptr(this->_void_ptr)); +} + +//////////////////////////////////////////////////////////////////// +// Function: ThreadSafeConstPointerTo::Member access operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE const TYPENAME ThreadSafeConstPointerTo::To *ThreadSafeConstPointerTo:: +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 +INLINE ThreadSafeConstPointerTo:: +operator const TYPENAME ThreadSafePointerToBase::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 +INLINE const TYPENAME ThreadSafeConstPointerTo::To *ThreadSafeConstPointerTo:: +p() const { + return (To *)AtomicAdjust::get_ptr(this->_void_ptr); +} + +//////////////////////////////////////////////////////////////////// +// Function: ThreadSafeConstPointerTo::Assignment operator +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE ThreadSafeConstPointerTo &ThreadSafeConstPointerTo:: +operator = (const To *ptr) { + reassign((To *)ptr); + return *this; +} + +//////////////////////////////////////////////////////////////////// +// Function: ThreadSafeConstPointerTo::Assignment operator +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE ThreadSafeConstPointerTo &ThreadSafeConstPointerTo:: +operator = (const ThreadSafePointerTo ©) { + reassign((const ThreadSafePointerToBase &)copy); + return *this; +} + +//////////////////////////////////////////////////////////////////// +// Function: ThreadSafeConstPointerTo::Assignment operator +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE ThreadSafeConstPointerTo &ThreadSafeConstPointerTo:: +operator = (const ThreadSafeConstPointerTo ©) { + reassign((const ThreadSafePointerToBase &)copy); + return *this; +} diff --git a/panda/src/express/threadSafePointerTo.cxx b/panda/src/express/threadSafePointerTo.cxx new file mode 100644 index 0000000000..945101aa81 --- /dev/null +++ b/panda/src/express/threadSafePointerTo.cxx @@ -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" diff --git a/panda/src/express/threadSafePointerTo.h b/panda/src/express/threadSafePointerTo.h new file mode 100644 index 0000000000..806707c655 --- /dev/null +++ b/panda/src/express/threadSafePointerTo.h @@ -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 ThreadSafePointerTo : public ThreadSafePointerToBase { +public: + typedef TYPENAME ThreadSafePointerToBase::To To; +PUBLISHED: + INLINE ThreadSafePointerTo(To *ptr = (To *)NULL); + INLINE ThreadSafePointerTo(const ThreadSafePointerTo ©); + INLINE ~ThreadSafePointerTo(); + +public: + INLINE To &operator *() const; + INLINE To *operator -> () const; + INLINE operator TYPENAME ThreadSafePointerToBase::To *() const; + +PUBLISHED: + // When downcasting to a derived class from a ThreadSafePointerTo, + // 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 &operator = (To *ptr); + INLINE ThreadSafePointerTo &operator = (const ThreadSafePointerTo ©); + + // 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::is_null(); } + INLINE void clear() { ThreadSafePointerToBase::clear(); } +}; + + +//////////////////////////////////////////////////////////////////// +// Class : ThreadSafeConstPointerTo +// Description : +//////////////////////////////////////////////////////////////////// +template +class ThreadSafeConstPointerTo : public ThreadSafePointerToBase { +public: + typedef TYPENAME ThreadSafePointerToBase::To To; +PUBLISHED: + INLINE ThreadSafeConstPointerTo(const To *ptr = (const To *)NULL); + INLINE ThreadSafeConstPointerTo(const ThreadSafePointerTo ©); + INLINE ThreadSafeConstPointerTo(const ThreadSafeConstPointerTo ©); + INLINE ~ThreadSafeConstPointerTo(); + +public: + INLINE const To &operator *() const; + INLINE const To *operator -> () const; + INLINE operator const TYPENAME ThreadSafePointerToBase::To *() const; + +PUBLISHED: + INLINE const To *p() const; + + INLINE ThreadSafeConstPointerTo &operator = (const To *ptr); + INLINE ThreadSafeConstPointerTo &operator = (const ThreadSafePointerTo ©); + INLINE ThreadSafeConstPointerTo &operator = (const ThreadSafeConstPointerTo ©); + + // 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::clear(); } +}; + +#define TSPT(type) ThreadSafePointerTo< type > +#define TSCPT(type) ThreadSafeConstPointerTo< type > + +#include "threadSafePointerTo.I" + +#endif diff --git a/panda/src/express/threadSafePointerToBase.I b/panda/src/express/threadSafePointerToBase.I new file mode 100644 index 0000000000..08120e534a --- /dev/null +++ b/panda/src/express/threadSafePointerToBase.I @@ -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 +INLINE ThreadSafePointerToBase:: +ThreadSafePointerToBase(To *ptr) { + reassign(ptr); +} + +//////////////////////////////////////////////////////////////////// +// Function: ThreadSafePointerToBase::Copy Constructor +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE ThreadSafePointerToBase:: +ThreadSafePointerToBase(const ThreadSafePointerToBase ©) { + reassign(copy); +} + +//////////////////////////////////////////////////////////////////// +// Function: ThreadSafePointerToBase::Destructor +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE ThreadSafePointerToBase:: +~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 +INLINE void ThreadSafePointerToBase:: +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 +INLINE void ThreadSafePointerToBase:: +reassign(const ThreadSafePointerToBase ©) { + 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 +void ThreadSafePointerToBase:: +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 +INLINE void ThreadSafePointerToBase:: +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 +INLINE void ThreadSafePointerToBase:: +output(ostream &out) const { + out << _void_ptr; + if (_void_ptr != (void *)NULL) { + out << ":" << ((To *)_void_ptr)->get_ref_count(); + } +} diff --git a/panda/src/express/threadSafePointerToBase.cxx b/panda/src/express/threadSafePointerToBase.cxx new file mode 100644 index 0000000000..45ec186589 --- /dev/null +++ b/panda/src/express/threadSafePointerToBase.cxx @@ -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" diff --git a/panda/src/express/threadSafePointerToBase.h b/panda/src/express/threadSafePointerToBase.h new file mode 100644 index 0000000000..b9baf80459 --- /dev/null +++ b/panda/src/express/threadSafePointerToBase.h @@ -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 ThreadSafePointerToBase : public PointerToVoid { +public: + typedef T To; + +protected: + INLINE ThreadSafePointerToBase(To *ptr); + INLINE ThreadSafePointerToBase(const ThreadSafePointerToBase ©); + INLINE ~ThreadSafePointerToBase(); + + INLINE void reassign(To *ptr); + INLINE void reassign(const ThreadSafePointerToBase ©); + +#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 +INLINE ostream &operator <<(ostream &out, const ThreadSafePointerToBase &pointer) { + pointer.output(out); + return out; +} + +#include "threadSafePointerToBase.I" + +#endif diff --git a/panda/src/gobj/geom.cxx b/panda/src/gobj/geom.cxx index 510b1a2fd4..3220a72d33 100644 --- a/panda/src/gobj/geom.cxx +++ b/panda/src/gobj/geom.cxx @@ -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); diff --git a/panda/src/gobj/geom.h b/panda/src/gobj/geom.h index 154476524b..38293ea23f 100644 --- a/panda/src/gobj/geom.h +++ b/panda/src/gobj/geom.h @@ -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 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. diff --git a/panda/src/gobj/geomMunger.cxx b/panda/src/gobj/geomMunger.cxx index 41fb1b4109..1f76189e95 100644 --- a/panda/src/gobj/geomMunger.cxx +++ b/panda/src/gobj/geomMunger.cxx @@ -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 diff --git a/panda/src/gobj/geomVertexData.cxx b/panda/src/gobj/geomVertexData.cxx index c7af299c0e..aa6fb1e968 100644 --- a/panda/src/gobj/geomVertexData.cxx +++ b/panda/src/gobj/geomVertexData.cxx @@ -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); diff --git a/panda/src/gobj/geomVertexData.h b/panda/src/gobj/geomVertexData.h index f817a5dfea..1e5f6c6071 100644 --- a/panda/src/gobj/geomVertexData.h +++ b/panda/src/gobj/geomVertexData.h @@ -252,6 +252,7 @@ private: typedef CycleDataStageWriter CDStageWriter; Cache _cache; + Mutex _cache_lock; private: void update_animated_vertices(CData *cdata, Thread *current_thread); diff --git a/panda/src/pipeline/pipelineCyclerTrueImpl.I b/panda/src/pipeline/pipelineCyclerTrueImpl.I index d62a06c568..4f34082ec6 100644 --- a/panda/src/pipeline/pipelineCyclerTrueImpl.I +++ b/panda/src/pipeline/pipelineCyclerTrueImpl.I @@ -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]; }