Add support for 16- and 64-bit atomics with MSVC

MSVC provides the necessary functions / intrinsics for 16- and 64-bit
operations. It has some support for 8-bit too, but the most important
functions seem to be missing...

Change-Id: I177b4eb2a2cf14d716b78c94f9d6a9b11aea1b84
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
bb10
Thiago Macieira 2013-12-03 16:55:43 -08:00 committed by The Qt Project
parent 07e831d7ff
commit 1b3a424bcf
1 changed files with 152 additions and 39 deletions

View File

@ -53,6 +53,11 @@
# define QT_INTERLOCKED_PROTOTYPE __cdecl
# define QT_INTERLOCKED_DECLARE_PROTOTYPES
# define QT_INTERLOCKED_INTRINSIC
# define Q_ATOMIC_INT16_IS_SUPPORTED
# ifdef _WIN64
# define Q_ATOMIC_INT64_IS_SUPPORTED
# endif
#else // Q_OS_WINCE
@ -130,6 +135,20 @@ extern "C" {
__int64 QT_INTERLOCKED_FUNCTION( ExchangeAdd64 )(__int64 QT_INTERLOCKED_VOLATILE *, __int64);
# endif
# ifdef Q_ATOMIC_INT16_IS_SUPPORTED
short QT_INTERLOCKED_PROTOTYPE QT_INTERLOCKED_FUNCTION( Increment16 )(short QT_INTERLOCKED_VOLATILE *);
short QT_INTERLOCKED_PROTOTYPE QT_INTERLOCKED_FUNCTION( Decrement16 )(short QT_INTERLOCKED_VOLATILE *);
short QT_INTERLOCKED_PROTOTYPE QT_INTERLOCKED_FUNCTION( CompareExchange16 )(short QT_INTERLOCKED_VOLATILE *, short, short);
short QT_INTERLOCKED_PROTOTYPE QT_INTERLOCKED_FUNCTION( Exchange16 )(short QT_INTERLOCKED_VOLATILE *, short);
short QT_INTERLOCKED_PROTOTYPE QT_INTERLOCKED_FUNCTION( ExchangeAdd16 )(short QT_INTERLOCKED_VOLATILE *, short);
# endif
# ifdef Q_ATOMIC_INT64_IS_SUPPORTED
__int64 QT_INTERLOCKED_PROTOTYPE QT_INTERLOCKED_FUNCTION( Increment64 )(__int64 QT_INTERLOCKED_VOLATILE *);
__int64 QT_INTERLOCKED_PROTOTYPE QT_INTERLOCKED_FUNCTION( Decrement64 )(__int64 QT_INTERLOCKED_VOLATILE *);
__int64 QT_INTERLOCKED_PROTOTYPE QT_INTERLOCKED_FUNCTION( CompareExchange64 )(__int64 QT_INTERLOCKED_VOLATILE *, __int64, __int64);
__int64 QT_INTERLOCKED_PROTOTYPE QT_INTERLOCKED_FUNCTION( Exchange64 )(__int64 QT_INTERLOCKED_VOLATILE *, __int64);
//above already: qint64 QT_INTERLOCKED_PROTOTYPE QT_INTERLOCKED_FUNCTION( ExchangeAdd64 )(qint64 QT_INTERLOCKED_VOLATILE *, qint64);
# endif
}
#endif // QT_INTERLOCKED_DECLARE_PROTOTYPES
@ -158,21 +177,6 @@ extern "C" {
////////////////////////////////////////////////////////////////////////////////////////////////////
// Interlocked* replacement macros
#define QT_INTERLOCKED_INCREMENT(value) \
QT_INTERLOCKED_FUNCTION(Increment)(value)
#define QT_INTERLOCKED_DECREMENT(value) \
QT_INTERLOCKED_FUNCTION(Decrement)(value)
#define QT_INTERLOCKED_COMPARE_EXCHANGE(value, newValue, expectedValue) \
QT_INTERLOCKED_FUNCTION(CompareExchange)((value), (newValue), (expectedValue))
#define QT_INTERLOCKED_EXCHANGE(value, newValue) \
QT_INTERLOCKED_FUNCTION(Exchange)((value), (newValue))
#define QT_INTERLOCKED_EXCHANGE_ADD(value, valueToAdd) \
QT_INTERLOCKED_FUNCTION(ExchangeAdd)((value), (valueToAdd))
#if defined(Q_OS_WINCE) || defined(__i386__) || defined(_M_IX86)
# define QT_INTERLOCKED_COMPARE_EXCHANGE_POINTER(value, newValue, expectedValue) \
@ -258,8 +262,45 @@ QT_END_NAMESPACE
#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE
#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_WAIT_FREE
#ifdef Q_ATOMIC_INT16_IS_SUPPORTED
# define Q_ATOMIC_INT16_REFERENCE_COUNTING_IS_ALWAYS_NATIVE
# define Q_ATOMIC_INT16_REFERENCE_COUNTING_IS_WAIT_FREE
# define Q_ATOMIC_INT16_TEST_AND_SET_IS_ALWAYS_NATIVE
# define Q_ATOMIC_INT16_TEST_AND_SET_IS_WAIT_FREE
# define Q_ATOMIC_INT16_FETCH_AND_STORE_IS_ALWAYS_NATIVE
# define Q_ATOMIC_INT16_FETCH_AND_STORE_IS_WAIT_FREE
# define Q_ATOMIC_INT16_FETCH_AND_ADD_IS_ALWAYS_NATIVE
# define Q_ATOMIC_INT16_FETCH_AND_ADD_IS_WAIT_FREE
template<> struct QAtomicIntegerTraits<short> { enum { IsInteger = 1 }; };
template<> struct QAtomicIntegerTraits<unsigned short> { enum { IsInteger = 1 }; };
#endif
#ifdef Q_ATOMIC_INT64_IS_SUPPORTED
# define Q_ATOMIC_INT64_REFERENCE_COUNTING_IS_ALWAYS_NATIVE
# define Q_ATOMIC_INT64_REFERENCE_COUNTING_IS_WAIT_FREE
# define Q_ATOMIC_INT64_TEST_AND_SET_IS_ALWAYS_NATIVE
# define Q_ATOMIC_INT64_TEST_AND_SET_IS_WAIT_FREE
# define Q_ATOMIC_INT64_FETCH_AND_STORE_IS_ALWAYS_NATIVE
# define Q_ATOMIC_INT64_FETCH_AND_STORE_IS_WAIT_FREE
# define Q_ATOMIC_INT64_FETCH_AND_ADD_IS_ALWAYS_NATIVE
# define Q_ATOMIC_INT64_FETCH_AND_ADD_IS_WAIT_FREE
template<> struct QAtomicIntegerTraits<long long> { enum { IsInteger = 1 }; };
template<> struct QAtomicIntegerTraits<unsigned long long> { enum { IsInteger = 1 }; };
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////
template <int N> struct QAtomicWindowsType { typedef typename QIntegerForSize<N>::Signed Type; };
template <> struct QAtomicWindowsType<4> { typedef long Type; };
template<> struct QAtomicIntegerTraits<int> { enum { IsInteger = 1 }; };
template<> struct QAtomicIntegerTraits<unsigned int> { enum { IsInteger = 1 }; };
template<> struct QAtomicIntegerTraits<long> { enum { IsInteger = 1 }; };
@ -268,62 +309,134 @@ template<> struct QAtomicIntegerTraits<unsigned long> { enum { IsInteger = 1 };
template<> struct QAtomicIntegerTraits<char32_t> { enum { IsInteger = 1 }; };
#endif
// No definition, needs specialization
template <int N> struct QAtomicOpsBySize;
template <>
struct QAtomicOpsBySize<4> : QGenericAtomicOps<QAtomicOpsBySize<4> >
template <int N> struct QAtomicOpsBySize : QGenericAtomicOps<QAtomicOpsBySize<N> >
{
// The 32-bit Interlocked*() API takes parameters as longs.
typedef long Type;
static inline Q_DECL_CONSTEXPR bool isReferenceCountingNative() Q_DECL_NOTHROW { return true; }
static inline Q_DECL_CONSTEXPR bool isReferenceCountingWaitFree() Q_DECL_NOTHROW { return true; }
static bool ref(long &_q_value) Q_DECL_NOTHROW;
static bool deref(long &_q_value) Q_DECL_NOTHROW;
template <typename T> static bool ref(T &_q_value) Q_DECL_NOTHROW;
template <typename T> static bool deref(T &_q_value) Q_DECL_NOTHROW;
static inline Q_DECL_CONSTEXPR bool isTestAndSetNative() Q_DECL_NOTHROW { return true; }
static inline Q_DECL_CONSTEXPR bool isTestAndSetWaitFree() Q_DECL_NOTHROW { return true; }
static bool testAndSetRelaxed(long &_q_value, long expectedValue, long newValue) Q_DECL_NOTHROW;
template <typename T> static bool testAndSetRelaxed(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW;
static inline Q_DECL_CONSTEXPR bool isFetchAndStoreNative() Q_DECL_NOTHROW { return true; }
static inline Q_DECL_CONSTEXPR bool isFetchAndStoreWaitFree() Q_DECL_NOTHROW { return true; }
static long fetchAndStoreRelaxed(long &_q_value, long newValue) Q_DECL_NOTHROW;
template <typename T> static T fetchAndStoreRelaxed(T &_q_value, T newValue) Q_DECL_NOTHROW;
static inline Q_DECL_CONSTEXPR bool isFetchAndAddNative() Q_DECL_NOTHROW { return true; }
static inline Q_DECL_CONSTEXPR bool isFetchAndAddWaitFree() Q_DECL_NOTHROW { return true; }
static long fetchAndAddRelaxed(long &_q_value, QAtomicAdditiveType<long>::AdditiveT valueToAdd) Q_DECL_NOTHROW;
template <typename T> static T fetchAndAddRelaxed(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd) Q_DECL_NOTHROW;
private:
typedef typename QAtomicWindowsType<N>::Type Type;
template <typename T> static inline Type *atomic(T *t)
{ Q_STATIC_ASSERT(sizeof(T) == sizeof(Type)); return reinterpret_cast<Type *>(t); }
template <typename T> static inline Type value(T t)
{ Q_STATIC_ASSERT(sizeof(T) == sizeof(Type)); return Type(t); }
};
template <typename T>
struct QAtomicOps : QAtomicOpsBySize<sizeof(T)>
{ };
inline bool QAtomicOpsBySize<4>::ref(long &_q_value) Q_DECL_NOTHROW
{
return QT_INTERLOCKED_INCREMENT(&_q_value) != 0;
typedef T Type;
};
template<> template<typename T>
inline bool QAtomicOpsBySize<4>::ref(T &_q_value) Q_DECL_NOTHROW
{
return QT_INTERLOCKED_FUNCTION(Increment)(atomic(&_q_value)) != 0;
}
inline bool QAtomicOpsBySize<4>::deref(long &_q_value) Q_DECL_NOTHROW
template<> template<typename T>
inline bool QAtomicOpsBySize<4>::deref(T &_q_value) Q_DECL_NOTHROW
{
return QT_INTERLOCKED_DECREMENT(&_q_value) != 0;
return QT_INTERLOCKED_FUNCTION(Decrement)(atomic(&_q_value)) != 0;
}
inline bool QAtomicOpsBySize<4>::testAndSetRelaxed(long &_q_value, long expectedValue, long newValue) Q_DECL_NOTHROW
template<> template<typename T>
inline bool QAtomicOpsBySize<4>::testAndSetRelaxed(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW
{
return QT_INTERLOCKED_COMPARE_EXCHANGE(&_q_value, newValue, expectedValue) == expectedValue;
return QT_INTERLOCKED_FUNCTION(CompareExchange)(atomic(&_q_value), value(newValue), value(expectedValue)) == value(expectedValue);
}
inline long QAtomicOpsBySize<4>::fetchAndStoreRelaxed(long &_q_value, long newValue) Q_DECL_NOTHROW
template<> template<typename T>
inline T QAtomicOpsBySize<4>::fetchAndStoreRelaxed(T &_q_value, T newValue) Q_DECL_NOTHROW
{
return QT_INTERLOCKED_EXCHANGE(&_q_value, newValue);
return QT_INTERLOCKED_FUNCTION(Exchange)(atomic(&_q_value), value(newValue));
}
inline long QAtomicOpsBySize<4>::fetchAndAddRelaxed(long &_q_value, QAtomicAdditiveType<long>::AdditiveT valueToAdd) Q_DECL_NOTHROW
template<> template<typename T>
inline T QAtomicOpsBySize<4>::fetchAndAddRelaxed(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd) Q_DECL_NOTHROW
{
return QT_INTERLOCKED_EXCHANGE_ADD(&_q_value, valueToAdd * QAtomicAdditiveType<long>::AddScale);
return QT_INTERLOCKED_FUNCTION(ExchangeAdd)(atomic(&_q_value), value<T>(valueToAdd * QAtomicAdditiveType<T>::AddScale));
}
#ifdef Q_ATOMIC_INT16_IS_SUPPORTED
template<> template<typename T>
inline bool QAtomicOpsBySize<2>::ref(T &_q_value) Q_DECL_NOTHROW
{
return QT_INTERLOCKED_FUNCTION(Increment16)(atomic(&_q_value)) != 0;
}
template<> template<typename T>
inline bool QAtomicOpsBySize<2>::deref(T &_q_value) Q_DECL_NOTHROW
{
return QT_INTERLOCKED_FUNCTION(Decrement16)(atomic(&_q_value)) != 0;
}
template<> template<typename T>
inline bool QAtomicOpsBySize<2>::testAndSetRelaxed(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW
{
return QT_INTERLOCKED_FUNCTION(CompareExchange16)(atomic(&_q_value), value(newValue), value(expectedValue)) == value(expectedValue);
}
template<> template<typename T>
inline T QAtomicOpsBySize<2>::fetchAndStoreRelaxed(T &_q_value, T newValue) Q_DECL_NOTHROW
{
return QT_INTERLOCKED_FUNCTION(Exchange16)(atomic(&_q_value), value(newValue));
}
template<> template<typename T>
inline T QAtomicOpsBySize<2>::fetchAndAddRelaxed(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd) Q_DECL_NOTHROW
{
return QT_INTERLOCKED_FUNCTION(ExchangeAdd16)(atomic(&_q_value), value<T>(valueToAdd * QAtomicAdditiveType<T>::AddScale));
}
#endif
#ifdef Q_ATOMIC_INT64_IS_SUPPORTED
template<> template<typename T>
inline bool QAtomicOpsBySize<8>::ref(T &_q_value) Q_DECL_NOTHROW
{
return QT_INTERLOCKED_FUNCTION(Increment64)(atomic(&_q_value)) != 0;
}
template<> template<typename T>
inline bool QAtomicOpsBySize<8>::deref(T &_q_value) Q_DECL_NOTHROW
{
return QT_INTERLOCKED_FUNCTION(Decrement64)(atomic(&_q_value)) != 0;
}
template<> template<typename T>
inline bool QAtomicOpsBySize<8>::testAndSetRelaxed(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW
{
return QT_INTERLOCKED_FUNCTION(CompareExchange64)(atomic(&_q_value), value(newValue), value(expectedValue)) == value(expectedValue);
}
template<> template<typename T>
inline T QAtomicOpsBySize<8>::fetchAndStoreRelaxed(T &_q_value, T newValue) Q_DECL_NOTHROW
{
return QT_INTERLOCKED_FUNCTION(Exchange64)(atomic(&_q_value), value(newValue));
}
template<> template<typename T>
inline T QAtomicOpsBySize<8>::fetchAndAddRelaxed(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd) Q_DECL_NOTHROW
{
return QT_INTERLOCKED_FUNCTION(ExchangeAdd64)(atomic(&_q_value), value<T>(valueToAdd * QAtomicAdditiveType<T>::AddScale));
}
#endif
// Specialization for pointer types, since we have Interlocked*Pointer() variants in some configurations
template <typename T>
struct QAtomicOps<T *> : QGenericAtomicOps<QAtomicOps<T *> >