diff --git a/dtool/Config.Win32.pp b/dtool/Config.Win32.pp index e3221d3252..64f4a5d82e 100644 --- a/dtool/Config.Win32.pp +++ b/dtool/Config.Win32.pp @@ -8,7 +8,7 @@ // What additional flags should we pass to interrogate? // NSPR versions prior to 4.4 used _declspec instead of __declspec. -#define SYSTEM_IGATE_FLAGS -longlong __int64 -D_X86_ -DWIN32_VC -D"_declspec(param)=" -D"__declspec(param)=" -D_near -D_far -D__near -D__far -D_WIN32 -D__stdcall +#define SYSTEM_IGATE_FLAGS -longlong __int64 -D_X86_ -DWIN32_VC -D"_declspec(param)=" -D"__declspec(param)=" -D_near -D_far -D__near -D__far -D_WIN32 -D__stdcall -Dvolatile= // Is the platform big-endian (like an SGI workstation) or // little-endian (like a PC)? Define this to the empty string to diff --git a/dtool/src/dtoolbase/atomicAdjust.h b/dtool/src/dtoolbase/atomicAdjust.h index ac02b76233..19cf1999ed 100644 --- a/dtool/src/dtoolbase/atomicAdjust.h +++ b/dtool/src/dtoolbase/atomicAdjust.h @@ -27,7 +27,7 @@ #include "atomicAdjustDummyImpl.h" typedef AtomicAdjustDummyImpl AtomicAdjust; -#elif defined(__i386__) +#elif defined(__i386__) || defined(_M_IX86) // For an i386 architecture, we'll always use the i386 implementation. // It should be safe for any OS, and it might be a bit faster than // any OS-provided calls. diff --git a/dtool/src/dtoolbase/atomicAdjustI386Impl.I b/dtool/src/dtoolbase/atomicAdjustI386Impl.I index ddfa22f510..0b283afbc5 100644 --- a/dtool/src/dtoolbase/atomicAdjustI386Impl.I +++ b/dtool/src/dtoolbase/atomicAdjustI386Impl.I @@ -24,7 +24,15 @@ //////////////////////////////////////////////////////////////////// INLINE void AtomicAdjustI386Impl:: inc(volatile PN_int32 &var) { -#ifndef __EDG__ +#ifdef _M_IX86 + // Windows case + volatile PN_int32 *var_ptr = &var; + __asm { + mov edx, var_ptr; + lock inc dword ptr [edx]; + } +#elif !defined(__EDG__) + // GCC case __asm__ __volatile__("lock; incl %0" :"=m" (var) :"m" (&var)); @@ -41,7 +49,16 @@ inc(volatile PN_int32 &var) { INLINE bool AtomicAdjustI386Impl:: dec(volatile PN_int32 &var) { unsigned char c; -#ifndef __EDG__ +#ifdef _M_IX86 + // Windows case + volatile PN_int32 *var_ptr = &var; + __asm { + mov edx, var_ptr; + lock dec dword ptr [edx]; + sete c; + } +#elif !defined(__EDG__) + // GCC case __asm__ __volatile__("lock; decl %0; sete %1" :"=m" (var), "=qm" (c) :"m" (&var) : "memory"); @@ -126,7 +143,18 @@ INLINE PN_int32 AtomicAdjustI386Impl:: compare_and_exchange(volatile PN_int32 &mem, PN_int32 old_value, PN_int32 new_value) { PN_int32 prev; -#ifndef __EDG__ +#ifdef _M_IX86 + // Windows case + volatile PN_int32 *mem_ptr = &mem; + __asm { + mov edx, mem_ptr; + mov ecx, new_value; + mov eax, old_value; + lock cmpxchg dword ptr [edx], ecx; + mov prev, eax; + } +#elif !defined(__EDG__) + // GCC case __asm__ __volatile__("lock; cmpxchgl %1,%2" : "=a"(prev) : "r"(new_value), "m"(mem), "0"(old_value) @@ -146,7 +174,18 @@ INLINE void *AtomicAdjustI386Impl:: compare_and_exchange_ptr(void * volatile &mem, void *old_value, void *new_value) { void *prev; -#ifndef __EDG__ +#ifdef _M_IX86 + // Windows case + void * volatile *mem_ptr = &mem; + __asm { + mov edx, mem_ptr; + mov ecx, new_value; + mov eax, old_value; + lock cmpxchg dword ptr [edx], ecx; + mov prev, eax; + } +#elif !defined(__EDG__) + // GCC case __asm__ __volatile__("lock; cmpxchgl %1,%2" : "=a"(prev) : "r"(new_value), "m"(mem), "0"(old_value) diff --git a/dtool/src/dtoolbase/atomicAdjustI386Impl.h b/dtool/src/dtoolbase/atomicAdjustI386Impl.h index 7df65a2723..aa8d942b88 100644 --- a/dtool/src/dtoolbase/atomicAdjustI386Impl.h +++ b/dtool/src/dtoolbase/atomicAdjustI386Impl.h @@ -22,7 +22,7 @@ #include "dtoolbase.h" #include "selectThreadImpl.h" -#if defined(__i386__) +#if defined(__i386__) || defined(_M_IX86) #include "numeric_types.h" diff --git a/dtool/src/dtoolbase/atomicAdjustPosixImpl.I b/dtool/src/dtoolbase/atomicAdjustPosixImpl.I index 2dcd3c883b..bd1c563088 100644 --- a/dtool/src/dtoolbase/atomicAdjustPosixImpl.I +++ b/dtool/src/dtoolbase/atomicAdjustPosixImpl.I @@ -75,3 +75,35 @@ get(const PN_int32 &var) { pthread_mutex_unlock(&_mutex); return orig_value; } + +//////////////////////////////////////////////////////////////////// +// Function: AtomicAdjustPosixImpl::set_ptr +// Access: Public, Static +// Description: Atomically changes the indicated variable and +// returns the original value. +//////////////////////////////////////////////////////////////////// +INLINE void *AtomicAdjustPosixImpl:: +set_ptr(void *&var, void *new_value) { + pthread_mutex_lock(&_mutex); + void *orig_value = var; + var = new_value; + pthread_mutex_unlock(&_mutex); + return orig_value; +} + +//////////////////////////////////////////////////////////////////// +// Function: AtomicAdjustPosixImpl::get_ptr +// Access: Public, Static +// Description: Atomically retrieves the snapshot value of the +// indicated variable. This is the only guaranteed safe +// way to retrieve the value that other threads might be +// asynchronously setting, incrementing, or decrementing +// (via other AtomicAjust methods). +//////////////////////////////////////////////////////////////////// +INLINE void *AtomicAdjustPosixImpl:: +get_ptr(const void *&var) { + pthread_mutex_lock(&_mutex); + void *orig_value = var; + pthread_mutex_unlock(&_mutex); + return orig_value; +} diff --git a/dtool/src/dtoolbase/atomicAdjustPosixImpl.h b/dtool/src/dtoolbase/atomicAdjustPosixImpl.h index b79dab296c..21adb54437 100644 --- a/dtool/src/dtoolbase/atomicAdjustPosixImpl.h +++ b/dtool/src/dtoolbase/atomicAdjustPosixImpl.h @@ -39,6 +39,9 @@ public: INLINE static PN_int32 set(PN_int32 &var, PN_int32 new_value); INLINE static PN_int32 get(const PN_int32 &var); + INLINE static void *set_ptr(void *&var, void *new_value); + INLINE static void *get_ptr(void * const &var); + private: static pthread_mutex_t _mutex; }; diff --git a/dtool/src/dtoolbase/atomicAdjustWin32Impl.I b/dtool/src/dtoolbase/atomicAdjustWin32Impl.I index 543446d007..2edccadcd8 100644 --- a/dtool/src/dtoolbase/atomicAdjustWin32Impl.I +++ b/dtool/src/dtoolbase/atomicAdjustWin32Impl.I @@ -90,3 +90,45 @@ INLINE void *AtomicAdjustWin32Impl:: get_ptr(void * const &var) { return var; } + +//////////////////////////////////////////////////////////////////// +// Function: AtomicAdjustWin32Impl::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 AtomicAdjustWin32Impl:: +compare_and_exchange(volatile 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); +} + +//////////////////////////////////////////////////////////////////// +// Function: AtomicAdjustWin32Impl::compare_and_exchange_ptr +// Access: Public, Static +// Description: Atomic compare and exchange. +// +// As above, but works on pointers instead of integers. +//////////////////////////////////////////////////////////////////// +INLINE void *AtomicAdjustWin32Impl:: +compare_and_exchange_ptr(void * volatile &mem, void *old_value, + void *new_value) { + // Note that the AtomicAdjust parameter order is different from + // Windows convention! + return InterlockedCompareExchangePointer(&mem, new_value, old_value); +} diff --git a/dtool/src/dtoolbase/atomicAdjustWin32Impl.h b/dtool/src/dtoolbase/atomicAdjustWin32Impl.h index 24f1850641..73eb0dafb7 100644 --- a/dtool/src/dtoolbase/atomicAdjustWin32Impl.h +++ b/dtool/src/dtoolbase/atomicAdjustWin32Impl.h @@ -28,6 +28,9 @@ #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 @@ -42,6 +45,14 @@ public: INLINE static void *set_ptr(void *&var, void *new_value); INLINE static void *get_ptr(void * const &var); + + INLINE static PN_int32 compare_and_exchange(volatile PN_int32 &mem, + PN_int32 old_value, + PN_int32 new_value); + + INLINE static void *compare_and_exchange_ptr(void * volatile &mem, + void *old_value, + void *new_value); }; #include "atomicAdjustWin32Impl.I" diff --git a/dtool/src/interrogate/interrogate.cxx b/dtool/src/interrogate/interrogate.cxx index 848ef9ba6d..7e9ee70cfe 100644 --- a/dtool/src/interrogate/interrogate.cxx +++ b/dtool/src/interrogate/interrogate.cxx @@ -22,6 +22,7 @@ #include "interrogateDatabase.h" #include "cppGlobals.h" #include "pnotify.h" +#include "atomicAdjust.h" #include // If our system getopt() doesn't come with getopt_long_only(), then use