From 7986aaa0c3d3d9aaae8639ffbeca9642876d4fb3 Mon Sep 17 00:00:00 2001 From: David Rose Date: Wed, 12 Apr 2006 15:15:37 +0000 Subject: [PATCH] mutex_spinlock --- dtool/Config.pp | 8 +++ dtool/LocalSetup.pp | 3 + dtool/Package.pp | 1 + dtool/src/dtoolbase/Sources.pp | 5 +- dtool/src/dtoolbase/atomicAdjust.h | 11 +++ dtool/src/dtoolbase/atomicAdjustDummyImpl.I | 16 ++--- dtool/src/dtoolbase/atomicAdjustDummyImpl.cxx | 5 -- dtool/src/dtoolbase/atomicAdjustDummyImpl.h | 23 +++--- dtool/src/dtoolbase/atomicAdjustI386Impl.I | 24 +++---- dtool/src/dtoolbase/atomicAdjustI386Impl.h | 19 +++-- dtool/src/dtoolbase/atomicAdjustNsprImpl.I | 70 ++++++++++++++++--- dtool/src/dtoolbase/atomicAdjustNsprImpl.cxx | 6 +- dtool/src/dtoolbase/atomicAdjustNsprImpl.h | 28 +++++--- dtool/src/dtoolbase/atomicAdjustPosixImpl.I | 62 ++++++++++++++-- dtool/src/dtoolbase/atomicAdjustPosixImpl.cxx | 4 +- dtool/src/dtoolbase/atomicAdjustPosixImpl.h | 24 ++++--- dtool/src/dtoolbase/atomicAdjustWin32Impl.I | 18 ++--- dtool/src/dtoolbase/atomicAdjustWin32Impl.cxx | 4 +- dtool/src/dtoolbase/atomicAdjustWin32Impl.h | 23 +++--- dtool/src/dtoolbase/dtoolbase_composite1.cxx | 1 + dtool/src/dtoolbase/dtoolbase_composite2.cxx | 2 +- dtool/src/dtoolbase/mutexDummyImpl.cxx | 5 -- dtool/src/dtoolbase/mutexDummyImpl.h | 4 -- dtool/src/dtoolbase/mutexImpl.h | 9 ++- dtool/src/dtoolbase/mutexLinuxImpl.I | 12 ++++ dtool/src/dtoolbase/mutexLinuxImpl.cxx | 4 +- dtool/src/dtoolbase/mutexLinuxImpl.h | 7 +- dtool/src/dtoolbase/mutexNsprImpl.I | 54 ++++++++++++++ dtool/src/dtoolbase/mutexNsprImpl.cxx | 4 +- dtool/src/dtoolbase/mutexNsprImpl.h | 24 +++++-- dtool/src/dtoolbase/mutexPosixImpl.cxx | 4 +- dtool/src/dtoolbase/mutexPosixImpl.h | 6 +- dtool/src/dtoolbase/mutexSpinlockImpl.I | 69 ++++++++++++++++++ dtool/src/dtoolbase/mutexSpinlockImpl.cxx | 36 ++++++++++ dtool/src/dtoolbase/mutexSpinlockImpl.h | 52 ++++++++++++++ dtool/src/dtoolbase/mutexWin32Impl.cxx | 4 +- dtool/src/dtoolbase/mutexWin32Impl.h | 6 +- dtool/src/dtoolbase/selectThreadImpl.h | 11 +++ panda/src/pipeline/Sources.pp | 3 + panda/src/pipeline/conditionVarDummyImpl.cxx | 5 -- panda/src/pipeline/conditionVarDummyImpl.h | 4 -- panda/src/pipeline/conditionVarImpl.h | 5 ++ panda/src/pipeline/conditionVarLinuxImpl.cxx | 4 +- panda/src/pipeline/conditionVarLinuxImpl.h | 4 +- panda/src/pipeline/conditionVarNsprImpl.cxx | 4 +- panda/src/pipeline/conditionVarNsprImpl.h | 4 +- panda/src/pipeline/conditionVarPosixImpl.cxx | 4 +- panda/src/pipeline/conditionVarPosixImpl.h | 4 +- panda/src/pipeline/conditionVarSpinlockImpl.I | 48 +++++++++++++ .../src/pipeline/conditionVarSpinlockImpl.cxx | 41 +++++++++++ panda/src/pipeline/conditionVarSpinlockImpl.h | 65 +++++++++++++++++ panda/src/pipeline/conditionVarWin32Impl.cxx | 4 +- panda/src/pipeline/conditionVarWin32Impl.h | 4 +- panda/src/pipeline/mutexDebug.cxx | 2 + panda/src/pipeline/pipeline_composite1.cxx | 1 + panda/src/pipeline/test_concurrency.cxx | 25 +++++-- 56 files changed, 722 insertions(+), 177 deletions(-) create mode 100644 dtool/src/dtoolbase/mutexSpinlockImpl.I create mode 100644 dtool/src/dtoolbase/mutexSpinlockImpl.cxx create mode 100644 dtool/src/dtoolbase/mutexSpinlockImpl.h create mode 100644 panda/src/pipeline/conditionVarSpinlockImpl.I create mode 100644 panda/src/pipeline/conditionVarSpinlockImpl.cxx create mode 100644 panda/src/pipeline/conditionVarSpinlockImpl.h diff --git a/dtool/Config.pp b/dtool/Config.pp index 84999d3c55..2c05d3a3ce 100644 --- a/dtool/Config.pp +++ b/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 diff --git a/dtool/LocalSetup.pp b/dtool/LocalSetup.pp index cd789476fa..ce3c51d5e4 100644 --- a/dtool/LocalSetup.pp +++ b/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] diff --git a/dtool/Package.pp b/dtool/Package.pp index f0f769c997..b7fbc83aee 100644 --- a/dtool/Package.pp +++ b/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]] diff --git a/dtool/src/dtoolbase/Sources.pp b/dtool/src/dtoolbase/Sources.pp index f1a328c94f..531295e416 100644 --- a/dtool/src/dtoolbase/Sources.pp +++ b/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 \ diff --git a/dtool/src/dtoolbase/atomicAdjust.h b/dtool/src/dtoolbase/atomicAdjust.h index 19cf1999ed..208ac28269 100644 --- a/dtool/src/dtoolbase/atomicAdjust.h +++ b/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. diff --git a/dtool/src/dtoolbase/atomicAdjustDummyImpl.I b/dtool/src/dtoolbase/atomicAdjustDummyImpl.I index d92ecabc7a..ac4d110d95 100644 --- a/dtool/src/dtoolbase/atomicAdjustDummyImpl.I +++ b/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) { diff --git a/dtool/src/dtoolbase/atomicAdjustDummyImpl.cxx b/dtool/src/dtoolbase/atomicAdjustDummyImpl.cxx index 3d62b0a3da..05f1ad627f 100644 --- a/dtool/src/dtoolbase/atomicAdjustDummyImpl.cxx +++ b/dtool/src/dtoolbase/atomicAdjustDummyImpl.cxx @@ -17,9 +17,4 @@ //////////////////////////////////////////////////////////////////// #include "selectThreadImpl.h" - -#ifdef THREAD_DUMMY_IMPL - #include "atomicAdjustDummyImpl.h" - -#endif // THREAD_DUMMY_IMPL diff --git a/dtool/src/dtoolbase/atomicAdjustDummyImpl.h b/dtool/src/dtoolbase/atomicAdjustDummyImpl.h index d4b75b5afa..1ceb327078 100644 --- a/dtool/src/dtoolbase/atomicAdjustDummyImpl.h +++ b/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 diff --git a/dtool/src/dtoolbase/atomicAdjustI386Impl.I b/dtool/src/dtoolbase/atomicAdjustI386Impl.I index 0b283afbc5..7daf966c52 100644 --- a/dtool/src/dtoolbase/atomicAdjustI386Impl.I +++ b/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; diff --git a/dtool/src/dtoolbase/atomicAdjustI386Impl.h b/dtool/src/dtoolbase/atomicAdjustI386Impl.h index aa8d942b88..f0a87a36c3 100644 --- a/dtool/src/dtoolbase/atomicAdjustI386Impl.h +++ b/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); }; diff --git a/dtool/src/dtoolbase/atomicAdjustNsprImpl.I b/dtool/src/dtoolbase/atomicAdjustNsprImpl.I index e454c2d629..725f5dafe7 100644 --- a/dtool/src/dtoolbase/atomicAdjustNsprImpl.I +++ b/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; +} diff --git a/dtool/src/dtoolbase/atomicAdjustNsprImpl.cxx b/dtool/src/dtoolbase/atomicAdjustNsprImpl.cxx index a2072ffa75..2791690031 100644 --- a/dtool/src/dtoolbase/atomicAdjustNsprImpl.cxx +++ b/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 diff --git a/dtool/src/dtoolbase/atomicAdjustNsprImpl.h b/dtool/src/dtoolbase/atomicAdjustNsprImpl.h index 525a2b5138..56dacdc90f 100644 --- a/dtool/src/dtoolbase/atomicAdjustNsprImpl.h +++ b/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 +#include //////////////////////////////////////////////////////////////////// // 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 diff --git a/dtool/src/dtoolbase/atomicAdjustPosixImpl.I b/dtool/src/dtoolbase/atomicAdjustPosixImpl.I index 7b88da6baf..3355aa2748 100644 --- a/dtool/src/dtoolbase/atomicAdjustPosixImpl.I +++ b/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; +} diff --git a/dtool/src/dtoolbase/atomicAdjustPosixImpl.cxx b/dtool/src/dtoolbase/atomicAdjustPosixImpl.cxx index e884808195..36bf9a5c8d 100644 --- a/dtool/src/dtoolbase/atomicAdjustPosixImpl.cxx +++ b/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 diff --git a/dtool/src/dtoolbase/atomicAdjustPosixImpl.h b/dtool/src/dtoolbase/atomicAdjustPosixImpl.h index 21adb54437..07fe443529 100644 --- a/dtool/src/dtoolbase/atomicAdjustPosixImpl.h +++ b/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 diff --git a/dtool/src/dtoolbase/atomicAdjustWin32Impl.I b/dtool/src/dtoolbase/atomicAdjustWin32Impl.I index 2edccadcd8..86f39dfe5c 100644 --- a/dtool/src/dtoolbase/atomicAdjustWin32Impl.I +++ b/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! diff --git a/dtool/src/dtoolbase/atomicAdjustWin32Impl.cxx b/dtool/src/dtoolbase/atomicAdjustWin32Impl.cxx index 8052d8c384..a5c25bbdf1 100644 --- a/dtool/src/dtoolbase/atomicAdjustWin32Impl.cxx +++ b/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 diff --git a/dtool/src/dtoolbase/atomicAdjustWin32Impl.h b/dtool/src/dtoolbase/atomicAdjustWin32Impl.h index 73eb0dafb7..90ee6a9e90 100644 --- a/dtool/src/dtoolbase/atomicAdjustWin32Impl.h +++ b/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 -#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 diff --git a/dtool/src/dtoolbase/dtoolbase_composite1.cxx b/dtool/src/dtoolbase/dtoolbase_composite1.cxx index 863cdc8887..59c9905009 100644 --- a/dtool/src/dtoolbase/dtoolbase_composite1.cxx +++ b/dtool/src/dtoolbase/dtoolbase_composite1.cxx @@ -3,3 +3,4 @@ #include "atomicAdjustNsprImpl.cxx" #include "atomicAdjustPosixImpl.cxx" #include "atomicAdjustWin32Impl.cxx" +#include "dtoolbase.cxx" diff --git a/dtool/src/dtoolbase/dtoolbase_composite2.cxx b/dtool/src/dtoolbase/dtoolbase_composite2.cxx index c99a7d363f..cc43df3030 100644 --- a/dtool/src/dtoolbase/dtoolbase_composite2.cxx +++ b/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" diff --git a/dtool/src/dtoolbase/mutexDummyImpl.cxx b/dtool/src/dtoolbase/mutexDummyImpl.cxx index 1597988c21..d0deca9e9c 100644 --- a/dtool/src/dtoolbase/mutexDummyImpl.cxx +++ b/dtool/src/dtoolbase/mutexDummyImpl.cxx @@ -17,9 +17,4 @@ //////////////////////////////////////////////////////////////////// #include "selectThreadImpl.h" - -#ifdef THREAD_DUMMY_IMPL - #include "mutexDummyImpl.h" - -#endif // THREAD_DUMMY_IMPL diff --git a/dtool/src/dtoolbase/mutexDummyImpl.h b/dtool/src/dtoolbase/mutexDummyImpl.h index 9d651a8be9..4cfe125a8e 100644 --- a/dtool/src/dtoolbase/mutexDummyImpl.h +++ b/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 diff --git a/dtool/src/dtoolbase/mutexImpl.h b/dtool/src/dtoolbase/mutexImpl.h index 63c1ab455e..6b2f1624c5 100644 --- a/dtool/src/dtoolbase/mutexImpl.h +++ b/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 diff --git a/dtool/src/dtoolbase/mutexLinuxImpl.I b/dtool/src/dtoolbase/mutexLinuxImpl.I index a0b5a45ce1..99da4c85f0 100644 --- a/dtool/src/dtoolbase/mutexLinuxImpl.I +++ b/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; +} diff --git a/dtool/src/dtoolbase/mutexLinuxImpl.cxx b/dtool/src/dtoolbase/mutexLinuxImpl.cxx index 0436e9c69c..4b20d7ff87 100644 --- a/dtool/src/dtoolbase/mutexLinuxImpl.cxx +++ b/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 diff --git a/dtool/src/dtoolbase/mutexLinuxImpl.h b/dtool/src/dtoolbase/mutexLinuxImpl.h index 560bdd04e3..fee0e8a995 100644 --- a/dtool/src/dtoolbase/mutexLinuxImpl.h +++ b/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 diff --git a/dtool/src/dtoolbase/mutexNsprImpl.I b/dtool/src/dtoolbase/mutexNsprImpl.I index 5dda0c41b7..de3589af84 100644 --- a/dtool/src/dtoolbase/mutexNsprImpl.I +++ b/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); +} diff --git a/dtool/src/dtoolbase/mutexNsprImpl.cxx b/dtool/src/dtoolbase/mutexNsprImpl.cxx index 61b1d58aec..cbed5b2bcd 100644 --- a/dtool/src/dtoolbase/mutexNsprImpl.cxx +++ b/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 diff --git a/dtool/src/dtoolbase/mutexNsprImpl.h b/dtool/src/dtoolbase/mutexNsprImpl.h index cc9a018256..e6675a717b 100644 --- a/dtool/src/dtoolbase/mutexNsprImpl.h +++ b/dtool/src/dtoolbase/mutexNsprImpl.h @@ -22,11 +22,10 @@ #include "dtoolbase.h" #include "selectThreadImpl.h" -#ifdef THREAD_NSPR_IMPL +#ifdef HAVE_NSPR #include - -#undef MUTEX_DEFINES_TRYLOCK +#include //////////////////////////////////////////////////////////////////// // 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 diff --git a/dtool/src/dtoolbase/mutexPosixImpl.cxx b/dtool/src/dtoolbase/mutexPosixImpl.cxx index ce93f2160d..575097e232 100644 --- a/dtool/src/dtoolbase/mutexPosixImpl.cxx +++ b/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 diff --git a/dtool/src/dtoolbase/mutexPosixImpl.h b/dtool/src/dtoolbase/mutexPosixImpl.h index 9b062efe67..47d0ff3e22 100644 --- a/dtool/src/dtoolbase/mutexPosixImpl.h +++ b/dtool/src/dtoolbase/mutexPosixImpl.h @@ -22,13 +22,11 @@ #include "dtoolbase.h" #include "selectThreadImpl.h" -#ifdef THREAD_POSIX_IMPL +#ifdef HAVE_POSIX_THREADS #include #include -#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 diff --git a/dtool/src/dtoolbase/mutexSpinlockImpl.I b/dtool/src/dtoolbase/mutexSpinlockImpl.I new file mode 100644 index 0000000000..8a42b2c0a6 --- /dev/null +++ b/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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// 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); +} diff --git a/dtool/src/dtoolbase/mutexSpinlockImpl.cxx b/dtool/src/dtoolbase/mutexSpinlockImpl.cxx new file mode 100644 index 0000000000..df7cad4353 --- /dev/null +++ b/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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#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 diff --git a/dtool/src/dtoolbase/mutexSpinlockImpl.h b/dtool/src/dtoolbase/mutexSpinlockImpl.h new file mode 100644 index 0000000000..c8a70568d9 --- /dev/null +++ b/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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#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 diff --git a/dtool/src/dtoolbase/mutexWin32Impl.cxx b/dtool/src/dtoolbase/mutexWin32Impl.cxx index 18b7a856bc..e1b0deeae6 100644 --- a/dtool/src/dtoolbase/mutexWin32Impl.cxx +++ b/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 diff --git a/dtool/src/dtoolbase/mutexWin32Impl.h b/dtool/src/dtoolbase/mutexWin32Impl.h index 6d53be6661..164ac60885 100644 --- a/dtool/src/dtoolbase/mutexWin32Impl.h +++ b/dtool/src/dtoolbase/mutexWin32Impl.h @@ -22,12 +22,10 @@ #include "dtoolbase.h" #include "selectThreadImpl.h" -#ifdef THREAD_WIN32_IMPL +#ifdef WIN32_VC #include -#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 diff --git a/dtool/src/dtoolbase/selectThreadImpl.h b/dtool/src/dtoolbase/selectThreadImpl.h index fd1fad851e..629b768895 100644 --- a/dtool/src/dtoolbase/selectThreadImpl.h +++ b/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. diff --git a/panda/src/pipeline/Sources.pp b/panda/src/pipeline/Sources.pp index 3ff85771a6..6ccaa8a685 100644 --- a/panda/src/pipeline/Sources.pp +++ b/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 \ diff --git a/panda/src/pipeline/conditionVarDummyImpl.cxx b/panda/src/pipeline/conditionVarDummyImpl.cxx index bb7d7b1b9c..7c0a301eca 100644 --- a/panda/src/pipeline/conditionVarDummyImpl.cxx +++ b/panda/src/pipeline/conditionVarDummyImpl.cxx @@ -17,9 +17,4 @@ //////////////////////////////////////////////////////////////////// #include "selectThreadImpl.h" - -#ifdef THREAD_DUMMY_IMPL - #include "conditionVarDummyImpl.h" - -#endif // THREAD_DUMMY_IMPL diff --git a/panda/src/pipeline/conditionVarDummyImpl.h b/panda/src/pipeline/conditionVarDummyImpl.h index e04e89868e..f0ac838c7c 100644 --- a/panda/src/pipeline/conditionVarDummyImpl.h +++ b/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 diff --git a/panda/src/pipeline/conditionVarImpl.h b/panda/src/pipeline/conditionVarImpl.h index 9c35a530f5..c69f467be2 100644 --- a/panda/src/pipeline/conditionVarImpl.h +++ b/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" diff --git a/panda/src/pipeline/conditionVarLinuxImpl.cxx b/panda/src/pipeline/conditionVarLinuxImpl.cxx index 6c1a594aba..3168603897 100644 --- a/panda/src/pipeline/conditionVarLinuxImpl.cxx +++ b/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 diff --git a/panda/src/pipeline/conditionVarLinuxImpl.h b/panda/src/pipeline/conditionVarLinuxImpl.h index cbc3fcdbaa..955d579862 100644 --- a/panda/src/pipeline/conditionVarLinuxImpl.h +++ b/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 diff --git a/panda/src/pipeline/conditionVarNsprImpl.cxx b/panda/src/pipeline/conditionVarNsprImpl.cxx index e27e80298f..302144653f 100644 --- a/panda/src/pipeline/conditionVarNsprImpl.cxx +++ b/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 diff --git a/panda/src/pipeline/conditionVarNsprImpl.h b/panda/src/pipeline/conditionVarNsprImpl.h index 4fb77fabc8..c305af0f6e 100644 --- a/panda/src/pipeline/conditionVarNsprImpl.h +++ b/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 diff --git a/panda/src/pipeline/conditionVarPosixImpl.cxx b/panda/src/pipeline/conditionVarPosixImpl.cxx index 480900eedc..f2bcab32a0 100644 --- a/panda/src/pipeline/conditionVarPosixImpl.cxx +++ b/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 diff --git a/panda/src/pipeline/conditionVarPosixImpl.h b/panda/src/pipeline/conditionVarPosixImpl.h index 1451eedd8f..d177512b36 100644 --- a/panda/src/pipeline/conditionVarPosixImpl.h +++ b/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 diff --git a/panda/src/pipeline/conditionVarSpinlockImpl.I b/panda/src/pipeline/conditionVarSpinlockImpl.I new file mode 100644 index 0000000000..38033e1b39 --- /dev/null +++ b/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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// 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); +} diff --git a/panda/src/pipeline/conditionVarSpinlockImpl.cxx b/panda/src/pipeline/conditionVarSpinlockImpl.cxx new file mode 100644 index 0000000000..684bd46764 --- /dev/null +++ b/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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#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 diff --git a/panda/src/pipeline/conditionVarSpinlockImpl.h b/panda/src/pipeline/conditionVarSpinlockImpl.h new file mode 100644 index 0000000000..185519590a --- /dev/null +++ b/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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#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 diff --git a/panda/src/pipeline/conditionVarWin32Impl.cxx b/panda/src/pipeline/conditionVarWin32Impl.cxx index 236545ee2d..6430fbfb79 100644 --- a/panda/src/pipeline/conditionVarWin32Impl.cxx +++ b/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 diff --git a/panda/src/pipeline/conditionVarWin32Impl.h b/panda/src/pipeline/conditionVarWin32Impl.h index 533f3d6513..fe0fa13627 100644 --- a/panda/src/pipeline/conditionVarWin32Impl.h +++ b/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 diff --git a/panda/src/pipeline/mutexDebug.cxx b/panda/src/pipeline/mutexDebug.cxx index 9ce9d8a5a7..275db14a19 100755 --- a/panda/src/pipeline/mutexDebug.cxx +++ b/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()) { diff --git a/panda/src/pipeline/pipeline_composite1.cxx b/panda/src/pipeline/pipeline_composite1.cxx index c683ca889e..aafcb22f64 100644 --- a/panda/src/pipeline/pipeline_composite1.cxx +++ b/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" diff --git a/panda/src/pipeline/test_concurrency.cxx b/panda/src/pipeline/test_concurrency.cxx index 4a839fb2cb..e4ccbee79b 100755 --- a/panda/src/pipeline/test_concurrency.cxx +++ b/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); }