mutex_spinlock

This commit is contained in:
David Rose 2006-04-12 15:15:37 +00:00
parent 84550f0527
commit 7986aaa0c3
56 changed files with 722 additions and 177 deletions

View File

@ -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

View File

@ -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]

View File

@ -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]]

View File

@ -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 \

View File

@ -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.

View File

@ -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) {

View File

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

View File

@ -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

View File

@ -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;

View File

@ -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);
};

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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!

View File

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

View File

@ -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

View File

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

View File

@ -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"

View File

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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

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

View File

@ -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

View File

@ -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.

View File

@ -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 \

View File

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

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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

View File

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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

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

View File

@ -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

View File

@ -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()) {

View File

@ -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"

View File

@ -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);
}