From e70980b2aacbc758a0cd1e2246633278f7c505ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Mon, 31 Aug 2009 17:05:51 +0200 Subject: Refactoring qatomic_windows.h Consolidated Interlocked* declarations and API implementation through macro hackery, (hopefully) for improved readability and maintainability. Fixes anti-aliasing warnings with MinGW in qatomic_windows.h. Gcc builds now use inline assembly for atomic operations, instead of relying on Interlocked* functions which aren't consistently declared across implementations (mingw32, mingw-w64, wine... others?). Drops support for VC 6 and MetroWerks. Reviewed-by: Thiago Macieira --- src/corelib/arch/arch.pri | 3 + src/corelib/arch/qatomic_windows.h | 558 ++++++++++------------- src/corelib/thread/qbasicatomic.h | 15 + tests/auto/qatomicint/tst_qatomicint.cpp | 44 ++ tests/auto/qatomicpointer/tst_qatomicpointer.cpp | 48 ++ 5 files changed, 345 insertions(+), 323 deletions(-) diff --git a/src/corelib/arch/arch.pri b/src/corelib/arch/arch.pri index a25027b..57bc80a 100644 --- a/src/corelib/arch/arch.pri +++ b/src/corelib/arch/arch.pri @@ -1,6 +1,9 @@ win32:HEADERS += arch/qatomic_windows.h \ arch/qatomic_generic.h +win32-g++*:HEADERS += arch/qatomic_i386.h \ + arch/qatomic_x86_64.h + mac:HEADERS += arch/qatomic_macosx.h \ arch/qatomic_generic.h diff --git a/src/corelib/arch/qatomic_windows.h b/src/corelib/arch/qatomic_windows.h index a826bd3..50dedc1 100644 --- a/src/corelib/arch/qatomic_windows.h +++ b/src/corelib/arch/qatomic_windows.h @@ -42,6 +42,195 @@ #ifndef QATOMIC_WINDOWS_H #define QATOMIC_WINDOWS_H +#ifndef Q_CC_MSVC + +// Mingw and other GCC platforms get inline assembly + +# ifdef __i386__ +# include "QtCore/qatomic_i386.h" +# else +# include "QtCore/qatomic_x86_64.h" +# endif + +#else // Q_CC_MSVC + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef Q_OS_WINCE + +// use compiler intrinsics for all atomic functions +# define QT_INTERLOCKED_PREFIX _ +# define QT_INTERLOCKED_PROTOTYPE __cdecl +# define QT_INTERLOCKED_DECLARE_PROTOTYPES +# define QT_INTERLOCKED_INTRINSIC + +#else // Q_OS_WINCE + +# if _WIN32_WCE < 0x600 && defined(_X86_) +// For X86 Windows CE, include winbase.h to catch inline functions which +// overwrite the regular definitions inside of coredll.dll. +// Though one could use the original version of Increment/Decrement, others are +// not exported at all. +# include + +// It's safer to remove the volatile and let the compiler add it as needed. +# define QT_INTERLOCKED_NO_VOLATILE + +# else // _WIN32_WCE >= 0x600 || _X86_ + +# define QT_INTERLOCKED_PROTOTYPE __cdecl +# define QT_INTERLOCKED_DECLARE_PROTOTYPES + +# if _WIN32_WCE >= 0x600 && defined(_X86_) +# define QT_INTERLOCKED_PREFIX _ +# define QT_INTERLOCKED_INTRINSIC +# else +# define QT_INTERLOCKED_NO_VOLATILE +# endif + +# endif // _WIN32_WCE >= 0x600 || _X86_ + +#endif // Q_OS_WINCE + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Prototype declaration + +#define QT_INTERLOCKED_CONCAT_I(prefix, suffix) \ + prefix ## suffix +#define QT_INTERLOCKED_CONCAT(prefix, suffix) \ + QT_INTERLOCKED_CONCAT_I(prefix, suffix) + +// MSVC intrinsics prefix function names with an underscore +#define QT_INTERLOCKED_FUNCTION(name) \ + QT_INTERLOCKED_CONCAT(QT_INTERLOCKED_PREFIX, name) + +#ifdef QT_INTERLOCKED_NO_VOLATILE +# define QT_INTERLOCKED_VOLATILE +# define QT_INTERLOCKED_REMOVE_VOLATILE(a) qt_interlocked_remove_volatile(a) +#else +# define QT_INTERLOCKED_VOLATILE volatile +# define QT_INTERLOCKED_REMOVE_VOLATILE(a) a +#endif + +#ifndef QT_INTERLOCKED_PREFIX +#define QT_INTERLOCKED_PREFIX +#endif + +#ifndef QT_INTERLOCKED_PROTOTYPE +#define QT_INTERLOCKED_PROTOTYPE +#endif + +#ifdef QT_INTERLOCKED_DECLARE_PROTOTYPES +#undef QT_INTERLOCKED_DECLARE_PROTOTYPES + +extern "C" { + + long QT_INTERLOCKED_PROTOTYPE QT_INTERLOCKED_FUNCTION( InterlockedIncrement )(long QT_INTERLOCKED_VOLATILE *); + long QT_INTERLOCKED_PROTOTYPE QT_INTERLOCKED_FUNCTION( InterlockedDecrement )(long QT_INTERLOCKED_VOLATILE *); + long QT_INTERLOCKED_PROTOTYPE QT_INTERLOCKED_FUNCTION( InterlockedCompareExchange )(long QT_INTERLOCKED_VOLATILE *, long, long); + long QT_INTERLOCKED_PROTOTYPE QT_INTERLOCKED_FUNCTION( InterlockedExchange )(long QT_INTERLOCKED_VOLATILE *, long); + long QT_INTERLOCKED_PROTOTYPE QT_INTERLOCKED_FUNCTION( InterlockedExchangeAdd )(long QT_INTERLOCKED_VOLATILE *, long); + +# if !defined(__i386__) && !defined(_M_IX86) + long QT_INTERLOCKED_FUNCTION( InterlockedCompareExchangePointer )(void * QT_INTERLOCKED_VOLATILE *, void *, void *); + long QT_INTERLOCKED_FUNCTION( InterlockedExchangePointer )(void * QT_INTERLOCKED_VOLATILE *, void *); + __int64 QT_INTERLOCKED_FUNCTION( InterlockedExchangeAdd64 )(__int64 QT_INTERLOCKED_VOLATILE *, long); +# endif + +} + +#endif // QT_INTERLOCKED_DECLARE_PROTOTYPES + +#undef QT_INTERLOCKED_PROTOTYPE +#undef QT_INTERLOCKED_VOLATILE + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifdef QT_INTERLOCKED_INTRINSIC +#undef QT_INTERLOCKED_INTRINSIC + +# pragma intrinsic (_InterlockedIncrement) +# pragma intrinsic (_InterlockedDecrement) +# pragma intrinsic (_InterlockedExchange) +# pragma intrinsic (_InterlockedCompareExchange) +# pragma intrinsic (_InterlockedExchangeAdd) + +# ifndef _M_IX86 +# pragma intrinsic (_InterlockedCompareExchangePointer) +# pragma intrinsic (_InterlockedExchangePointer) +# pragma intrinsic (_InterlockedExchangeAdd64) +# endif + +#endif // QT_INTERLOCKED_INTRINSIC + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interlocked* replacement macros + +#define QT_INTERLOCKED_INCREMENT(value) \ + QT_INTERLOCKED_FUNCTION(InterlockedIncrement)( \ + QT_INTERLOCKED_REMOVE_VOLATILE( value ) ) + +#define QT_INTERLOCKED_DECREMENT(value) \ + QT_INTERLOCKED_FUNCTION(InterlockedDecrement)( \ + QT_INTERLOCKED_REMOVE_VOLATILE( value ) ) + +#define QT_INTERLOCKED_COMPARE_EXCHANGE(value, newValue, expectedValue) \ + QT_INTERLOCKED_FUNCTION(InterlockedCompareExchange)( \ + QT_INTERLOCKED_REMOVE_VOLATILE( value ), \ + newValue, \ + expectedValue ) + +#define QT_INTERLOCKED_EXCHANGE(value, newValue) \ + QT_INTERLOCKED_FUNCTION(InterlockedExchange)( \ + QT_INTERLOCKED_REMOVE_VOLATILE( value ), \ + newValue ) + +#define QT_INTERLOCKED_EXCHANGE_ADD(value, valueToAdd) \ + QT_INTERLOCKED_FUNCTION(InterlockedExchangeAdd)( \ + QT_INTERLOCKED_REMOVE_VOLATILE( value ), \ + valueToAdd ) + +#if defined(__i386__) || defined(_M_IX86) + +# define QT_INTERLOCKED_COMPARE_EXCHANGE_POINTER(value, newValue, expectedValue) \ + reinterpret_cast( \ + QT_INTERLOCKED_FUNCTION(InterlockedCompareExchange)( \ + QT_INTERLOCKED_REMOVE_VOLATILE( value ## _integral ), \ + (long)( newValue ), \ + (long)( expectedValue ) )) + +# define QT_INTERLOCKED_EXCHANGE_POINTER(value, newValue) \ + QT_INTERLOCKED_FUNCTION(InterlockedExchange)( \ + QT_INTERLOCKED_REMOVE_VOLATILE( value ## _integral ), \ + (quintptr)( newValue ) ) + +# define QT_INTERLOCKED_EXCHANGE_ADD_POINTER(value, valueToAdd) \ + QT_INTERLOCKED_FUNCTION(InterlockedExchangeAdd)( \ + QT_INTERLOCKED_REMOVE_VOLATILE( value ## _integral ), \ + valueToAdd ) + +#else // !defined(__i386__) && !defined(_M_IX86) + +# define QT_INTERLOCKED_COMPARE_EXCHANGE_POINTER(value, newValue, expectedValue) \ + QT_INTERLOCKED_FUNCTION(InterlockedCompareExchangePointer)( \ + QT_INTERLOCKED_REMOVE_VOLATILE( value ), \ + newValue, \ + expectedValue ) + +# define QT_INTERLOCKED_EXCHANGE_POINTER(value, newValue) \ + QT_INTERLOCKED_FUNCTION(InterlockedExchangePointer)( \ + QT_INTERLOCKED_REMOVE_VOLATILE( value ), \ + newValue ) + +# define QT_INTERLOCKED_EXCHANGE_ADD_POINTER(value, valueToAdd) \ + QT_INTERLOCKED_FUNCTION(InterlockedExchangeAdd64)( \ + QT_INTERLOCKED_REMOVE_VOLATILE( value ## _integral ), \ + valueToAdd ) + +#endif // !defined(__i386__) && !defined(_M_IX86) + +//////////////////////////////////////////////////////////////////////////////////////////////////// + QT_BEGIN_HEADER QT_BEGIN_NAMESPACE @@ -107,369 +296,68 @@ template Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddWaitFree() { return true; } -#if defined(Q_CC_MSVC) || defined(Q_CC_MWERKS) - -// MSVC++ 6.0 doesn't generate correct code when optimizations are turned on! -#if _MSC_VER < 1300 && defined (_M_IX86) - -inline bool QBasicAtomicInt::ref() -{ - volatile int *pointer = &_q_value; - unsigned char retVal; - __asm { - mov ECX,pointer - lock inc DWORD ptr[ECX] - setne retVal - } - return retVal != 0; -} - -inline bool QBasicAtomicInt::deref() -{ - volatile int *pointer = &_q_value; - unsigned char retVal; - __asm { - mov ECX,pointer - lock dec DWORD ptr[ECX] - setne retVal - } - return retVal != 0; -} - -inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) -{ - volatile int *pointer = &_q_value; - __asm { - mov EDX,pointer - mov EAX,expectedValue - mov ECX,newValue - lock cmpxchg dword ptr[EDX],ECX - mov newValue,EAX - } - return newValue == expectedValue; -} - - -inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) -{ - volatile int *pointer = &_q_value; - __asm { - mov EDX,pointer - mov ECX,newValue - lock xchg dword ptr[EDX],ECX - mov newValue,ECX - } - return newValue; -} - - -inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) -{ - volatile int *pointer = &_q_value; - __asm { - mov EDX,pointer - mov ECX,valueToAdd - lock xadd dword ptr[EDX],ECX - mov valueToAdd,ECX - } - return valueToAdd; -} +//////////////////////////////////////////////////////////////////////////////////////////////////// -template -Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) -{ - volatile void *pointer = &_q_value; - __asm { - mov EDX,pointer - mov EAX,expectedValue - mov ECX,newValue - lock cmpxchg dword ptr[EDX],ECX - mov newValue,EAX - } - return newValue == expectedValue; -} - -template -Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreOrdered(T *newValue) -{ - volatile void *pointer = &_q_value; - __asm { - mov EDX,pointer - mov ECX,newValue - lock xchg dword ptr[EDX],ECX - mov newValue,ECX - } - return reinterpret_cast(newValue); -} - -template -Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) +#ifdef QT_INTERLOCKED_NO_VOLATILE +template +Q_INLINE_TEMPLATE T *qt_interlocked_remove_volatile(T volatile *t) { - volatile void *pointer = &_q_value; - valueToAdd *= sizeof(T); - __asm { - mov EDX,pointer - mov ECX,valueToAdd - lock xadd dword ptr[EDX],ECX - mov pointer,ECX - } - return reinterpret_cast(const_cast(pointer)); + return const_cast(t); } +#endif // !QT_INTERLOCKED_NO_VOLATILE -#else - -#if !defined(Q_OS_WINCE) && !defined(Q_CC_MWERKS) -// use compiler intrinsics for all atomic functions -//those functions need to be define in the global namespace -QT_END_NAMESPACE - -extern "C" { - long __cdecl _InterlockedIncrement(volatile long *); - long __cdecl _InterlockedDecrement(volatile long *); - long __cdecl _InterlockedExchange(volatile long *, long); - long __cdecl _InterlockedCompareExchange(volatile long *, long, long); - long __cdecl _InterlockedExchangeAdd(volatile long *, long); -} -# pragma intrinsic (_InterlockedIncrement) -# pragma intrinsic (_InterlockedDecrement) -# pragma intrinsic (_InterlockedExchange) -# pragma intrinsic (_InterlockedCompareExchange) -# pragma intrinsic (_InterlockedExchangeAdd) - -# ifndef _M_IX86 -extern "C" { - void *_InterlockedCompareExchangePointer(void * volatile *, void *, void *); - void *_InterlockedExchangePointer(void * volatile *, void *); - __int64 _InterlockedExchangeAdd64(__int64 volatile * Addend, __int64 Value); -} -# pragma intrinsic (_InterlockedCompareExchangePointer) -# pragma intrinsic (_InterlockedExchangePointer) -# pragma intrinsic (_InterlockedExchangeAdd64) -# define _InterlockedExchangeAddPointer(a,b) \ - _InterlockedExchangeAdd64(reinterpret_cast(a), __int64(b)) -# else -# define _InterlockedCompareExchangePointer(a,b,c) \ - _InterlockedCompareExchange(reinterpret_cast(a), long(b), long(c)) -# define _InterlockedExchangePointer(a, b) \ - _InterlockedExchange(reinterpret_cast(a), long(b)) -# define _InterlockedExchangeAddPointer(a,b) \ - _InterlockedExchangeAdd(reinterpret_cast(a), long(b)) -# endif - -QT_BEGIN_NAMESPACE +//////////////////////////////////////////////////////////////////////////////////////////////////// inline bool QBasicAtomicInt::ref() { - return _InterlockedIncrement(reinterpret_cast(&_q_value)) != 0; + return QT_INTERLOCKED_INCREMENT(&_q_value) != 0; } inline bool QBasicAtomicInt::deref() { - return _InterlockedDecrement(reinterpret_cast(&_q_value)) != 0; + return QT_INTERLOCKED_DECREMENT(&_q_value) != 0; } inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) { - return _InterlockedCompareExchange(reinterpret_cast(&_q_value), newValue, expectedValue) == expectedValue; + return QT_INTERLOCKED_COMPARE_EXCHANGE(&_q_value, newValue, expectedValue) + == expectedValue; } inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) { - return _InterlockedExchange(reinterpret_cast(&_q_value), newValue); + return QT_INTERLOCKED_EXCHANGE(&_q_value, newValue); } inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) { - return _InterlockedExchangeAdd(reinterpret_cast(&_q_value), valueToAdd); + return QT_INTERLOCKED_EXCHANGE_ADD(&_q_value, valueToAdd); } -#if defined(Q_CC_MSVC) -#pragma warning( push ) -#pragma warning( disable : 4311 ) // ignoring the warning from /Wp64 -#endif +//////////////////////////////////////////////////////////////////////////////////////////////////// template Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) { - return (_InterlockedCompareExchangePointer(reinterpret_cast(&_q_value), - newValue, expectedValue) == -#ifndef _M_IX86 - (void *) -#else - (long) -#endif - (expectedValue)); -} - -#if defined(Q_CC_MSVC) -#pragma warning( pop ) -#endif - -template -Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreOrdered(T *newValue) -{ - return reinterpret_cast(_InterlockedExchangePointer(reinterpret_cast(&_q_value), newValue)); + return QT_INTERLOCKED_COMPARE_EXCHANGE_POINTER(&_q_value, newValue, expectedValue) + == expectedValue; } template -Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) -{ - return reinterpret_cast(_InterlockedExchangeAddPointer(reinterpret_cast(&_q_value), valueToAdd * sizeof(T))); -} - -#else // Q_OS_WINCE - -#if (_WIN32_WCE < 0x600 && defined(_X86_)) || defined(Q_CC_MWERKS) -// For X86 Windows CE build we need to include winbase.h to be able -// to catch the inline functions which overwrite the regular -// definitions inside of coredll.dll. Though one could use the -// original version of Increment/Decrement, the others are not -// exported at all. -#include -#else -#if _WIN32_WCE >= 0x600 || defined(Q_CC_MWERKS) -#define Q_ARGUMENT_TYPE volatile -# if defined(_X86_) -# define InterlockedIncrement _InterlockedIncrement -# define InterlockedDecrement _InterlockedDecrement -# define InterlockedExchange _InterlockedExchange -# define InterlockedCompareExchange _InterlockedCompareExchange -# define InterlockedExchangeAdd _InterlockedExchangeAdd -# endif -#else -#define Q_ARGUMENT_TYPE -#endif - -QT_END_NAMESPACE - -extern "C" { -long __cdecl InterlockedIncrement(long Q_ARGUMENT_TYPE * lpAddend); -long __cdecl InterlockedDecrement(long Q_ARGUMENT_TYPE * lpAddend); -long __cdecl InterlockedExchange(long Q_ARGUMENT_TYPE * Target, long Value); -long __cdecl InterlockedCompareExchange(long Q_ARGUMENT_TYPE * Destination, long Exchange, long Comperand); -long __cdecl InterlockedExchangeAdd(long Q_ARGUMENT_TYPE * Addend, long Value); -} - -#if _WIN32_WCE >= 0x600 && defined(_X86_) -# pragma intrinsic (_InterlockedIncrement) -# pragma intrinsic (_InterlockedDecrement) -# pragma intrinsic (_InterlockedExchange) -# pragma intrinsic (_InterlockedCompareExchange) -# pragma intrinsic (_InterlockedExchangeAdd) -#endif - -QT_BEGIN_NAMESPACE - -#endif - - -inline bool QBasicAtomicInt::ref() -{ - return InterlockedIncrement((long*)(&_q_value)) != 0; -} - -inline bool QBasicAtomicInt::deref() -{ - return InterlockedDecrement((long*)(&_q_value)) != 0; -} - -inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) -{ - return InterlockedCompareExchange((long*)(&_q_value), newValue, expectedValue) == expectedValue; -} - -inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) -{ - return InterlockedExchange((long*)(&_q_value), newValue); -} - -inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) -{ - return InterlockedExchangeAdd((long*)(&_q_value), valueToAdd); -} - -template -Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) -{ - return (InterlockedCompareExchange((long*)(&_q_value), - (long)newValue, (long)expectedValue) == - (long)(expectedValue)); -} - -template -Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreOrdered(T *newValue) +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreOrdered(T* newValue) { - return reinterpret_cast(InterlockedExchange((long*)(&_q_value), (long)newValue)); + return reinterpret_cast( + QT_INTERLOCKED_EXCHANGE_POINTER(&_q_value, newValue)); } template Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) { - return reinterpret_cast(InterlockedExchangeAdd((long*)(&_q_value), valueToAdd * sizeof(T))); -} - -#endif //Q_OS_WINCE - -#endif // _MSC_VER ... - -#else - -// __INTERLOCKED_DECLARED is defined in MinGW's winbase.h. Simply, preferrably we use -// MinGW's definition, such that we pick up variations in the headers. -#ifndef __INTERLOCKED_DECLARED -#define __INTERLOCKED_DECLARED -QT_END_NAMESPACE - -extern "C" { - __declspec(dllimport) long __stdcall InterlockedCompareExchange(long *, long, long); - __declspec(dllimport) long __stdcall InterlockedIncrement(long *); - __declspec(dllimport) long __stdcall InterlockedDecrement(long *); - __declspec(dllimport) long __stdcall InterlockedExchange(long *, long); - __declspec(dllimport) long __stdcall InterlockedExchangeAdd(long *, long); -} - -QT_BEGIN_NAMESPACE -#endif - -inline bool QBasicAtomicInt::ref() -{ - return InterlockedIncrement(reinterpret_cast(const_cast(&_q_value))) != 0; -} - -inline bool QBasicAtomicInt::deref() -{ - return InterlockedDecrement(reinterpret_cast(const_cast(&_q_value))) != 0; + return reinterpret_cast( + QT_INTERLOCKED_EXCHANGE_ADD_POINTER(&_q_value, valueToAdd * sizeof(T))); } -inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) -{ - return InterlockedCompareExchange(reinterpret_cast(const_cast(&_q_value)), newValue, expectedValue) == expectedValue; -} - -inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) -{ return InterlockedExchange(reinterpret_cast(const_cast(&_q_value)), newValue); } - -inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) -{ - return InterlockedExchangeAdd(reinterpret_cast(const_cast(&_q_value)), valueToAdd); -} - -template -Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T* newValue) -{ return InterlockedCompareExchange(reinterpret_cast(const_cast(&_q_value)), - reinterpret_cast(newValue), - reinterpret_cast(expectedValue)) == reinterpret_cast(expectedValue); } - -template -Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreOrdered(T* newValue) -{ return reinterpret_cast(InterlockedExchange(reinterpret_cast(const_cast(&_q_value)), - reinterpret_cast(newValue))); } - -template -Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) -{ return reinterpret_cast(InterlockedExchangeAdd(reinterpret_cast(const_cast(&_q_value)), valueToAdd * sizeof(T))); } - -#endif // Q_CC_GNU +//////////////////////////////////////////////////////////////////////////////////////////////////// inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) { @@ -516,6 +404,8 @@ inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) return fetchAndAddOrdered(valueToAdd); } +//////////////////////////////////////////////////////////////////////////////////////////////////// + template Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue) { @@ -570,8 +460,30 @@ Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelease(qptrdiff valueTo return fetchAndAddOrdered(valueToAdd); } +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Cleanup + +#undef QT_INTERLOCKED_CONCAT_I +#undef QT_INTERLOCKED_CONCAT +#undef QT_INTERLOCKED_FUNCTION +#undef QT_INTERLOCKED_PREFIX + +#undef QT_INTERLOCKED_NO_VOLATILE +#undef QT_INTERLOCKED_REMOVE_VOLATILE + +#undef QT_INTERLOCKED_INCREMENT +#undef QT_INTERLOCKED_DECREMENT +#undef QT_INTERLOCKED_COMPARE_EXCHANGE +#undef QT_INTERLOCKED_EXCHANGE +#undef QT_INTERLOCKED_EXCHANGE_ADD +#undef QT_INTERLOCKED_COMPARE_EXCHANGE_POINTER +#undef QT_INTERLOCKED_EXCHANGE_POINTER +#undef QT_INTERLOCKED_EXCHANGE_ADD_POINTER + QT_END_NAMESPACE QT_END_HEADER +#endif // Q_CC_MSVC + #endif // QATOMIC_WINDOWS_H diff --git a/src/corelib/thread/qbasicatomic.h b/src/corelib/thread/qbasicatomic.h index e96b4d2..629fb3d 100644 --- a/src/corelib/thread/qbasicatomic.h +++ b/src/corelib/thread/qbasicatomic.h @@ -56,7 +56,13 @@ public: #ifdef QT_ARCH_PARISC int _q_lock[4]; #endif +#if defined(QT_ARCH_WINDOWS) || defined(QT_ARCH_WINDOWSCE) + union { // needed for Q_BASIC_ATOMIC_INITIALIZER + volatile long _q_value; + }; +#else volatile int _q_value; +#endif // Non-atomic API inline bool operator==(int value) const @@ -128,7 +134,14 @@ public: #ifdef QT_ARCH_PARISC int _q_lock[4]; #endif +#if defined(QT_ARCH_WINDOWS) || defined(QT_ARCH_WINDOWSCE) + union { + T * volatile _q_value; + long volatile _q_value_integral; + }; +#else T * volatile _q_value; +#endif // Non-atomic API inline bool operator==(T *value) const @@ -194,6 +207,8 @@ public: #ifdef QT_ARCH_PARISC # define Q_BASIC_ATOMIC_INITIALIZER(a) {{-1,-1,-1,-1},(a)} +#elif defined(QT_ARCH_WINDOWS) || defined(QT_ARCH_WINDOWSCE) +# define Q_BASIC_ATOMIC_INITIALIZER(a) { {(a)} } #else # define Q_BASIC_ATOMIC_INITIALIZER(a) { (a) } #endif diff --git a/tests/auto/qatomicint/tst_qatomicint.cpp b/tests/auto/qatomicint/tst_qatomicint.cpp index c3ea31d..5fde633 100644 --- a/tests/auto/qatomicint/tst_qatomicint.cpp +++ b/tests/auto/qatomicint/tst_qatomicint.cpp @@ -59,6 +59,8 @@ public: ~tst_QAtomicInt(); private slots: + void warningFree(); + // QAtomicInt members void constructor_data(); void constructor(); @@ -101,6 +103,9 @@ private slots: void testAndSet_loop(); void fetchAndAdd_loop(); void fetchAndAdd_threadedLoop(); + +private: + static void warningFreeHelper(); }; tst_QAtomicInt::tst_QAtomicInt() @@ -109,6 +114,45 @@ tst_QAtomicInt::tst_QAtomicInt() tst_QAtomicInt::~tst_QAtomicInt() { } +void tst_QAtomicInt::warningFreeHelper() +{ + Q_ASSERT(false); + // The code below is bogus, and shouldn't be run. We're looking for warnings, only. + + QBasicAtomicInt i = Q_BASIC_ATOMIC_INITIALIZER(0); + + int expectedValue = 0; + int newValue = 0; + int valueToAdd = 0; + + i.ref(); + i.deref(); + + i.testAndSetRelaxed(expectedValue, newValue); + i.testAndSetAcquire(expectedValue, newValue); + i.testAndSetRelease(expectedValue, newValue); + i.testAndSetOrdered(expectedValue, newValue); + + i.fetchAndStoreRelaxed(newValue); + i.fetchAndStoreAcquire(newValue); + i.fetchAndStoreRelease(newValue); + i.fetchAndStoreOrdered(newValue); + + i.fetchAndAddRelaxed(valueToAdd); + i.fetchAndAddAcquire(valueToAdd); + i.fetchAndAddRelease(valueToAdd); + i.fetchAndAddOrdered(valueToAdd); +} + +void tst_QAtomicInt::warningFree() +{ + // This is a compile time check for warnings. + // No need for actual work here. + + void (*foo)() = &warningFreeHelper; + (void)foo; +} + void tst_QAtomicInt::constructor_data() { QTest::addColumn("value"); diff --git a/tests/auto/qatomicpointer/tst_qatomicpointer.cpp b/tests/auto/qatomicpointer/tst_qatomicpointer.cpp index b9636a0..c1e0efd 100644 --- a/tests/auto/qatomicpointer/tst_qatomicpointer.cpp +++ b/tests/auto/qatomicpointer/tst_qatomicpointer.cpp @@ -58,6 +58,8 @@ public: ~tst_QAtomicPointer(); private slots: + void warningFree(); + void constructor(); void copy_constructor(); void equality_operator(); @@ -78,6 +80,9 @@ private slots: void isFetchAndAddWaitFree(); void fetchAndAdd_data(); void fetchAndAdd(); + +private: + static void warningFreeHelper(); }; tst_QAtomicPointer::tst_QAtomicPointer() @@ -86,6 +91,49 @@ tst_QAtomicPointer::tst_QAtomicPointer() tst_QAtomicPointer::~tst_QAtomicPointer() { } +struct WFHC +{ + void bar() {} +}; + +void tst_QAtomicPointer::warningFreeHelper() +{ + Q_ASSERT(false); + // The code below is bogus, and shouldn't be run. We're looking for warnings, only. + + QBasicAtomicPointer p = Q_BASIC_ATOMIC_INITIALIZER(0); + + p->bar(); + + WFHC *expectedValue = 0; + WFHC *newValue = 0; + qptrdiff valueToAdd = 0; + + p.testAndSetRelaxed(expectedValue, newValue); + p.testAndSetAcquire(expectedValue, newValue); + p.testAndSetRelease(expectedValue, newValue); + p.testAndSetOrdered(expectedValue, newValue); + + p.fetchAndStoreRelaxed(newValue); + p.fetchAndStoreAcquire(newValue); + p.fetchAndStoreRelease(newValue); + p.fetchAndStoreOrdered(newValue); + + p.fetchAndAddRelaxed(valueToAdd); + p.fetchAndAddAcquire(valueToAdd); + p.fetchAndAddRelease(valueToAdd); + p.fetchAndAddOrdered(valueToAdd); +} + +void tst_QAtomicPointer::warningFree() +{ + // This is a compile time check for warnings. + // No need for actual work here. + + void (*foo)() = &warningFreeHelper; + (void)foo; +} + void tst_QAtomicPointer::constructor() { void *one = this; -- cgit v0.12