Browse Source

name mutexes for debugging; better UpdateSeq thread behavior

David Rose 19 years ago
parent
commit
889228f403

+ 3 - 2
panda/src/collide/collisionSolid.cxx

@@ -45,7 +45,7 @@ TypeHandle CollisionSolid::_type_handle;
 //  Description:
 ////////////////////////////////////////////////////////////////////
 CollisionSolid::
-CollisionSolid() {
+CollisionSolid() : _lock("CollisionSolid") {
   _flags = F_viz_geom_stale | F_tangible | F_internal_bounds_stale;
 }
 
@@ -58,7 +58,8 @@ CollisionSolid::
 CollisionSolid(const CollisionSolid &copy) :
   _effective_normal(copy._effective_normal),
   _internal_bounds(copy._internal_bounds),
-  _flags(copy._flags)
+  _flags(copy._flags),
+  _lock("CollisionSolid")
 {
   _flags |= F_viz_geom_stale;
 }

+ 16 - 1
panda/src/display/graphicsEngine.cxx

@@ -100,7 +100,9 @@ PStatCollector GraphicsEngine::_test_geom_pcollector("Collision Tests:CollisionG
 ////////////////////////////////////////////////////////////////////
 GraphicsEngine::
 GraphicsEngine(Pipeline *pipeline) :
-  _pipeline(pipeline)
+  _pipeline(pipeline),
+  _app("app"),
+  _lock("GraphicsEngine")
 {
   if (_pipeline == (Pipeline *)NULL) {
     _pipeline = Pipeline::get_render_pipeline();
@@ -1727,6 +1729,17 @@ get_window_renderer(const string &name, int pipeline_stage) {
   return thread.p();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsEngine::WindowRenderer::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+GraphicsEngine::WindowRenderer::
+WindowRenderer(const string &name) :
+  _wl_lock(string("GraphicsEngine::WindowRenderer ") + name)
+{
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsEngine::WindowRenderer::add_gsg
 //       Access: Public
@@ -2026,7 +2039,9 @@ do_callbacks(GraphicsEngine::CallbackTime callback_time) {
 GraphicsEngine::RenderThread::
 RenderThread(const string &name, GraphicsEngine *engine) : 
   Thread(name, "Main"),
+  WindowRenderer(name),
   _engine(engine),
+  _cv_mutex(string("GraphicsEngine::RenderThread ") + name),
   _cv_start(_cv_mutex),
   _cv_done(_cv_mutex)
 {

+ 2 - 0
panda/src/display/graphicsEngine.h

@@ -269,6 +269,8 @@ private:
 
   class WindowRenderer {
   public:
+    WindowRenderer(const string &name);
+
     void add_gsg(GraphicsStateGuardian *gsg);
     void add_window(Windows &wlist, GraphicsOutput *window);
     void remove_window(GraphicsOutput *window);

+ 3 - 1
panda/src/display/graphicsOutput.cxx

@@ -74,7 +74,9 @@ GraphicsOutput(GraphicsPipe *pipe,
                const FrameBufferProperties &properties,
                int x_size, int y_size, int flags,
                GraphicsStateGuardian *gsg,
-               GraphicsOutput *host) {
+               GraphicsOutput *host) :
+  _lock("GraphicsOutput")
+{
 #ifdef DO_MEMORY_USAGE
   MemoryUsage::update_type(this, this);
 #endif

+ 3 - 1
panda/src/display/graphicsPipe.cxx

@@ -66,7 +66,9 @@ const int GraphicsPipe::strip_properties[] = {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 GraphicsPipe::
-GraphicsPipe() {
+GraphicsPipe() :
+  _lock("GraphicsPipe")
+{
   // Initially, we assume the GraphicsPipe is valid.  A derived class
   // should set this to false if it determines otherwise.
   _is_valid = true;

+ 1 - 1
panda/src/display/graphicsPipeSelection.cxx

@@ -34,7 +34,7 @@ GraphicsPipeSelection *GraphicsPipeSelection::_global_ptr = NULL;
 //  Description:
 ////////////////////////////////////////////////////////////////////
 GraphicsPipeSelection::
-GraphicsPipeSelection() {
+GraphicsPipeSelection() : _lock("GraphicsPipeSelection") {
   // We declare these variables here instead of in config_display, in
   // case this constructor is running at static init time.
   ConfigVariableString load_display

+ 2 - 1
panda/src/display/graphicsWindow.cxx

@@ -42,7 +42,8 @@ GraphicsWindow(GraphicsPipe *pipe,
                int x_size, int y_size, int flags,
                GraphicsStateGuardian *gsg,
                GraphicsOutput *host) :
-  GraphicsOutput(pipe, name, properties, x_size, y_size, flags, gsg, host)
+  GraphicsOutput(pipe, name, properties, x_size, y_size, flags, gsg, host),
+  _input_lock("GraphicsWindow::_input_lock")
 {
 #ifdef DO_MEMORY_USAGE
   MemoryUsage::update_type(this, this);

+ 1 - 1
panda/src/display/lru.cxx

@@ -79,7 +79,7 @@ Lru::Lru (int maximum_memory, int maximum_pages, int maximum_page_types)
     }
 
 #if ENABLE_MUTEX
-    this -> _m.mutex = new Mutex ( );
+    this -> _m.mutex = new Mutex ("lru");
 #endif
 
   }

+ 1 - 1
panda/src/event/eventQueue.cxx

@@ -29,7 +29,7 @@ EventQueue *EventQueue::_global_event_queue = NULL;
 //  Description:
 ////////////////////////////////////////////////////////////////////
 EventQueue::
-EventQueue() {
+EventQueue() : _lock("EventQueue") {
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
panda/src/express/referenceCount.I

@@ -301,7 +301,7 @@ has_weak_list() const {
 INLINE WeakReferenceList *ReferenceCount::
 get_weak_list() const {
   if (_weak_list == (WeakReferenceList *)NULL) {
-    ((ReferenceCount *)this)->_weak_list = new WeakReferenceList;
+    ((ReferenceCount *)this)->create_weak_list();
   }
   return _weak_list;
 }

+ 29 - 1
panda/src/express/referenceCount.cxx

@@ -16,8 +16,9 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-
 #include "referenceCount.h"
+#include "atomicAdjust.h"
+#include "mutexImpl.h"
 
 TypeHandle ReferenceCount::_type_handle;
 
@@ -48,3 +49,30 @@ do_test_ref_count_integrity() const {
 
   return true;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: ReferenceCount::create_weak_list
+//       Access: Private
+//  Description: Allocates a new WeakReferenceList structure and
+//               stores it on the object.
+////////////////////////////////////////////////////////////////////
+void ReferenceCount::
+create_weak_list() {
+#ifdef HAVE_ATOMIC_COMPARE_AND_EXCHANGE_PTR
+  WeakReferenceList *weak_list = new WeakReferenceList;
+  void *orig = 
+    AtomicAdjust::compare_and_exchange_ptr((void *&)_weak_list, NULL, weak_list);
+  if (orig != (void *)NULL) {
+    // Someone else created it first.
+    delete weak_list;
+  }
+#else
+  static MutexImpl lock("ReferenceCount::create_weak_list");
+  lock.lock();
+  if (_weak_list != (WeakReferenceList *)NULL) {
+    _weak_list = new WeakReferenceList;
+  }
+  lock.release();
+#endif  // HAVE_ATOMIC_COMPARE_AND_EXCHANGE_PTR
+}
+

+ 3 - 0
panda/src/express/referenceCount.h

@@ -66,6 +66,9 @@ public:
 protected:
   bool do_test_ref_count_integrity() const;
 
+private:
+  void create_weak_list();
+
 private:
   enum { 
     // We use this value as a flag to indicate an object has been

+ 11 - 2
panda/src/express/weakReferenceList.cxx

@@ -37,10 +37,12 @@ WeakReferenceList() {
 ////////////////////////////////////////////////////////////////////
 WeakReferenceList::
 ~WeakReferenceList() {
+  _lock.lock();
   Pointers::iterator pi;
   for (pi = _pointers.begin(); pi != _pointers.end(); ++pi) {
     (*pi)->mark_deleted();
   }
+  _lock.release();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -58,7 +60,9 @@ WeakReferenceList::
 ////////////////////////////////////////////////////////////////////
 void WeakReferenceList::
 add_reference(WeakPointerToVoid *ptv) {
+  _lock.lock();
   bool inserted = _pointers.insert(ptv).second;
+  _lock.release();
   nassertv(inserted);
 }
 
@@ -73,7 +77,12 @@ add_reference(WeakPointerToVoid *ptv) {
 ////////////////////////////////////////////////////////////////////
 void WeakReferenceList::
 clear_reference(WeakPointerToVoid *ptv) {
+  _lock.lock();
   Pointers::iterator pi = _pointers.find(ptv);
-  nassertv_always(pi != _pointers.end());
-  _pointers.erase(pi);
+  bool valid = (pi != _pointers.end());
+  if (valid) {
+    _pointers.erase(pi);
+  }
+  _lock.release();
+  nassertv(valid);
 }

+ 2 - 0
panda/src/express/weakReferenceList.h

@@ -21,6 +21,7 @@
 
 #include "pandabase.h"
 #include "pset.h"
+#include "mutexImpl.h"
 
 class WeakPointerToVoid;
 
@@ -45,6 +46,7 @@ public:
 private:  
   typedef pset<WeakPointerToVoid *> Pointers;
   Pointers _pointers;
+  MutexImpl _lock;
 };
 
 #include "weakReferenceList.I"

+ 2 - 1
panda/src/gobj/geomCacheManager.cxx

@@ -35,7 +35,8 @@ PStatCollector GeomCacheManager::_geom_cache_evict_pcollector("Geom cache operat
 ////////////////////////////////////////////////////////////////////
 GeomCacheManager::
 GeomCacheManager() :
-  _total_size(0)
+  _total_size(0),
+  _lock("GeomCacheManager")
 {
   // We deliberately hang on to this pointer forever.
   _list = new GeomCacheEntry;

+ 1 - 1
panda/src/pgraph/nodePathComponent.cxx

@@ -22,7 +22,7 @@
 // We start the key counters off at 1, since 0 is reserved for an
 // empty NodePath (and also for an unassigned key).
 int NodePathComponent::_next_key = 1;
-Mutex NodePathComponent::_key_lock;
+Mutex NodePathComponent::_key_lock("NodePathComponent::_key_lock");
 TypeHandle NodePathComponent::_type_handle;
 
 

+ 4 - 2
panda/src/pgraph/pandaNode.cxx

@@ -67,7 +67,8 @@ TypeHandle PandaNode::_type_handle;
 ////////////////////////////////////////////////////////////////////
 PandaNode::
 PandaNode(const string &name) :
-  Namable(name)
+  Namable(name),
+  _paths_lock("PandaNode::_paths_lock")
 {
   if (pgraph_cat.is_debug()) {
     pgraph_cat.debug()
@@ -113,7 +114,8 @@ PandaNode::
 PandaNode(const PandaNode &copy) :
   ReferenceCount(copy),
   TypedWritable(copy),
-  Namable(copy)
+  Namable(copy),
+  _paths_lock("PandaNode::_paths_lock")
 {
   if (pgraph_cat.is_debug()) {
     pgraph_cat.debug()

+ 1 - 1
panda/src/pgraph/renderState.cxx

@@ -1696,7 +1696,7 @@ init_states() {
   // meantime, this is OK because we guarantee that this method is
   // called at static init time, presumably when there is still only
   // one thread in the world.
-  _states_lock = new ReMutex;
+  _states_lock = new ReMutex("RenderState");
   nassertv(Thread::get_current_thread() == Thread::get_main_thread());
 }
 

+ 1 - 1
panda/src/pgraph/transformState.cxx

@@ -1274,7 +1274,7 @@ init_states() {
   // meantime, this is OK because we guarantee that this method is
   // called at static init time, presumably when there is still only
   // one thread in the world.
-  _states_lock = new ReMutex;
+  _states_lock = new ReMutex("TransformState");
   nassertv(Thread::get_current_thread() == Thread::get_main_thread());
 }
   

+ 0 - 14
panda/src/pipeline/mutexDebug.I

@@ -17,20 +17,6 @@
 ////////////////////////////////////////////////////////////////////
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: MutexDebug::Constructor
-//       Access: Protected
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE MutexDebug::
-MutexDebug(bool allow_recursion) :
-  _allow_recursion(allow_recursion),
-  _locking_thread(NULL),
-  _lock_count(0),
-  _cvar(_global_mutex)
-{
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: MutexDebug::Copy Constructor
 //       Access: Private

+ 19 - 3
panda/src/pipeline/mutexDebug.cxx

@@ -27,6 +27,21 @@ MutexDebug::VoidFunc *MutexDebug::_pstats_wait_stop;
 
 MutexImpl MutexDebug::_global_mutex;
 
+////////////////////////////////////////////////////////////////////
+//     Function: MutexDebug::Constructor
+//       Access: Protected
+//  Description:
+////////////////////////////////////////////////////////////////////
+MutexDebug::
+MutexDebug(const string &name, bool allow_recursion) :
+  _name(name),
+  _allow_recursion(allow_recursion),
+  _locking_thread(NULL),
+  _lock_count(0),
+  _cvar(_global_mutex)
+{
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: MutexDebug::Destructor
 //       Access: Protected, Virtual
@@ -50,9 +65,9 @@ MutexDebug::
 void MutexDebug::
 output(ostream &out) const {
   if (_allow_recursion) {
-    out << "ReMutex " << (void *)this;
+    out << "ReMutex " << _name << " " << (void *)this;
   } else {
-    out << "Mutex " << (void *)this;
+    out << "Mutex " << _name << " " << (void *)this;
   }
 }
 
@@ -152,7 +167,8 @@ do_lock() {
 
     if (thread_cat.is_spam()) {
       thread_cat.spam()
-        << *this_thread << " blocking on " << *this << "\n";
+        << *this_thread << " blocking on " << *this << " (held by "
+        << *_locking_thread << ")\n";
     }
     while (_locking_thread != (Thread *)NULL) {
       _cvar.wait();

+ 2 - 1
panda/src/pipeline/mutexDebug.h

@@ -35,7 +35,7 @@ class Thread;
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA MutexDebug {
 protected:
-  INLINE MutexDebug(bool allow_recursion);
+  MutexDebug(const string &name, bool allow_recursion);
   virtual ~MutexDebug();
 private:
   INLINE MutexDebug(const MutexDebug &copy);
@@ -59,6 +59,7 @@ private:
   void report_deadlock(Thread *this_thread);
 
 private:
+  string _name;
   bool _allow_recursion;
   Thread *_locking_thread;
   int _lock_count;

+ 3 - 0
panda/src/pipeline/pipeline.cxx

@@ -32,6 +32,9 @@ Pipeline *Pipeline::_render_pipeline = (Pipeline *)NULL;
 Pipeline::
 Pipeline(const string &name, int num_stages) :
   Namable(name)
+#ifdef THREADED_PIPELINE
+  , _lock("Pipeline")
+#endif
 {
 #ifdef THREADED_PIPELINE
   // Set up the linked list of cyclers to be a circular list that

+ 30 - 2
panda/src/pipeline/pmutex.I

@@ -24,13 +24,41 @@
 ////////////////////////////////////////////////////////////////////
 INLINE Mutex::
 #ifdef DEBUG_THREADS
-Mutex() : MutexDebug(false)
+Mutex() : MutexDebug(string(), false)
 #else
 Mutex()
 #endif  // DEBUG_THREADS
 {
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Mutex::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE Mutex::
+#ifdef DEBUG_THREADS
+Mutex(const char *name) : MutexDebug(string(name), false)
+#else
+Mutex(const char *)
+#endif  // DEBUG_THREADS
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Mutex::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE Mutex::
+#ifdef DEBUG_THREADS
+Mutex(const string &name) : MutexDebug(name, false)
+#else
+Mutex(const string &)
+#endif  // DEBUG_THREADS
+{
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Mutex::Destructor
 //       Access: Public
@@ -47,7 +75,7 @@ INLINE Mutex::
 ////////////////////////////////////////////////////////////////////
 INLINE Mutex::
 #ifdef DEBUG_THREADS
-Mutex(const Mutex &copy) : MutexDebug(false)
+Mutex(const Mutex &copy) : MutexDebug(string(), false)
 #else
   Mutex(const Mutex &copy)
 #endif  // DEBUG_THREADS

+ 2 - 0
panda/src/pipeline/pmutex.h

@@ -50,6 +50,8 @@ class EXPCL_PANDA Mutex : public MutexDirect
 {
 public:
   INLINE Mutex();
+  INLINE Mutex(const char *name);
+  INLINE Mutex(const string &name);
   INLINE ~Mutex();
 private:
   INLINE Mutex(const Mutex &copy);

+ 22 - 9
panda/src/pipeline/reMutex.I

@@ -24,7 +24,7 @@
 ////////////////////////////////////////////////////////////////////
 INLINE ReMutex::
 #ifdef DEBUG_THREADS
-ReMutex() : MutexDebug(true)
+ReMutex() : MutexDebug(string(), true)
 #else
 ReMutex()
 #endif  // DEBUG_THREADS
@@ -32,27 +32,40 @@ ReMutex()
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: ReMutex::Destructor
+//     Function: ReMutex::Constructor
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE ReMutex::
-~ReMutex() {
+#ifdef DEBUG_THREADS
+ReMutex(const char *name) : MutexDebug(string(name), true)
+#else
+ReMutex(const char *)
+#endif  // DEBUG_THREADS
+{
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: ReMutex::Copy Constructor
-//       Access: Private
-//  Description: Do not attempt to copy mutexes.
+//     Function: ReMutex::Constructor
+//       Access: Public
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE ReMutex::
 #ifdef DEBUG_THREADS
-ReMutex(const ReMutex &copy) : MutexDebug(true)
+ReMutex(const string &name) : MutexDebug(name, true)
 #else
-  ReMutex(const ReMutex &copy)
+ReMutex(const string &)
 #endif  // DEBUG_THREADS
 {
-  nassertv(false);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ReMutex::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE ReMutex::
+~ReMutex() {
 }
 
 ////////////////////////////////////////////////////////////////////

+ 2 - 0
panda/src/pipeline/reMutex.h

@@ -42,6 +42,8 @@ class EXPCL_PANDA ReMutex : public ReMutexDirect
 {
 public:
   INLINE ReMutex();
+  INLINE ReMutex(const char *name);
+  INLINE ReMutex(const string &name);
   INLINE ~ReMutex();
 private:
   INLINE ReMutex(const ReMutex &copy);

+ 20 - 9
panda/src/pstatclient/pStatClient.cxx

@@ -58,7 +58,8 @@ PerThreadData() {
 ////////////////////////////////////////////////////////////////////
 PStatClient::
 PStatClient() :
-  _impl(NULL)
+  _impl(NULL),
+  _lock("PStatClient")
 {
   _collectors = NULL;
   _collectors_size = 0;
@@ -489,14 +490,7 @@ do_make_thread(Thread *thread) {
   _threads_by_name[thread->get_name()].push_back(new_index);
   _threads_by_sync_name[thread->get_sync_name()].push_back(new_index);
         
-  InternalThread *pthread = new InternalThread;
-  pthread->_thread = thread;
-  pthread->_name = thread->get_name();
-  pthread->_sync_name = thread->get_sync_name();
-  pthread->_is_active = false;
-  pthread->_next_packet = 0.0;
-  pthread->_frame_number = 0;
-
+  InternalThread *pthread = new InternalThread(thread);
   add_thread(pthread);
 
   // We need an additional PerThreadData for this thread in all of the
@@ -899,4 +893,21 @@ make_def(const PStatClient *client, int this_index) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PStatClient::Collector::make_def
+//       Access: Private
+//  Description: Creates the new PStatCollectorDef for this collector.
+////////////////////////////////////////////////////////////////////
+PStatClient::InternalThread::
+InternalThread(Thread *thread) :
+  _thread(thread),
+  _name(thread->get_name()),
+  _sync_name(thread->get_sync_name()),
+  _is_active(false),
+  _next_packet(0.0),
+  _frame_number(0),
+  _thread_lock(string("PStatClient::InternalThread ") + thread->get_name())
+{
+}
+
 #endif // DO_PSTATS

+ 2 - 0
panda/src/pstatclient/pStatClient.h

@@ -194,6 +194,8 @@ private:
   // maintained separately for each thread.
   class InternalThread {
   public:
+    InternalThread(Thread *thread);
+
     WPT(Thread) _thread;
     string _name;
     string _sync_name;

+ 47 - 48
panda/src/putil/updateSeq.I

@@ -23,7 +23,7 @@
 //  Description: Creates an UpdateSeq in the 'initial' state.
 ////////////////////////////////////////////////////////////////////
 INLINE UpdateSeq::
-UpdateSeq() {
+UpdateSeq() : _lock("UpdateSeq") {
   _seq = (unsigned int)SC_initial;
 }
 
@@ -67,9 +67,8 @@ fresh() {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE UpdateSeq::
-UpdateSeq(const UpdateSeq &copy) {
-  MutexHolder holder(_lock);
-  _seq = copy._seq;
+UpdateSeq(const UpdateSeq &copy) : _lock("UpdateSeq") {
+  _seq = AtomicAdjust::get(copy._seq);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -79,8 +78,7 @@ UpdateSeq(const UpdateSeq &copy) {
 ////////////////////////////////////////////////////////////////////
 INLINE UpdateSeq &UpdateSeq::
 operator = (const UpdateSeq &copy) {
-  MutexHolder holder(_lock);
-  _seq = copy._seq;
+  AtomicAdjust::set(_seq, AtomicAdjust::get(copy._seq));
   return *this;
 }
 
@@ -91,8 +89,7 @@ operator = (const UpdateSeq &copy) {
 ////////////////////////////////////////////////////////////////////
 INLINE void UpdateSeq::
 clear() {
-  MutexHolder holder(_lock);
-  _seq = (unsigned int)SC_initial;
+  AtomicAdjust::set(_seq, (PN_int32)SC_initial);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -103,8 +100,7 @@ clear() {
 ////////////////////////////////////////////////////////////////////
 INLINE bool UpdateSeq::
 is_initial() const {
-  MutexHolder holder(_lock);
-  return _seq == (unsigned int)SC_initial;
+  return AtomicAdjust::get(_seq) == (PN_int32)SC_initial;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -114,8 +110,7 @@ is_initial() const {
 ////////////////////////////////////////////////////////////////////
 INLINE bool UpdateSeq::
 is_old() const {
-  MutexHolder holder(_lock);
-  return _seq == (unsigned int)SC_old;
+  return AtomicAdjust::get(_seq) == (PN_int32)SC_old;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -126,8 +121,7 @@ is_old() const {
 ////////////////////////////////////////////////////////////////////
 INLINE bool UpdateSeq::
 is_fresh() const {
-  MutexHolder holder(_lock);
-  return _seq == (unsigned int)SC_fresh;
+  return AtomicAdjust::get(_seq) == (PN_int32)SC_fresh;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -138,8 +132,8 @@ is_fresh() const {
 ////////////////////////////////////////////////////////////////////
 INLINE bool UpdateSeq::
 is_special() const {
-  MutexHolder holder(_lock);
-  return priv_is_special();
+  // This relies on the assumption that (~0 + 1) == 0.
+  return ((AtomicAdjust::get(_seq) + 1) <= 2);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -149,8 +143,7 @@ is_special() const {
 ////////////////////////////////////////////////////////////////////
 INLINE bool UpdateSeq::
 operator == (const UpdateSeq &other) const {
-  MutexHolder holder(_lock);
-  return (_seq == other._seq);
+  return AtomicAdjust::get(_seq) == AtomicAdjust::get(other._seq);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -160,8 +153,7 @@ operator == (const UpdateSeq &other) const {
 ////////////////////////////////////////////////////////////////////
 INLINE bool UpdateSeq::
 operator != (const UpdateSeq &other) const {
-  MutexHolder holder(_lock);
-  return (_seq != other._seq);
+  return AtomicAdjust::get(_seq) != AtomicAdjust::get(other._seq);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -171,8 +163,7 @@ operator != (const UpdateSeq &other) const {
 ////////////////////////////////////////////////////////////////////
 INLINE bool UpdateSeq::
 operator < (const UpdateSeq &other) const {
-  MutexHolder holder(_lock);
-  return priv_lt(other);
+  return priv_lt(AtomicAdjust::get(_seq), AtomicAdjust::get(other._seq));
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -182,8 +173,7 @@ operator < (const UpdateSeq &other) const {
 ////////////////////////////////////////////////////////////////////
 INLINE bool UpdateSeq::
 operator <= (const UpdateSeq &other) const {
-  MutexHolder holder(_lock);
-  return _seq == other._seq || priv_lt(other);
+  return priv_le(AtomicAdjust::get(_seq), AtomicAdjust::get(other._seq));
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -215,11 +205,14 @@ INLINE UpdateSeq UpdateSeq::
 operator ++ () {
   {
     MutexHolder holder(_lock);
-    ++_seq;
-    if (priv_is_special()) {
+
+    PN_int32 new_seq = _seq + 1;
+    if (priv_is_special(new_seq)) {
       // Oops, wraparound.  We don't want to confuse the new value
       // with our special cases.
-      _seq = (unsigned int)SC_old + 1;
+      AtomicAdjust::set(_seq, (PN_int32)SC_old + 1);
+    } else {
+      AtomicAdjust::set(_seq, new_seq);
     }
   }
     
@@ -237,10 +230,12 @@ operator ++ (int) {
   {
     MutexHolder holder(_lock);
     temp._seq = _seq;
-    
-    ++_seq;
-    if (priv_is_special()) {
-      _seq = (unsigned int)SC_old + 1;
+
+    PN_int32 new_seq = _seq + 1;
+    if (priv_is_special(new_seq)) {
+      AtomicAdjust::set(_seq, (PN_int32)SC_old + 1);
+    } else {
+      AtomicAdjust::set(_seq, new_seq);
     }
   }
     
@@ -254,11 +249,7 @@ operator ++ (int) {
 ////////////////////////////////////////////////////////////////////
 INLINE void UpdateSeq::
 output(ostream &out) const {
-  unsigned int seq;
-  {
-    MutexHolder holder(_lock);
-    seq = _seq;
-  }
+  PN_int32 seq = AtomicAdjust::get(_seq);
   switch (seq) {
   case SC_initial:
     out << "initial";
@@ -273,38 +264,46 @@ output(ostream &out) const {
     break;
 
   default:
-    out << (long unsigned int)seq;
+    out << (unsigned int)seq;
   }
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: UpdateSeq::priv_is_special
-//       Access: Published
-//  Description: The private implementation of is_special().  Assumes
-//               the lock is already held.
+//       Access: Private, Static
+//  Description: The private implementation of is_special().
 ////////////////////////////////////////////////////////////////////
 INLINE bool UpdateSeq::
-priv_is_special() const {
+priv_is_special(PN_int32 seq) {
   // This relies on the assumption that (~0 + 1) == 0.
-  return ((_seq + 1) <= 2);
+  return (((unsigned int)seq + 1) <= 2);
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: UpdateSeq::priv_lt
-//       Access: Published
-//  Description: The private implementation of operator < ().  Assumes
-//               the lock is already held.
+//       Access: Private, Static
+//  Description: The private implementation of operator < ().
 ////////////////////////////////////////////////////////////////////
 INLINE bool UpdateSeq::
-priv_lt(const UpdateSeq &other) const {
+priv_lt(PN_int32 a, PN_int32 b) {
   // The special cases of SC_initial or SC_old are less than all other
   // non-special numbers, and SC_initial is less than SC_old.  The
   // special case of SC_fresh is greater than all other non-special
   // numbers.  For all other cases, we use a circular comparision such
   // that n < m iff (signed)(n - m) < 0.
   return
-    (priv_is_special() || other.priv_is_special()) ? (_seq < other._seq) :
-    ((signed int)(_seq - other._seq) < 0);
+    (priv_is_special(a) || priv_is_special(b)) ? ((unsigned int)a < (unsigned int)b) :
+    ((signed int)(a - b) < 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: UpdateSeq::priv_le
+//       Access: Private, Static
+//  Description: The private implementation of operator <= ().
+////////////////////////////////////////////////////////////////////
+INLINE bool UpdateSeq::
+priv_le(PN_int32 a, PN_int32 b) {
+  return (a == b) || priv_lt(a, b);
 }
 
 INLINE ostream &operator << (ostream &out, const UpdateSeq &value) {

+ 0 - 2
panda/src/putil/updateSeq.cxx

@@ -17,5 +17,3 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "updateSeq.h"
-
-Mutex UpdateSeq::_lock;

+ 7 - 6
panda/src/putil/updateSeq.h

@@ -22,6 +22,8 @@
 #include "pandabase.h"
 #include "pmutex.h"
 #include "mutexHolder.h"
+#include "atomicAdjust.h"
+#include "numeric_types.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : UpdateSeq
@@ -72,8 +74,9 @@ PUBLISHED:
   INLINE void output(ostream &out) const;
 
 private:
-  INLINE bool priv_is_special() const;
-  INLINE bool priv_lt(const UpdateSeq &other) const;
+  INLINE static bool priv_is_special(PN_int32 seq);
+  INLINE static bool priv_lt(PN_int32 a, PN_int32 b);
+  INLINE static bool priv_le(PN_int32 a, PN_int32 b);
 
 private:
   enum SpecialCases {
@@ -82,10 +85,8 @@ private:
     SC_fresh = ~(unsigned int)0,
   };
 
-  unsigned int _seq;
-
-  // This mutex globally protects all UpdateSeqs in the world.
-  static Mutex _lock;
+  PN_int32 _seq;
+  Mutex _lock;
 };
 
 INLINE ostream &operator << (ostream &out, const UpdateSeq &value);

+ 3 - 1
panda/src/tform/mouseWatcherGroup.cxx

@@ -29,7 +29,9 @@ TypeHandle MouseWatcherGroup::_type_handle;
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 MouseWatcherGroup::
-MouseWatcherGroup() {
+MouseWatcherGroup() :
+  _lock("MouseWatcherGroup")
+{
 #ifndef NDEBUG
   _show_regions = false;
   _color.set(0.4f, 0.6f, 1.0f, 1.0f);