Browse Source

mutex_spinlock

David Rose 19 years ago
parent
commit
7986aaa0c3
56 changed files with 722 additions and 177 deletions
  1. 8 0
      dtool/Config.pp
  2. 3 0
      dtool/LocalSetup.pp
  3. 1 0
      dtool/Package.pp
  4. 4 1
      dtool/src/dtoolbase/Sources.pp
  5. 11 0
      dtool/src/dtoolbase/atomicAdjust.h
  6. 8 8
      dtool/src/dtoolbase/atomicAdjustDummyImpl.I
  7. 0 5
      dtool/src/dtoolbase/atomicAdjustDummyImpl.cxx
  8. 8 15
      dtool/src/dtoolbase/atomicAdjustDummyImpl.h
  9. 12 12
      dtool/src/dtoolbase/atomicAdjustI386Impl.I
  10. 8 11
      dtool/src/dtoolbase/atomicAdjustI386Impl.h
  11. 60 10
      dtool/src/dtoolbase/atomicAdjustNsprImpl.I
  12. 4 2
      dtool/src/dtoolbase/atomicAdjustNsprImpl.cxx
  13. 20 8
      dtool/src/dtoolbase/atomicAdjustNsprImpl.h
  14. 56 6
      dtool/src/dtoolbase/atomicAdjustPosixImpl.I
  15. 2 2
      dtool/src/dtoolbase/atomicAdjustPosixImpl.cxx
  16. 16 8
      dtool/src/dtoolbase/atomicAdjustPosixImpl.h
  17. 9 9
      dtool/src/dtoolbase/atomicAdjustWin32Impl.I
  18. 2 2
      dtool/src/dtoolbase/atomicAdjustWin32Impl.cxx
  19. 10 13
      dtool/src/dtoolbase/atomicAdjustWin32Impl.h
  20. 1 0
      dtool/src/dtoolbase/dtoolbase_composite1.cxx
  21. 1 1
      dtool/src/dtoolbase/dtoolbase_composite2.cxx
  22. 0 5
      dtool/src/dtoolbase/mutexDummyImpl.cxx
  23. 0 4
      dtool/src/dtoolbase/mutexDummyImpl.h
  24. 8 1
      dtool/src/dtoolbase/mutexImpl.h
  25. 12 0
      dtool/src/dtoolbase/mutexLinuxImpl.I
  26. 2 2
      dtool/src/dtoolbase/mutexLinuxImpl.cxx
  27. 3 4
      dtool/src/dtoolbase/mutexLinuxImpl.h
  28. 54 0
      dtool/src/dtoolbase/mutexNsprImpl.I
  29. 2 2
      dtool/src/dtoolbase/mutexNsprImpl.cxx
  30. 20 4
      dtool/src/dtoolbase/mutexNsprImpl.h
  31. 2 2
      dtool/src/dtoolbase/mutexPosixImpl.cxx
  32. 2 4
      dtool/src/dtoolbase/mutexPosixImpl.h
  33. 69 0
      dtool/src/dtoolbase/mutexSpinlockImpl.I
  34. 36 0
      dtool/src/dtoolbase/mutexSpinlockImpl.cxx
  35. 52 0
      dtool/src/dtoolbase/mutexSpinlockImpl.h
  36. 2 2
      dtool/src/dtoolbase/mutexWin32Impl.cxx
  37. 2 4
      dtool/src/dtoolbase/mutexWin32Impl.h
  38. 11 0
      dtool/src/dtoolbase/selectThreadImpl.h
  39. 3 0
      panda/src/pipeline/Sources.pp
  40. 0 5
      panda/src/pipeline/conditionVarDummyImpl.cxx
  41. 0 4
      panda/src/pipeline/conditionVarDummyImpl.h
  42. 5 0
      panda/src/pipeline/conditionVarImpl.h
  43. 2 2
      panda/src/pipeline/conditionVarLinuxImpl.cxx
  44. 2 2
      panda/src/pipeline/conditionVarLinuxImpl.h
  45. 2 2
      panda/src/pipeline/conditionVarNsprImpl.cxx
  46. 2 2
      panda/src/pipeline/conditionVarNsprImpl.h
  47. 2 2
      panda/src/pipeline/conditionVarPosixImpl.cxx
  48. 2 2
      panda/src/pipeline/conditionVarPosixImpl.h
  49. 48 0
      panda/src/pipeline/conditionVarSpinlockImpl.I
  50. 41 0
      panda/src/pipeline/conditionVarSpinlockImpl.cxx
  51. 65 0
      panda/src/pipeline/conditionVarSpinlockImpl.h
  52. 2 2
      panda/src/pipeline/conditionVarWin32Impl.cxx
  53. 2 2
      panda/src/pipeline/conditionVarWin32Impl.h
  54. 2 0
      panda/src/pipeline/mutexDebug.cxx
  55. 1 0
      panda/src/pipeline/pipeline_composite1.cxx
  56. 20 5
      panda/src/pipeline/test_concurrency.cxx

+ 8 - 0
dtool/Config.pp

@@ -599,6 +599,14 @@
 // run-time overhead for these tests.
 #defer DEBUG_THREADS $[<= $[OPTIMIZE], 2]
 
+// Define this true to implement mutexes and condition variables via
+// user-space spinlocks, instead of via OS-provided constructs.  This
+// is almost never a good idea, except possibly in very specialized
+// cases when you are building Panda for a particular application, on
+// a particular platform, and you are sure you won't have more threads
+// than CPU's.  Even then, OS-based locking is probably better.
+#define MUTEX_SPINLOCK
+
 // Do you want to build the network interface?  What additional libraries
 // are required?  Currently, this requires NSPR.
 #define NET_IPATH

+ 3 - 0
dtool/LocalSetup.pp

@@ -235,6 +235,9 @@ $[cdefine HAVE_THREADS]
 /* Define to enable deadlock detection, mutex recursion checks, etc. */
 $[cdefine DEBUG_THREADS]
 
+/* Define to implement mutexes and condition variables via a user-space spinlock. */
+$[cdefine MUTEX_SPINLOCK]
+
 /* Define if we want to compile the net code.  */
 $[cdefine HAVE_NET]
 

+ 1 - 0
dtool/Package.pp

@@ -214,6 +214,7 @@
 
 #set HAVE_THREADS $[HAVE_THREADS]
 #set DEBUG_THREADS $[DEBUG_THREADS]
+#set MUTEX_SPINLOCK $[MUTEX_SPINLOCK]
 
 #set NET_IPATH $[unixfilename $[NET_IPATH]]
 #set NET_LPATH $[unixfilename $[NET_LPATH]]

+ 4 - 1
dtool/src/dtoolbase/Sources.pp

@@ -24,6 +24,7 @@
     mutexLinuxImpl.h mutexLinuxImpl.I \
     mutexPosixImpl.h mutexPosixImpl.I \
     mutexWin32Impl.h mutexWin32Impl.I \
+    mutexSpinlockImpl.h mutexSpinlockImpl.I \
     nearly_zero.h \
     numeric_types.h \
     selectThreadImpl.h \
@@ -43,7 +44,8 @@
     mutexNsprImpl.cxx \
     mutexLinuxImpl.cxx \
     mutexPosixImpl.cxx \
-    mutexWin32Impl.cxx
+    mutexWin32Impl.cxx \
+    mutexSpinlockImpl.cxx
 
   #define INSTALL_HEADERS \
     atomicAdjust.h \
@@ -63,6 +65,7 @@
     mutexLinuxImpl.h mutexLinuxImpl.I \
     mutexPosixImpl.h mutexPosixImpl.I \
     mutexWin32Impl.h mutexWin32Impl.I \
+    mutexSpinlockImpl.h mutexSpinlockImpl.I \
     nearly_zero.h \
     numeric_types.h \
     selectThreadImpl.h \

+ 11 - 0
dtool/src/dtoolbase/atomicAdjust.h

@@ -35,11 +35,22 @@ typedef AtomicAdjustDummyImpl AtomicAdjust;
 #include "atomicAdjustI386Impl.h"
 typedef AtomicAdjustI386Impl AtomicAdjust;
 
+// These symbols are defined if the compare_and_exchange() methods are
+// implemented natively, without recourse to external locks.  If these
+// are not defined, users may elect to implement an operation with
+// some other method than compare_and_exchange(), which might be
+// faster.
+#define HAVE_ATOMIC_COMPARE_AND_EXCHANGE 1
+#define HAVE_ATOMIC_COMPARE_AND_EXCHANGE_PTR 1
+
 #elif defined(THREAD_WIN32_IMPL)
 
 #include "atomicAdjustWin32Impl.h"
 typedef AtomicAdjustWin32Impl AtomicAdjust;
 
+#define HAVE_ATOMIC_COMPARE_AND_EXCHANGE 1
+#define HAVE_ATOMIC_COMPARE_AND_EXCHANGE_PTR 1
+
 #elif defined(THREAD_LINUX_IMPL)
 
 #error Linux native threads are currently implemented only for i386; use Posix threads instead.

+ 8 - 8
dtool/src/dtoolbase/atomicAdjustDummyImpl.I

@@ -23,7 +23,7 @@
 //  Description: Atomically increments the indicated variable.
 ////////////////////////////////////////////////////////////////////
 INLINE void AtomicAdjustDummyImpl::
-inc(PN_int32 &var) {
+inc(TVOLATILE PN_int32 &var) {
   ++var;
 }
 
@@ -35,7 +35,7 @@ inc(PN_int32 &var) {
 //               is zero.
 ////////////////////////////////////////////////////////////////////
 INLINE bool AtomicAdjustDummyImpl::
-dec(PN_int32 &var) {
+dec(TVOLATILE PN_int32 &var) {
   return (--var) != 0;
 }
 
@@ -46,7 +46,7 @@ dec(PN_int32 &var) {
 //               returns the original value.
 ////////////////////////////////////////////////////////////////////
 INLINE PN_int32 AtomicAdjustDummyImpl::
-set(PN_int32 &var, PN_int32 new_value) {
+set(TVOLATILE PN_int32 &var, PN_int32 new_value) {
   PN_int32 orig_value = var;
   var = new_value;
   return orig_value;
@@ -62,7 +62,7 @@ set(PN_int32 &var, PN_int32 new_value) {
 //               (via other AtomicAjust methods).
 ////////////////////////////////////////////////////////////////////
 INLINE PN_int32 AtomicAdjustDummyImpl::
-get(const PN_int32 &var) {
+get(const TVOLATILE PN_int32 &var) {
   return var;
 }
 
@@ -73,7 +73,7 @@ get(const PN_int32 &var) {
 //               returns the original value.
 ////////////////////////////////////////////////////////////////////
 INLINE void *AtomicAdjustDummyImpl::
-set_ptr(void *&var, void *new_value) {
+set_ptr(void * TVOLATILE &var, void *new_value) {
   void *orig_value = var;
   var = new_value;
   return orig_value;
@@ -89,7 +89,7 @@ set_ptr(void *&var, void *new_value) {
 //               (via other AtomicAjust methods).
 ////////////////////////////////////////////////////////////////////
 INLINE void *AtomicAdjustDummyImpl::
-get_ptr(void * const &var) {
+get_ptr(void * const TVOLATILE &var) {
   return var;
 }
 
@@ -104,7 +104,7 @@ get_ptr(void * const &var) {
 //               return_value == old_value.
 ////////////////////////////////////////////////////////////////////
 INLINE PN_int32 AtomicAdjustDummyImpl::
-compare_and_exchange(PN_int32 &mem, PN_int32 old_value,
+compare_and_exchange(TVOLATILE PN_int32 &mem, PN_int32 old_value,
                      PN_int32 new_value) {
   PN_int32 orig_value = mem;
   if (mem == old_value) {
@@ -121,7 +121,7 @@ compare_and_exchange(PN_int32 &mem, PN_int32 old_value,
 //               As above, but works on pointers instead of integers.
 ////////////////////////////////////////////////////////////////////
 INLINE void *AtomicAdjustDummyImpl::
-compare_and_exchange_ptr(void *&mem, void *old_value,
+compare_and_exchange_ptr(void * TVOLATILE &mem, void *old_value,
                          void *new_value) {
   void *orig_value = mem;
   if (mem == old_value) {

+ 0 - 5
dtool/src/dtoolbase/atomicAdjustDummyImpl.cxx

@@ -17,9 +17,4 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "selectThreadImpl.h"
-
-#ifdef THREAD_DUMMY_IMPL
-
 #include "atomicAdjustDummyImpl.h"
-
-#endif  // THREAD_DUMMY_IMPL

+ 8 - 15
dtool/src/dtoolbase/atomicAdjustDummyImpl.h

@@ -22,13 +22,8 @@
 #include "dtoolbase.h"
 #include "selectThreadImpl.h"
 
-#ifdef THREAD_DUMMY_IMPL
-
 #include "numeric_types.h"
 
-#define HAVE_ATOMIC_COMPARE_AND_EXCHANGE 1
-#define HAVE_ATOMIC_COMPARE_AND_EXCHANGE_PTR 1
-
 ////////////////////////////////////////////////////////////////////
 //       Class : AtomicAdjustDummyImpl
 // Description : A trivial implementation for atomic adjustments for
@@ -37,25 +32,23 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_DTOOL AtomicAdjustDummyImpl {
 public:
-  INLINE static void inc(PN_int32 &var);
-  INLINE static bool dec(PN_int32 &var);
-  INLINE static PN_int32 set(PN_int32 &var, PN_int32 new_value);
-  INLINE static PN_int32 get(const PN_int32 &var);
+  INLINE static void inc(TVOLATILE PN_int32 &var);
+  INLINE static bool dec(TVOLATILE PN_int32 &var);
+  INLINE static PN_int32 set(TVOLATILE PN_int32 &var, PN_int32 new_value);
+  INLINE static PN_int32 get(const TVOLATILE PN_int32 &var);
 
-  INLINE static void *set_ptr(void *&var, void *new_value);
-  INLINE static void *get_ptr(void * const &var);
+  INLINE static void *set_ptr(void * TVOLATILE &var, void *new_value);
+  INLINE static void *get_ptr(void * const TVOLATILE &var);
 
-  INLINE static PN_int32 compare_and_exchange(PN_int32 &mem, 
+  INLINE static PN_int32 compare_and_exchange(TVOLATILE PN_int32 &mem, 
                                               PN_int32 old_value,
                                               PN_int32 new_value);
 
-  INLINE static void *compare_and_exchange_ptr(void *&mem, 
+  INLINE static void *compare_and_exchange_ptr(void * TVOLATILE &mem, 
                                                void *old_value,
                                                void *new_value);
 };
 
 #include "atomicAdjustDummyImpl.I"
 
-#endif  // THREAD_DUMMY_IMPL
-
 #endif

+ 12 - 12
dtool/src/dtoolbase/atomicAdjustI386Impl.I

@@ -23,10 +23,10 @@
 //  Description: Atomically increments the indicated variable.
 ////////////////////////////////////////////////////////////////////
 INLINE void AtomicAdjustI386Impl::
-inc(volatile PN_int32 &var) {
+inc(TVOLATILE PN_int32 &var) {
 #ifdef _M_IX86
   // Windows case
-  volatile PN_int32 *var_ptr = &var;
+  TVOLATILE PN_int32 *var_ptr = &var;
   __asm {
     mov edx, var_ptr;
     lock inc dword ptr [edx];
@@ -47,11 +47,11 @@ inc(volatile PN_int32 &var) {
 //               is zero.
 ////////////////////////////////////////////////////////////////////
 INLINE bool AtomicAdjustI386Impl::
-dec(volatile PN_int32 &var) {
+dec(TVOLATILE PN_int32 &var) {
   unsigned char c;
 #ifdef _M_IX86
   // Windows case
-  volatile PN_int32 *var_ptr = &var;
+  TVOLATILE PN_int32 *var_ptr = &var;
   __asm {
     mov edx, var_ptr;
     lock dec dword ptr [edx];
@@ -73,7 +73,7 @@ dec(volatile PN_int32 &var) {
 //               returns the original value.
 ////////////////////////////////////////////////////////////////////
 INLINE PN_int32 AtomicAdjustI386Impl::
-set(PN_int32 &var, PN_int32 new_value) {
+set(TVOLATILE PN_int32 &var, PN_int32 new_value) {
   PN_int32 orig_value = var;
   var = new_value;
   return orig_value;
@@ -89,7 +89,7 @@ set(PN_int32 &var, PN_int32 new_value) {
 //               (via other AtomicAjust methods).
 ////////////////////////////////////////////////////////////////////
 INLINE PN_int32 AtomicAdjustI386Impl::
-get(const PN_int32 &var) {
+get(const TVOLATILE PN_int32 &var) {
   return var;
 }
 
@@ -100,7 +100,7 @@ get(const PN_int32 &var) {
 //               returns the original value.
 ////////////////////////////////////////////////////////////////////
 INLINE void *AtomicAdjustI386Impl::
-set_ptr(void *&var, void *new_value) {
+set_ptr(void * TVOLATILE &var, void *new_value) {
   void *orig_value = var;
   var = new_value;
   return orig_value;
@@ -116,7 +116,7 @@ set_ptr(void *&var, void *new_value) {
 //               (via other AtomicAjust methods).
 ////////////////////////////////////////////////////////////////////
 INLINE void *AtomicAdjustI386Impl::
-get_ptr(void * const &var) {
+get_ptr(void * const TVOLATILE &var) {
   return var;
 }
 
@@ -140,12 +140,12 @@ get_ptr(void * const &var) {
 //
 ////////////////////////////////////////////////////////////////////
 INLINE PN_int32 AtomicAdjustI386Impl::
-compare_and_exchange(volatile PN_int32 &mem, PN_int32 old_value,
+compare_and_exchange(TVOLATILE PN_int32 &mem, PN_int32 old_value,
                      PN_int32 new_value) {
   PN_int32 prev;
 #ifdef _M_IX86
   // Windows case
-  volatile PN_int32 *mem_ptr = &mem;
+  TVOLATILE PN_int32 *mem_ptr = &mem;
   __asm {
     mov edx, mem_ptr;
     mov ecx, new_value;
@@ -171,12 +171,12 @@ compare_and_exchange(volatile PN_int32 &mem, PN_int32 old_value,
 //               As above, but works on pointers instead of integers.
 ////////////////////////////////////////////////////////////////////
 INLINE void *AtomicAdjustI386Impl::
-compare_and_exchange_ptr(void * volatile &mem, void *old_value,
+compare_and_exchange_ptr(void * TVOLATILE &mem, void *old_value,
                          void *new_value) {
   void *prev;
 #ifdef _M_IX86
   // Windows case
-  void * volatile *mem_ptr = &mem;
+  void * TVOLATILE *mem_ptr = &mem;
   __asm {
     mov edx, mem_ptr;
     mov ecx, new_value;

+ 8 - 11
dtool/src/dtoolbase/atomicAdjustI386Impl.h

@@ -26,9 +26,6 @@
 
 #include "numeric_types.h"
 
-#define HAVE_ATOMIC_COMPARE_AND_EXCHANGE 1
-#define HAVE_ATOMIC_COMPARE_AND_EXCHANGE_PTR 1
-
 ////////////////////////////////////////////////////////////////////
 //       Class : AtomicAdjustI386Impl
 // Description : Uses assembly-language calls to atomically increment
@@ -38,19 +35,19 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_DTOOL AtomicAdjustI386Impl {
 public:
-  INLINE static void inc(volatile PN_int32 &var);
-  INLINE static bool dec(volatile PN_int32 &var);
-  INLINE static PN_int32 set(PN_int32 &var, PN_int32 new_value);
-  INLINE static PN_int32 get(const PN_int32 &var);
+  INLINE static void inc(TVOLATILE PN_int32 &var);
+  INLINE static bool dec(TVOLATILE PN_int32 &var);
+  INLINE static PN_int32 set(TVOLATILE PN_int32 &var, PN_int32 new_value);
+  INLINE static PN_int32 get(const TVOLATILE PN_int32 &var);
 
-  INLINE static void *set_ptr(void *&var, void *new_value);
-  INLINE static void *get_ptr(void * const &var);
+  INLINE static void *set_ptr(void * TVOLATILE &var, void *new_value);
+  INLINE static void *get_ptr(void * const TVOLATILE &var);
 
-  INLINE static PN_int32 compare_and_exchange(volatile PN_int32 &mem, 
+  INLINE static PN_int32 compare_and_exchange(TVOLATILE PN_int32 &mem, 
                                               PN_int32 old_value,
                                               PN_int32 new_value);
 
-  INLINE static void *compare_and_exchange_ptr(void * volatile &mem, 
+  INLINE static void *compare_and_exchange_ptr(void * TVOLATILE &mem, 
                                                void *old_value,
                                                void *new_value);
 };

+ 60 - 10
dtool/src/dtoolbase/atomicAdjustNsprImpl.I

@@ -23,8 +23,8 @@
 //  Description: Atomically increments the indicated variable.
 ////////////////////////////////////////////////////////////////////
 INLINE void AtomicAdjustNsprImpl::
-inc(PN_int32 &var) {
-  PR_AtomicIncrement(&var);
+inc(TVOLATILE PN_int32 &var) {
+  PR_AtomicIncrement((PRInt32 *)&var);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -35,8 +35,8 @@ inc(PN_int32 &var) {
 //               is zero.
 ////////////////////////////////////////////////////////////////////
 INLINE bool AtomicAdjustNsprImpl::
-dec(PN_int32 &var) {
-  return (PR_AtomicDecrement(&var) != 0);
+dec(TVOLATILE PN_int32 &var) {
+  return (PR_AtomicDecrement((PRInt32 *)&var) != 0);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -46,8 +46,8 @@ dec(PN_int32 &var) {
 //               returns the original value.
 ////////////////////////////////////////////////////////////////////
 INLINE PN_int32 AtomicAdjustNsprImpl::
-set(PN_int32 &var, PN_int32 new_value) {
-  return PR_AtomicSet(&var, new_value);
+set(TVOLATILE PN_int32 &var, PN_int32 new_value) {
+  return PR_AtomicSet((PRInt32 *)&var, new_value);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -60,7 +60,7 @@ set(PN_int32 &var, PN_int32 new_value) {
 //               (via other AtomicAjust methods).
 ////////////////////////////////////////////////////////////////////
 INLINE PN_int32 AtomicAdjustNsprImpl::
-get(const PN_int32 &var) {
+get(const TVOLATILE PN_int32 &var) {
   return var;
 }
 
@@ -71,8 +71,8 @@ get(const PN_int32 &var) {
 //               returns the original value.
 ////////////////////////////////////////////////////////////////////
 INLINE void *AtomicAdjustNsprImpl::
-set_ptr(void *&var, void *new_value) {
-  return PR_AtomicSet((PN_int32 *)&var, (PN_int32)new_value);
+set_ptr(void * TVOLATILE &var, void *new_value) {
+  return (void *)PR_AtomicSet((PRInt32 *)&var, (PRInt32)new_value);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -85,6 +85,56 @@ set_ptr(void *&var, void *new_value) {
 //               (via other AtomicAjust methods).
 ////////////////////////////////////////////////////////////////////
 INLINE void *AtomicAdjustNsprImpl::
-get_ptr(void * const &var) {
+get_ptr(void * const TVOLATILE &var) {
   return var;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: AtomicAdjustNsprImpl::compare_and_exchange
+//       Access: Public, Static
+//  Description: Atomic compare and exchange.  
+//
+//               If mem is equal to old_value, store new_value in mem.
+//               In either case, return the original value of mem.
+//               The caller can test for success by comparing
+//               return_value == old_value.
+//
+//               The atomic function expressed in pseudo-code:
+//
+//                 orig_value = mem;
+//                 if (mem == old_value) {
+//                   mem = new_value;
+//                 }
+//                 return orig_value;
+//
+////////////////////////////////////////////////////////////////////
+INLINE PN_int32 AtomicAdjustNsprImpl::
+compare_and_exchange(TVOLATILE PN_int32 &mem, PN_int32 old_value,
+                     PN_int32 new_value) {
+  PR_Lock(_mutex);
+  PN_int32 orig_value = mem;
+  if (mem == old_value) {
+    mem = new_value;
+  }
+  PR_Unlock(_mutex);
+  return orig_value;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AtomicAdjustNsprImpl::compare_and_exchange_ptr
+//       Access: Public, Static
+//  Description: Atomic compare and exchange.  
+//
+//               As above, but works on pointers instead of integers.
+////////////////////////////////////////////////////////////////////
+INLINE void *AtomicAdjustNsprImpl::
+compare_and_exchange_ptr(void * TVOLATILE &mem, void *old_value,
+                         void *new_value) {
+  PR_Lock(_mutex);
+  void *orig_value = mem;
+  if (mem == old_value) {
+    mem = new_value;
+  }
+  PR_Unlock(_mutex);
+  return orig_value;
+}

+ 4 - 2
dtool/src/dtoolbase/atomicAdjustNsprImpl.cxx

@@ -18,8 +18,10 @@
 
 #include "selectThreadImpl.h"
 
-#ifdef THREAD_NSPR_IMPL
+#ifdef HAVE_NSPR
 
 #include "atomicAdjustNsprImpl.h"
 
-#endif  // THREAD_NSPR_IMPL
+PRLock *AtomicAdjustNsprImpl::_mutex = PR_NewLock();
+
+#endif  // HAVE_NSPR

+ 20 - 8
dtool/src/dtoolbase/atomicAdjustNsprImpl.h

@@ -22,11 +22,12 @@
 #include "dtoolbase.h"
 #include "selectThreadImpl.h"
 
-#ifdef THREAD_NSPR_IMPL
+#ifdef HAVE_NSPR
 
 #include "numeric_types.h"
 
 #include <pratom.h>
+#include <prlock.h>
 
 ////////////////////////////////////////////////////////////////////
 //       Class : AtomicAdjustNsprImpl
@@ -34,17 +35,28 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_DTOOL AtomicAdjustNsprImpl {
 public:
-  INLINE static void inc(PN_int32 &var);
-  INLINE static bool dec(PN_int32 &var);
-  INLINE static PN_int32 set(PN_int32 &var, PN_int32 new_value);
-  INLINE static PN_int32 get(const PN_int32 &var);
+  INLINE static void inc(TVOLATILE PN_int32 &var);
+  INLINE static bool dec(TVOLATILE PN_int32 &var);
+  INLINE static PN_int32 set(TVOLATILE PN_int32 &var, PN_int32 new_value);
+  INLINE static PN_int32 get(const TVOLATILE PN_int32 &var);
 
-  INLINE static void *set_ptr(void *&var, void *new_value);
-  INLINE static void *get_ptr(void * const &var);
+  INLINE static void *set_ptr(void * TVOLATILE &var, void *new_value);
+  INLINE static void *get_ptr(void * const TVOLATILE &var);
+
+  INLINE static PN_int32 compare_and_exchange(TVOLATILE PN_int32 &mem, 
+                                              PN_int32 old_value,
+                                              PN_int32 new_value);
+
+  INLINE static void *compare_and_exchange_ptr(void * TVOLATILE &mem, 
+                                               void *old_value,
+                                               void *new_value);
+
+private:
+  static PRLock *_mutex;
 };
 
 #include "atomicAdjustNsprImpl.I"
 
-#endif  // THREAD_NSPR_IMPL
+#endif  // HAVE_NSPR
 
 #endif

+ 56 - 6
dtool/src/dtoolbase/atomicAdjustPosixImpl.I

@@ -23,7 +23,7 @@
 //  Description: Atomically increments the indicated variable.
 ////////////////////////////////////////////////////////////////////
 INLINE void AtomicAdjustPosixImpl::
-inc(PN_int32 &var) {
+inc(TVOLATILE PN_int32 &var) {
   pthread_mutex_lock(&_mutex);
   ++var;
   pthread_mutex_unlock(&_mutex);
@@ -37,7 +37,7 @@ inc(PN_int32 &var) {
 //               is zero.
 ////////////////////////////////////////////////////////////////////
 INLINE bool AtomicAdjustPosixImpl::
-dec(PN_int32 &var) {
+dec(TVOLATILE PN_int32 &var) {
   pthread_mutex_lock(&_mutex);
   PN_int32 result = --var;
   pthread_mutex_unlock(&_mutex);
@@ -51,7 +51,7 @@ dec(PN_int32 &var) {
 //               returns the original value.
 ////////////////////////////////////////////////////////////////////
 INLINE PN_int32 AtomicAdjustPosixImpl::
-set(PN_int32 &var, PN_int32 new_value) {
+set(TVOLATILE PN_int32 &var, PN_int32 new_value) {
   pthread_mutex_lock(&_mutex);
   PN_int32 orig_value = var;
   var = new_value;
@@ -69,7 +69,7 @@ set(PN_int32 &var, PN_int32 new_value) {
 //               (via other AtomicAjust methods).
 ////////////////////////////////////////////////////////////////////
 INLINE PN_int32 AtomicAdjustPosixImpl::
-get(const PN_int32 &var) {
+get(const TVOLATILE PN_int32 &var) {
   pthread_mutex_lock(&_mutex);
   PN_int32 orig_value = var;
   pthread_mutex_unlock(&_mutex);
@@ -83,7 +83,7 @@ get(const PN_int32 &var) {
 //               returns the original value.
 ////////////////////////////////////////////////////////////////////
 INLINE void *AtomicAdjustPosixImpl::
-set_ptr(void *&var, void *new_value) {
+set_ptr(void * TVOLATILE &var, void *new_value) {
   pthread_mutex_lock(&_mutex);
   void *orig_value = var;
   var = new_value;
@@ -101,9 +101,59 @@ set_ptr(void *&var, void *new_value) {
 //               (via other AtomicAjust methods).
 ////////////////////////////////////////////////////////////////////
 INLINE void *AtomicAdjustPosixImpl::
-get_ptr(void * const &var) {
+get_ptr(void * const TVOLATILE &var) {
   pthread_mutex_lock(&_mutex);
   void *orig_value = var;
   pthread_mutex_unlock(&_mutex);
   return orig_value;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: AtomicAdjustPosixImpl::compare_and_exchange
+//       Access: Public, Static
+//  Description: Atomic compare and exchange.  
+//
+//               If mem is equal to old_value, store new_value in mem.
+//               In either case, return the original value of mem.
+//               The caller can test for success by comparing
+//               return_value == old_value.
+//
+//               The atomic function expressed in pseudo-code:
+//
+//                 orig_value = mem;
+//                 if (mem == old_value) {
+//                   mem = new_value;
+//                 }
+//                 return orig_value;
+//
+////////////////////////////////////////////////////////////////////
+INLINE PN_int32 AtomicAdjustPosixImpl::
+compare_and_exchange(TVOLATILE PN_int32 &mem, PN_int32 old_value,
+                     PN_int32 new_value) {
+  pthread_mutex_lock(&_mutex);
+  PN_int32 orig_value = mem;
+  if (mem == old_value) {
+    mem = new_value;
+  }
+  pthread_mutex_unlock(&_mutex);
+  return orig_value;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AtomicAdjustPosixImpl::compare_and_exchange_ptr
+//       Access: Public, Static
+//  Description: Atomic compare and exchange.  
+//
+//               As above, but works on pointers instead of integers.
+////////////////////////////////////////////////////////////////////
+INLINE void *AtomicAdjustPosixImpl::
+compare_and_exchange_ptr(void * TVOLATILE &mem, void *old_value,
+                         void *new_value) {
+  pthread_mutex_lock(&_mutex);
+  void *orig_value = mem;
+  if (mem == old_value) {
+    mem = new_value;
+  }
+  pthread_mutex_unlock(&_mutex);
+  return orig_value;
+}

+ 2 - 2
dtool/src/dtoolbase/atomicAdjustPosixImpl.cxx

@@ -18,10 +18,10 @@
 
 #include "selectThreadImpl.h"
 
-#ifdef THREAD_POSIX_IMPL
+#ifdef HAVE_POSIX_THREADS
 
 #include "atomicAdjustPosixImpl.h"
 
 pthread_mutex_t AtomicAdjustPosixImpl::_mutex = PTHREAD_MUTEX_INITIALIZER;
 
-#endif  // THREAD_POSIX_IMPL
+#endif  // HAVE_POSIX_THREADS

+ 16 - 8
dtool/src/dtoolbase/atomicAdjustPosixImpl.h

@@ -22,7 +22,7 @@
 #include "dtoolbase.h"
 #include "selectThreadImpl.h"
 
-#ifdef THREAD_POSIX_IMPL
+#ifdef HAVE_POSIX_THREADS
 
 #include "numeric_types.h"
 
@@ -34,13 +34,21 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_DTOOL AtomicAdjustPosixImpl {
 public:
-  INLINE static void inc(PN_int32 &var);
-  INLINE static bool dec(PN_int32 &var);
-  INLINE static PN_int32 set(PN_int32 &var, PN_int32 new_value);
-  INLINE static PN_int32 get(const PN_int32 &var);
+  INLINE static void inc(TVOLATILE PN_int32 &var);
+  INLINE static bool dec(TVOLATILE PN_int32 &var);
+  INLINE static PN_int32 set(TVOLATILE PN_int32 &var, PN_int32 new_value);
+  INLINE static PN_int32 get(const TVOLATILE PN_int32 &var);
 
-  INLINE static void *set_ptr(void *&var, void *new_value);
-  INLINE static void *get_ptr(void * const &var);
+  INLINE static void *set_ptr(void * TVOLATILE &var, void *new_value);
+  INLINE static void *get_ptr(void * const TVOLATILE &var);
+
+  INLINE static PN_int32 compare_and_exchange(TVOLATILE PN_int32 &mem, 
+                                              PN_int32 old_value,
+                                              PN_int32 new_value);
+
+  INLINE static void *compare_and_exchange_ptr(void * TVOLATILE &mem, 
+                                               void *old_value,
+                                               void *new_value);
 
 private:
   static pthread_mutex_t _mutex;
@@ -48,6 +56,6 @@ private:
 
 #include "atomicAdjustPosixImpl.I"
 
-#endif  // THREAD_POSIX_IMPL
+#endif  // HAVE_POSIX_THREADS
 
 #endif

+ 9 - 9
dtool/src/dtoolbase/atomicAdjustWin32Impl.I

@@ -23,7 +23,7 @@
 //  Description: Atomically increments the indicated variable.
 ////////////////////////////////////////////////////////////////////
 INLINE void AtomicAdjustWin32Impl::
-inc(PN_int32 &var) {
+inc(TVOLATILE PN_int32 &var) {
   InterlockedIncrement((LONG *)&var);
 }
 
@@ -35,7 +35,7 @@ inc(PN_int32 &var) {
 //               is zero.
 ////////////////////////////////////////////////////////////////////
 INLINE bool AtomicAdjustWin32Impl::
-dec(PN_int32 &var) {
+dec(TVOLATILE PN_int32 &var) {
   return (InterlockedDecrement((LONG *)&var) != 0);
 }
 
@@ -46,7 +46,7 @@ dec(PN_int32 &var) {
 //               returns the original value.
 ////////////////////////////////////////////////////////////////////
 INLINE PN_int32 AtomicAdjustWin32Impl::
-set(PN_int32 &var, PN_int32 new_value) {
+set(TVOLATILE PN_int32 &var, PN_int32 new_value) {
   return InterlockedExchange((LONG *)&var, new_value);
 }
 
@@ -60,7 +60,7 @@ set(PN_int32 &var, PN_int32 new_value) {
 //               (via other AtomicAjust methods).
 ////////////////////////////////////////////////////////////////////
 INLINE PN_int32 AtomicAdjustWin32Impl::
-get(const PN_int32 &var) {
+get(const TVOLATILE PN_int32 &var) {
   return var;
 }
 
@@ -71,7 +71,7 @@ get(const PN_int32 &var) {
 //               returns the original value.
 ////////////////////////////////////////////////////////////////////
 INLINE void *AtomicAdjustWin32Impl::
-set_ptr(void *&var, void *new_value) {
+set_ptr(void * TVOLATILE &var, void *new_value) {
   void *orig_value = var;
   var = new_value;
   return orig_value;
@@ -87,7 +87,7 @@ set_ptr(void *&var, void *new_value) {
 //               (via other AtomicAjust methods).
 ////////////////////////////////////////////////////////////////////
 INLINE void *AtomicAdjustWin32Impl::
-get_ptr(void * const &var) {
+get_ptr(void * const TVOLATILE &var) {
   return var;
 }
 
@@ -111,11 +111,11 @@ get_ptr(void * const &var) {
 //
 ////////////////////////////////////////////////////////////////////
 INLINE PN_int32 AtomicAdjustWin32Impl::
-compare_and_exchange(volatile PN_int32 &mem, PN_int32 old_value,
+compare_and_exchange(TVOLATILE PN_int32 &mem, PN_int32 old_value,
                      PN_int32 new_value) {
   // Note that the AtomicAdjust parameter order is different from
   // Windows convention!
-  return InterlockedCompareExchange((volatile LONG *)&mem, new_value, old_value);
+  return InterlockedCompareExchange((TVOLATILE LONG *)&mem, new_value, old_value);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -126,7 +126,7 @@ compare_and_exchange(volatile PN_int32 &mem, PN_int32 old_value,
 //               As above, but works on pointers instead of integers.
 ////////////////////////////////////////////////////////////////////
 INLINE void *AtomicAdjustWin32Impl::
-compare_and_exchange_ptr(void * volatile &mem, void *old_value,
+compare_and_exchange_ptr(void * TVOLATILE &mem, void *old_value,
                          void *new_value) {
   // Note that the AtomicAdjust parameter order is different from
   // Windows convention!

+ 2 - 2
dtool/src/dtoolbase/atomicAdjustWin32Impl.cxx

@@ -18,8 +18,8 @@
 
 #include "selectThreadImpl.h"
 
-#ifdef THREAD_WIN32_IMPL
+#ifdef WIN32_VC
 
 #include "atomicAdjustWin32Impl.h"
 
-#endif  // THREAD_WIN32_IMPL
+#endif  // WIN32_VC

+ 10 - 13
dtool/src/dtoolbase/atomicAdjustWin32Impl.h

@@ -22,15 +22,12 @@
 #include "dtoolbase.h"
 #include "selectThreadImpl.h"
 
-#ifdef THREAD_WIN32_IMPL
+#ifdef WIN32_VC
 
 #include "numeric_types.h"
 
 #include <windows.h>
 
-#define HAVE_ATOMIC_COMPARE_AND_EXCHANGE 1
-#define HAVE_ATOMIC_COMPARE_AND_EXCHANGE_PTR 1
-
 ////////////////////////////////////////////////////////////////////
 //       Class : AtomicAdjustWin32Impl
 // Description : Uses Windows native calls to implement atomic
@@ -38,25 +35,25 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_DTOOL AtomicAdjustWin32Impl {
 public:
-  INLINE static void inc(PN_int32 &var);
-  INLINE static bool dec(PN_int32 &var);
-  INLINE static PN_int32 set(PN_int32 &var, PN_int32 new_value);
-  INLINE static PN_int32 get(const PN_int32 &var);
+  INLINE static void inc(TVOLATILE PN_int32 &var);
+  INLINE static bool dec(TVOLATILE PN_int32 &var);
+  INLINE static PN_int32 set(TVOLATILE PN_int32 &var, PN_int32 new_value);
+  INLINE static PN_int32 get(const TVOLATILE PN_int32 &var);
 
-  INLINE static void *set_ptr(void *&var, void *new_value);
-  INLINE static void *get_ptr(void * const &var);
+  INLINE static void *set_ptr(void * TVOLATILE &var, void *new_value);
+  INLINE static void *get_ptr(void * const TVOLATILE &var);
 
-  INLINE static PN_int32 compare_and_exchange(volatile PN_int32 &mem, 
+  INLINE static PN_int32 compare_and_exchange(TVOLATILE PN_int32 &mem, 
                                               PN_int32 old_value,
                                               PN_int32 new_value);
 
-  INLINE static void *compare_and_exchange_ptr(void * volatile &mem, 
+  INLINE static void *compare_and_exchange_ptr(void * TVOLATILE &mem, 
                                                void *old_value,
                                                void *new_value);
 };
 
 #include "atomicAdjustWin32Impl.I"
 
-#endif  // THREAD_WIN32_IMPL
+#endif  // WIN32_VC
 
 #endif

+ 1 - 0
dtool/src/dtoolbase/dtoolbase_composite1.cxx

@@ -3,3 +3,4 @@
 #include "atomicAdjustNsprImpl.cxx"
 #include "atomicAdjustPosixImpl.cxx"
 #include "atomicAdjustWin32Impl.cxx"
+#include "dtoolbase.cxx"

+ 1 - 1
dtool/src/dtoolbase/dtoolbase_composite2.cxx

@@ -1,6 +1,6 @@
-#include "dtoolbase.cxx"
 #include "mutexDummyImpl.cxx"
 #include "mutexNsprImpl.cxx"
 #include "mutexLinuxImpl.cxx"
 #include "mutexPosixImpl.cxx"
 #include "mutexWin32Impl.cxx"
+#include "mutexSpinlockImpl.cxx"

+ 0 - 5
dtool/src/dtoolbase/mutexDummyImpl.cxx

@@ -17,9 +17,4 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "selectThreadImpl.h"
-
-#ifdef THREAD_DUMMY_IMPL
-
 #include "mutexDummyImpl.h"
-
-#endif  // THREAD_DUMMY_IMPL

+ 0 - 4
dtool/src/dtoolbase/mutexDummyImpl.h

@@ -22,8 +22,6 @@
 #include "dtoolbase.h"
 #include "selectThreadImpl.h"
 
-#ifdef THREAD_DUMMY_IMPL
-
 ////////////////////////////////////////////////////////////////////
 //       Class : MutexDummyImpl
 // Description : A fake mutex implementation for single-threaded
@@ -41,6 +39,4 @@ public:
 
 #include "mutexDummyImpl.I"
 
-#endif  // THREAD_DUMMY_IMPL
-
 #endif

+ 8 - 1
dtool/src/dtoolbase/mutexImpl.h

@@ -29,6 +29,12 @@ typedef MutexDummyImpl MutexImpl;
 typedef MutexDummyImpl ReMutexImpl;
 #define HAVE_REMUTEXIMPL 1
 
+#elif defined(MUTEX_SPINLOCK)
+
+#include "mutexSpinlockImpl.h"
+typedef MutexSpinlockImpl MutexImpl;
+#undef HAVE_REMUTEXIMPL
+
 #elif defined(THREAD_WIN32_IMPL)
 
 #include "mutexWin32Impl.h"
@@ -53,7 +59,8 @@ typedef ReMutexPosixImpl ReMutexImpl;
 
 #include "mutexNsprImpl.h"
 typedef MutexNsprImpl MutexImpl;
-#undef HAVE_REMUTEXIMPL  // NSPR doesn't provide a reentrant mutex.
+typedef ReMutexNsprImpl ReMutexImpl;
+#define HAVE_REMUTEXIMPL 1
 
 #endif
 

+ 12 - 0
dtool/src/dtoolbase/mutexLinuxImpl.I

@@ -36,3 +36,15 @@ INLINE MutexLinuxImpl::
 ~MutexLinuxImpl() {
   assert(_mode == M_unlocked);
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: MutexLinuxImpl::try_lock
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE bool MutexLinuxImpl::
+try_lock() {
+  // We haven't implemented try_lock().  We just report that it would
+  // always block (since we don't know).
+  return false;
+}

+ 2 - 2
dtool/src/dtoolbase/mutexLinuxImpl.cxx

@@ -18,7 +18,7 @@
 
 #include "selectThreadImpl.h"
 
-#ifdef THREAD_LINUX_IMPL
+#ifdef HAVE_LINUX_NATIVE_THREADS
 
 #include "mutexLinuxImpl.h"
 #include "atomicAdjust.h"
@@ -61,4 +61,4 @@ release() {
   }
 }
 
-#endif  // THREAD_LINUX_IMPL
+#endif  // HAVE_LINUX_NATIVE_THREADS

+ 3 - 4
dtool/src/dtoolbase/mutexLinuxImpl.h

@@ -22,12 +22,10 @@
 #include "dtoolbase.h"
 #include "selectThreadImpl.h"
 
-#ifdef THREAD_LINUX_IMPL
+#ifdef HAVE_LINUX_NATIVE_THREADS
 
 #include "numeric_types.h"
 
-#undef MUTEX_DEFINES_TRYLOCK
-
 ////////////////////////////////////////////////////////////////////
 //       Class : MutexLinuxImpl
 // Description : Uses Linux threads to implement a mutex.
@@ -38,6 +36,7 @@ public:
   INLINE ~MutexLinuxImpl();
 
   void lock();
+  INLINE bool try_lock();
   void release();
 
 private:
@@ -53,6 +52,6 @@ private:
 
 #include "mutexLinuxImpl.I"
 
-#endif  // THREAD_LINUX_IMPL
+#endif  // HAVE_LINUX_NATIVE_THREADS
 
 #endif

+ 54 - 0
dtool/src/dtoolbase/mutexNsprImpl.I

@@ -70,3 +70,57 @@ release() {
   int status = PR_Unlock(_lock);
   assert(status == PR_SUCCESS);
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: ReMutexNsprImpl::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE ReMutexNsprImpl::
+ReMutexNsprImpl() {
+  _monitor = PR_NewMonitor();
+  assert(_monitor != (PRMonitor *)NULL);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ReMutexNsprImpl::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE ReMutexNsprImpl::
+~ReMutexNsprImpl() {
+  PR_DestroyMonitor(_monitor);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ReMutexNsprImpl::lock
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void ReMutexNsprImpl::
+lock() {
+  PR_EnterMonitor(_monitor);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ReMutexNsprImpl::try_lock
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE bool ReMutexNsprImpl::
+try_lock() {
+  // NSPR doesn't define a try_lock function.  Too bad.  We just
+  // report that it would always block (since we don't know).
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ReMutexNsprImpl::release
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void ReMutexNsprImpl::
+release() {
+  int status = PR_ExitMonitor(_monitor);
+  assert(status == PR_SUCCESS);
+}

+ 2 - 2
dtool/src/dtoolbase/mutexNsprImpl.cxx

@@ -18,8 +18,8 @@
 
 #include "selectThreadImpl.h"
 
-#ifdef THREAD_NSPR_IMPL
+#ifdef HAVE_NSPR
 
 #include "mutexNsprImpl.h"
 
-#endif  // THREAD_NSPR_IMPL
+#endif  // HAVE_NSPR

+ 20 - 4
dtool/src/dtoolbase/mutexNsprImpl.h

@@ -22,11 +22,10 @@
 #include "dtoolbase.h"
 #include "selectThreadImpl.h"
 
-#ifdef THREAD_NSPR_IMPL
+#ifdef HAVE_NSPR
 
 #include <prlock.h>
-
-#undef MUTEX_DEFINES_TRYLOCK
+#include <prmon.h>
 
 ////////////////////////////////////////////////////////////////////
 //       Class : MutexNsprImpl
@@ -46,8 +45,25 @@ private:
   friend class ConditionVarNsprImpl;
 };
 
+////////////////////////////////////////////////////////////////////
+//       Class : ReMutexNsprImpl
+// Description : Uses NSPR to implement a reMutex.
+////////////////////////////////////////////////////////////////////
+class EXPCL_DTOOL ReMutexNsprImpl {
+public:
+  INLINE ReMutexNsprImpl();
+  INLINE ~ReMutexNsprImpl();
+
+  INLINE void lock();
+  INLINE bool try_lock();
+  INLINE void release();
+
+private:
+  PRMonitor *_monitor;
+};
+
 #include "mutexNsprImpl.I"
 
-#endif  // THREAD_NSPR_IMPL
+#endif  // HAVE_NSPR
 
 #endif

+ 2 - 2
dtool/src/dtoolbase/mutexPosixImpl.cxx

@@ -18,8 +18,8 @@
 
 #include "selectThreadImpl.h"
 
-#ifdef THREAD_POSIX_IMPL
+#ifdef HAVE_POSIX_THREADS
 
 #include "mutexPosixImpl.h"
 
-#endif  // THREAD_POSIX_IMPL
+#endif  // HAVE_POSIX_THREADS

+ 2 - 4
dtool/src/dtoolbase/mutexPosixImpl.h

@@ -22,13 +22,11 @@
 #include "dtoolbase.h"
 #include "selectThreadImpl.h"
 
-#ifdef THREAD_POSIX_IMPL
+#ifdef HAVE_POSIX_THREADS
 
 #include <pthread.h>
 #include <errno.h>
 
-#define MUTEX_DEFINES_TRYLOCK 1
-
 ////////////////////////////////////////////////////////////////////
 //       Class : MutexPosixImpl
 // Description : Uses Posix threads to implement a mutex.
@@ -66,6 +64,6 @@ private:
 
 #include "mutexPosixImpl.I"
 
-#endif  // THREAD_POSIX_IMPL
+#endif  // HAVE_POSIX_THREADS
 
 #endif

+ 69 - 0
dtool/src/dtoolbase/mutexSpinlockImpl.I

@@ -0,0 +1,69 @@
+// Filename: mutexSpinlockImpl.I
+// Created by:  drose (11Apr06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: MutexSpinlockImpl::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE MutexSpinlockImpl::
+MutexSpinlockImpl() {
+  _lock = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MutexSpinlockImpl::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE MutexSpinlockImpl::
+~MutexSpinlockImpl() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MutexSpinlockImpl::lock
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void MutexSpinlockImpl::
+lock() {
+  if (!try_lock()) {
+    do_lock();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MutexSpinlockImpl::try_lock
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE bool MutexSpinlockImpl::
+try_lock() {
+  return (AtomicAdjust::compare_and_exchange(_lock, 0, 1) == 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MutexSpinlockImpl::release
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void MutexSpinlockImpl::
+release() {
+  AtomicAdjust::set(_lock, 0);
+}

+ 36 - 0
dtool/src/dtoolbase/mutexSpinlockImpl.cxx

@@ -0,0 +1,36 @@
+// Filename: mutexSpinlockImpl.cxx
+// Created by:  drose (11Apr06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "selectThreadImpl.h"
+
+#ifdef MUTEX_SPINLOCK
+
+#include "mutexSpinlockImpl.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: MutexSpinlockImpl::do_lock
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void MutexSpinlockImpl::
+do_lock() {
+  while (AtomicAdjust::compare_and_exchange(_lock, 0, 1) != 0) {
+  }
+}
+
+#endif  // MUTEX_SPINLOCK

+ 52 - 0
dtool/src/dtoolbase/mutexSpinlockImpl.h

@@ -0,0 +1,52 @@
+// Filename: mutexSpinlockImpl.h
+// Created by:  drose (11Apr06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef MUTEXSPINLOCKIMPL_H
+#define MUTEXSPINLOCKIMPL_H
+
+#include "dtoolbase.h"
+#include "selectThreadImpl.h"
+
+#ifdef MUTEX_SPINLOCK
+
+#include "atomicAdjust.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : MutexSpinlockImpl
+// Description : Uses Windows native calls to implement a mutex.
+////////////////////////////////////////////////////////////////////
+class EXPCL_DTOOL MutexSpinlockImpl {
+public:
+  INLINE MutexSpinlockImpl();
+  INLINE ~MutexSpinlockImpl();
+
+  INLINE void lock();
+  INLINE bool try_lock();
+  INLINE void release();
+
+private:
+  void do_lock();
+
+  volatile PN_int32 _lock;
+};
+
+#include "mutexSpinlockImpl.I"
+
+#endif  // MUTEX_SPINLOCK
+
+#endif

+ 2 - 2
dtool/src/dtoolbase/mutexWin32Impl.cxx

@@ -18,8 +18,8 @@
 
 #include "selectThreadImpl.h"
 
-#ifdef THREAD_WIN32_IMPL
+#ifdef WIN32_VC
 
 #include "mutexWin32Impl.h"
 
-#endif  // THREAD_WIN32_IMPL
+#endif  // WIN32_VC

+ 2 - 4
dtool/src/dtoolbase/mutexWin32Impl.h

@@ -22,12 +22,10 @@
 #include "dtoolbase.h"
 #include "selectThreadImpl.h"
 
-#ifdef THREAD_WIN32_IMPL
+#ifdef WIN32_VC
 
 #include <windows.h>
 
-#define MUTEX_DEFINES_TRYLOCK 1
-
 ////////////////////////////////////////////////////////////////////
 //       Class : MutexWin32Impl
 // Description : Uses Windows native calls to implement a mutex.
@@ -48,6 +46,6 @@ private:
 
 #include "mutexWin32Impl.I"
 
-#endif  // THREAD_WIN32_IMPL
+#endif  // WIN32_VC
 
 #endif

+ 11 - 0
dtool/src/dtoolbase/selectThreadImpl.h

@@ -33,11 +33,22 @@
 // synchronization classes are defined in panda/src/express.
 ////////////////////////////////////////////////////////////////////
 
+// This keyword should be used to mark any variable which is possibly
+// volatile because multiple threads might contend on it, unprotected
+// by a mutex.  It will be defined out in the non-threaded case.
+// Other uses for volatile (dma buffers, for instance) should use the
+// regular volatile keyword.
+#define TVOLATILE volatile
+
 #if !defined(HAVE_THREADS)
 
 // With threading disabled, use the do-nothing implementation.
 #define THREAD_DUMMY_IMPL 1
 
+// And the TVOLATILE keyword means nothing in the absence of threads.
+#undef TVOLATILE
+#define TVOLATILE
+
 #elif defined(WIN32_VC)
 
 // In Windows, use the native threading library.

+ 3 - 0
panda/src/pipeline/Sources.pp

@@ -19,6 +19,7 @@
     conditionVarLinuxImpl.h conditionVarLinuxImpl.I \
     conditionVarPosixImpl.h conditionVarPosixImpl.I \
     conditionVarWin32Impl.h conditionVarWin32Impl.I \
+    conditionVarSpinlockImpl.h conditionVarSpinlockImpl.I \
     config_pipeline.h \
     cycleData.h cycleData.I \
     cycleDataReader.h cycleDataReader.I \
@@ -58,6 +59,7 @@
     conditionVarLinuxImpl.cxx \
     conditionVarPosixImpl.cxx \
     conditionVarWin32Impl.cxx \
+    conditionVarSpinlockImpl.cxx \
     config_pipeline.cxx \
     cycleData.cxx \
     cycleDataReader.cxx \
@@ -95,6 +97,7 @@
     conditionVarLinuxImpl.h conditionVarLinuxImpl.I \
     conditionVarPosixImpl.h conditionVarPosixImpl.I \
     conditionVarWin32Impl.h conditionVarWin32Impl.I \
+    conditionVarSpinlockImpl.h conditionVarSpinlockImpl.I \
     config_pipeline.h \
     cycleData.h cycleData.I \
     cycleDataReader.h cycleDataReader.I \

+ 0 - 5
panda/src/pipeline/conditionVarDummyImpl.cxx

@@ -17,9 +17,4 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "selectThreadImpl.h"
-
-#ifdef THREAD_DUMMY_IMPL
-
 #include "conditionVarDummyImpl.h"
-
-#endif  // THREAD_DUMMY_IMPL

+ 0 - 4
panda/src/pipeline/conditionVarDummyImpl.h

@@ -22,8 +22,6 @@
 #include "pandabase.h"
 #include "selectThreadImpl.h"
 
-#ifdef THREAD_DUMMY_IMPL
-
 #include "pnotify.h"
 
 class MutexDummyImpl;
@@ -46,6 +44,4 @@ public:
 
 #include "conditionVarDummyImpl.I"
 
-#endif  // THREAD_DUMMY_IMPL
-
 #endif

+ 5 - 0
panda/src/pipeline/conditionVarImpl.h

@@ -27,6 +27,11 @@
 #include "conditionVarDummyImpl.h"
 typedef ConditionVarDummyImpl ConditionVarImpl;
 
+#elif defined(MUTEX_SPINLOCK)
+
+#include "conditionVarSpinlockImpl.h"
+typedef ConditionVarSpinlockImpl ConditionVarImpl;
+
 #elif defined(THREAD_WIN32_IMPL)
 
 #include "conditionVarWin32Impl.h"

+ 2 - 2
panda/src/pipeline/conditionVarLinuxImpl.cxx

@@ -18,7 +18,7 @@
 
 #include "selectThreadImpl.h"
 
-#ifdef THREAD_LINUX_IMPL
+#ifdef HAVE_LINUX_NATIVE_THREADS
 
 #include "conditionVarLinuxImpl.h"
 
@@ -52,4 +52,4 @@ signal() {
   syscall(SYS_futex, &_counter, FUTEX_WAKE, 1);
 }
 
-#endif  // THREAD_LINUX_IMPL
+#endif  // HAVE_LINUX_NATIVE_THREADS

+ 2 - 2
panda/src/pipeline/conditionVarLinuxImpl.h

@@ -22,7 +22,7 @@
 #include "pandabase.h"
 #include "selectThreadImpl.h"
 
-#ifdef THREAD_LINUX_IMPL
+#ifdef HAVE_LINUX_NATIVE_THREADS
 
 #include "mutexLinuxImpl.h"
 #include "pnotify.h"
@@ -48,6 +48,6 @@ private:
 
 #include "conditionVarLinuxImpl.I"
 
-#endif  // THREAD_LINUX_IMPL
+#endif  // HAVE_LINUX_NATIVE_THREADS
 
 #endif

+ 2 - 2
panda/src/pipeline/conditionVarNsprImpl.cxx

@@ -18,8 +18,8 @@
 
 #include "selectThreadImpl.h"
 
-#ifdef THREAD_NSPR_IMPL
+#ifdef HAVE_NSPR
 
 #include "conditionVarNsprImpl.h"
 
-#endif  // THREAD_NSPR_IMPL
+#endif  // HAVE_NSPR

+ 2 - 2
panda/src/pipeline/conditionVarNsprImpl.h

@@ -22,7 +22,7 @@
 #include "pandabase.h"
 #include "selectThreadImpl.h"
 
-#ifdef THREAD_NSPR_IMPL
+#ifdef HAVE_NSPR
 
 #include "mutexNsprImpl.h"
 #include "pnotify.h"
@@ -49,6 +49,6 @@ private:
 
 #include "conditionVarNsprImpl.I"
 
-#endif  // THREAD_NSPR_IMPL
+#endif  // HAVE_NSPR
 
 #endif

+ 2 - 2
panda/src/pipeline/conditionVarPosixImpl.cxx

@@ -18,8 +18,8 @@
 
 #include "selectThreadImpl.h"
 
-#ifdef THREAD_POSIX_IMPL
+#ifdef HAVE_POSIX_THREADS
 
 #include "conditionVarPosixImpl.h"
 
-#endif  // THREAD_POSIX_IMPL
+#endif  // HAVE_POSIX_THREADS

+ 2 - 2
panda/src/pipeline/conditionVarPosixImpl.h

@@ -22,7 +22,7 @@
 #include "pandabase.h"
 #include "selectThreadImpl.h"
 
-#ifdef THREAD_POSIX_IMPL
+#ifdef HAVE_POSIX_THREADS
 
 #include "mutexPosixImpl.h"
 #include "pnotify.h"
@@ -50,6 +50,6 @@ private:
 
 #include "conditionVarPosixImpl.I"
 
-#endif  // THREAD_POSIX_IMPL
+#endif  // HAVE_POSIX_THREADS
 
 #endif

+ 48 - 0
panda/src/pipeline/conditionVarSpinlockImpl.I

@@ -0,0 +1,48 @@
+// Filename: conditionVarSpinlockImpl.I
+// Created by:  drose (11Apr06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConditionVarSpinlockImpl::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE ConditionVarSpinlockImpl::
+ConditionVarSpinlockImpl(MutexSpinlockImpl &mutex) : _mutex(mutex) {
+  _event = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConditionVarSpinlockImpl::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE ConditionVarSpinlockImpl::
+~ConditionVarSpinlockImpl() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConditionVarSpinlockImpl::signal
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void ConditionVarSpinlockImpl::
+signal() {
+  // This will wake up all waiters on the lock.  But that's allowed.
+  AtomicAdjust::inc(_event);
+}

+ 41 - 0
panda/src/pipeline/conditionVarSpinlockImpl.cxx

@@ -0,0 +1,41 @@
+// Filename: conditionVarSpinlockImpl.cxx
+// Created by:  drose (11Apr06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "selectThreadImpl.h"
+
+#ifdef MUTEX_SPINLOCK
+
+#include "conditionVarSpinlockImpl.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConditionVarSpinlockImpl::wait
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void ConditionVarSpinlockImpl::
+wait() {
+  PN_int32 current = _event;
+  _mutex.release();
+
+  while (AtomicAdjust::get(_event) == current) {
+  }
+
+  _mutex.lock();
+}
+
+#endif  // MUTEX_SPINLOCK

+ 65 - 0
panda/src/pipeline/conditionVarSpinlockImpl.h

@@ -0,0 +1,65 @@
+// Filename: conditionVarSpinlockImpl.h
+// Created by:  drose (11Apr06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef CONDITIONVARSPINLOCKIMPL_H
+#define CONDITIONVARSPINLOCKIMPL_H
+
+#include "pandabase.h"
+#include "selectThreadImpl.h"
+
+#ifdef MUTEX_SPINLOCK
+
+#include "mutexSpinlockImpl.h"
+#include "pnotify.h"
+#include "atomicAdjust.h"
+
+class MutexSpinlockImpl;
+
+////////////////////////////////////////////////////////////////////
+//       Class : ConditionVarSpinlockImpl
+// Description : Uses Windows native calls to implement a
+//               conditionVar.
+//
+//               The Windows native synchronization primitives don't
+//               actually implement a full POSIX-style condition
+//               variable, but the Event primitive does a fair job if
+//               we disallow POSIX broadcast.  See
+//               http://www.cs.wustl.edu/~schmidt/spinlock-cv-1.html for
+//               a full implementation that includes broadcast.  This
+//               class is much simpler than that full implementation,
+//               so we can avoid the overhead require to support
+//               broadcast.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA ConditionVarSpinlockImpl {
+public:
+  INLINE ConditionVarSpinlockImpl(MutexSpinlockImpl &mutex);
+  INLINE ~ConditionVarSpinlockImpl();
+
+  void wait();
+  INLINE void signal();
+
+private:
+  MutexSpinlockImpl &_mutex;
+  volatile PN_int32 _event;
+};
+
+#include "conditionVarSpinlockImpl.I"
+
+#endif  // MUTEX_SPINLOCK
+
+#endif

+ 2 - 2
panda/src/pipeline/conditionVarWin32Impl.cxx

@@ -18,8 +18,8 @@
 
 #include "selectThreadImpl.h"
 
-#ifdef THREAD_WIN32_IMPL
+#ifdef WIN32_VC
 
 #include "conditionVarWin32Impl.h"
 
-#endif  // THREAD_WIN32_IMPL
+#endif  // WIN32_VC

+ 2 - 2
panda/src/pipeline/conditionVarWin32Impl.h

@@ -22,7 +22,7 @@
 #include "pandabase.h"
 #include "selectThreadImpl.h"
 
-#ifdef THREAD_WIN32_IMPL
+#ifdef WIN32_VC
 
 #include "mutexWin32Impl.h"
 #include "pnotify.h"
@@ -61,6 +61,6 @@ private:
 
 #include "conditionVarWin32Impl.I"
 
-#endif  // THREAD_WIN32_IMPL
+#endif  // WIN32_VC
 
 #endif

+ 2 - 0
panda/src/pipeline/mutexDebug.cxx

@@ -140,6 +140,8 @@ do_lock() {
     }
     while (_locking_thread != (Thread *)NULL) {
       _cvar.wait();
+      thread_cat.spam()
+        << *this_thread << " wakeup\n";
     }
     
     if (thread_cat.is_spam()) {

+ 1 - 0
panda/src/pipeline/pipeline_composite1.cxx

@@ -6,6 +6,7 @@
 #include "conditionVarLinuxImpl.cxx"
 #include "conditionVarPosixImpl.cxx"
 #include "conditionVarWin32Impl.cxx"
+#include "conditionVarSpinlockImpl.cxx"
 #include "config_pipeline.cxx"
 #include "cycleData.cxx"
 #include "cycleDataReader.cxx"

+ 20 - 5
panda/src/pipeline/test_concurrency.cxx

@@ -34,10 +34,20 @@ static const double delay_between_threads = 2.0;
 static const double thread_run_time = 15.0;
 
 // The number of threads to spawn.
-static const int number_of_threads = 5;
+static const int number_of_threads = 4;
+
+// Number of bytes to reserve between writable memory pointers.
+static const int block_size = 64;
 
 static Mutex _output_lock;
 
+union MemBlock {
+  char _pad[block_size];
+  int _value;
+};
+
+volatile MemBlock memblock[number_of_threads];
+
 #define OUTPUT(stuff) { \
   MutexHolder holder(_output_lock); \
   stuff; \
@@ -45,8 +55,9 @@ static Mutex _output_lock;
 
 class MyThread : public Thread {
 public:
-  MyThread(const string &name) : 
-    Thread(name, name)
+  MyThread(const string &name, int index) : 
+    Thread(name, name),
+    _index(index)
   {
   }
     
@@ -55,11 +66,13 @@ public:
     
     double total_seconds = 0.0;
     TrueClock *clock = TrueClock::get_global_ptr();
+    volatile int snarf;
     
     while (total_seconds < thread_run_time) {
       double start_time = clock->get_short_time();
       
       for (long long i = 0; i < iterations_per_output; ++i) {
+        memblock[_index]._value = snarf;
       }
 
       double end_time = clock->get_short_time();
@@ -75,6 +88,8 @@ public:
     
     OUTPUT(nout << *this << " exiting.\n");
   }
+
+  int _index;
 };
 
 int
@@ -84,14 +99,14 @@ main(int argc, char *argv[]) {
   typedef pvector< PT(MyThread) > Threads;
   Threads threads;
 
-  PT(MyThread) thread = new MyThread("a");
+  PT(MyThread) thread = new MyThread("a", 0);
   threads.push_back(thread);
   thread->start(TP_normal, true, true);
 
   for (int i = 1; i < number_of_threads; ++i) {
     char name = 'a' + i;
     Thread::sleep(delay_between_threads);
-    PT(MyThread) thread = new MyThread(string(1, name));
+    PT(MyThread) thread = new MyThread(string(1, name), i);
     threads.push_back(thread);
     thread->start(TP_normal, true, true);
   }