diff options
Diffstat (limited to 'tests/auto/corelib/thread/qatomicinteger/tst_qatomicinteger.cpp')
-rw-r--r-- | tests/auto/corelib/thread/qatomicinteger/tst_qatomicinteger.cpp | 198 |
1 files changed, 39 insertions, 159 deletions
diff --git a/tests/auto/corelib/thread/qatomicinteger/tst_qatomicinteger.cpp b/tests/auto/corelib/thread/qatomicinteger/tst_qatomicinteger.cpp index 9f03c4c2b7..d1a8a8f729 100644 --- a/tests/auto/corelib/thread/qatomicinteger/tst_qatomicinteger.cpp +++ b/tests/auto/corelib/thread/qatomicinteger/tst_qatomicinteger.cpp @@ -1,62 +1,19 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Intel Corporation. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifdef QT_ATOMIC_FORCE_CXX11 -// We need to check if this compiler has C++11 atomics and constexpr support. -// We can't rely on qcompilerdetection.h because it forces all of qglobal.h to -// be included, which causes qbasicatomic.h to be included too. -// Incomplete, but ok -# if defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1500 && (__cplusplus >= 201103L || defined(__INTEL_CXX11_MODE__)) -# elif defined(__clang__) && (__cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)) -# if !__has_feature(cxx_constexpr) || !__has_feature(cxx_atomic) || !__has_include(<atomic>) -# undef QT_ATOMIC_FORCE_CXX11 -# endif -# elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 407 && (__cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)) -# elif defined(_MSC_VER) - // We need MSVC 2015 because of: atomics (2012), constexpr (2015), and unrestricted unions (2015). - // Support for constexpr is not working completely on MSVC 2015 but it's enough for the test. -# else -# undef QT_ATOMIC_FORCE_CXX11 -# endif - -# ifndef QT_ATOMIC_FORCE_CXX11 -# undef QATOMIC_TEST_TYPE -# define QATOMIC_TEST_TYPE unsupported -# endif -#endif +// Copyright (C) 2016 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only -#include <QtTest> +#include <QTest> #include <QAtomicInt> #include <limits> #include <limits.h> #include <wchar.h> +#if !defined(Q_ATOMIC_INT8_IS_SUPPORTED) +# error "QAtomicInteger for 8-bit types must be supported!" +#endif +#if !defined(Q_ATOMIC_INT16_IS_SUPPORTED) +# error "QAtomicInteger for 16-bit types must be supported!" +#endif #if !defined(Q_ATOMIC_INT32_IS_SUPPORTED) # error "QAtomicInteger for 32-bit types must be supported!" #endif @@ -65,31 +22,21 @@ #endif // always supported types: +#define TYPE_SUPPORTED_char 1 +#define TYPE_SUPPORTED_uchar 1 +#define TYPE_SUPPORTED_schar 1 +#define TYPE_SUPPORTED_short 1 +#define TYPE_SUPPORTED_ushort 1 +#define TYPE_SUPPORTED_char16_t 1 +#define TYPE_SUPPORTED_wchar_t 1 #define TYPE_SUPPORTED_int 1 #define TYPE_SUPPORTED_uint 1 #define TYPE_SUPPORTED_long 1 #define TYPE_SUPPORTED_ulong 1 #define TYPE_SUPPORTED_qptrdiff 1 #define TYPE_SUPPORTED_quintptr 1 -#if (defined(__SIZEOF_WCHAR_T__) && (__SIZEOF_WCHAR_T__-0) > 2) \ - || (defined(WCHAR_MAX) && (WCHAR_MAX-0 > 0x10000)) -# define TYPE_SUPPORTED_wchar_t 1 -#endif -#define TYPE_SUPPORTED_char32_t 1 +#define TYPE_SUPPORTED_char32_t 1 -#ifdef Q_ATOMIC_INT8_IS_SUPPORTED -# define TYPE_SUPPORTED_char 1 -# define TYPE_SUPPORTED_uchar 1 -# define TYPE_SUPPORTED_schar 1 -#endif -#ifdef Q_ATOMIC_INT16_IS_SUPPORTED -# define TYPE_SUPPORTED_short 1 -# define TYPE_SUPPORTED_ushort 1 -# define TYPE_SUPPORTED_char16_t 1 -# ifndef TYPE_SUPPORTED_wchar_t -# define TYPE_SUPPORTED_wchar_t 1 -# endif -#endif #ifdef Q_ATOMIC_INT64_IS_SUPPORTED # define TYPE_SUPPORTED_qlonglong 1 # define TYPE_SUPPORTED_qulonglong 1 @@ -117,6 +64,7 @@ typedef signed char schar; typedef TEST_TYPE Type; typedef Type T; // shorthand +using U = std::make_unsigned_t<T>; enum { TypeIsUnsigned = Type(-1) > Type(0), TypeIsSigned = !TypeIsUnsigned @@ -127,6 +75,8 @@ template <> struct LargeIntTemplate<true> { typedef quint64 Type; }; template <> struct LargeIntTemplate<false> { typedef qint64 Type; }; typedef LargeIntTemplate<TypeIsUnsigned>::Type LargeInt; +namespace { + class tst_QAtomicIntegerXX : public QObject { Q_OBJECT @@ -196,18 +146,11 @@ void tst_QAtomicIntegerXX::static_checks() (void) QAtomicInteger<T>::isFetchAndAddNative(); (void) QAtomicInteger<T>::isFetchAndAddWaitFree(); -#ifdef Q_COMPILER_CONSTEXPR // this is a compile-time test only booleanHelper<QAtomicInteger<T>::isReferenceCountingWaitFree()>(); booleanHelper<QAtomicInteger<T>::isTestAndSetWaitFree()>(); booleanHelper<QAtomicInteger<T>::isFetchAndStoreWaitFree()>(); booleanHelper<QAtomicInteger<T>::isFetchAndAddWaitFree()>(); -#elif 0 // no longer constexpr - booleanHelper<QAtomicInteger<T>::isReferenceCountingNative()>(); - booleanHelper<QAtomicInteger<T>::isTestAndSetNative()>(); - booleanHelper<QAtomicInteger<T>::isFetchAndStoreNative()>(); - booleanHelper<QAtomicInteger<T>::isFetchAndAddNative()>(); -#endif } void tst_QAtomicIntegerXX::addData() @@ -349,46 +292,32 @@ void tst_QAtomicIntegerXX::loadAcquireStoreRelease() void tst_QAtomicIntegerXX::refDeref() { QFETCH(LargeInt, value); - const bool needToPreventOverflow = TypeIsSigned && value == std::numeric_limits<T>::max(); - const bool needToPreventUnderflow = TypeIsSigned && value == std::numeric_limits<T>::min(); - T nextValue = T(value); - if (!needToPreventOverflow) - ++nextValue; - T prevValue = T(value); - if (!needToPreventUnderflow) - --prevValue; + + // We perform arithmetic using the unsigned type U to avoid signed + // integer overflows in the non-atomic portion (atomics have well-defined, + // two's complement overflow, even signed ones). + T nextValue = T(U(value) + 1); + T prevValue = T(U(value) - 1); QAtomicInteger<T> atomic(value); - if (!needToPreventOverflow) { QCOMPARE(atomic.ref(), (nextValue != 0)); QCOMPARE(atomic.loadRelaxed(), nextValue); QCOMPARE(atomic.deref(), (value != 0)); - } QCOMPARE(atomic.loadRelaxed(), T(value)); - if (!needToPreventUnderflow) { QCOMPARE(atomic.deref(), (prevValue != 0)); QCOMPARE(atomic.loadRelaxed(), prevValue); QCOMPARE(atomic.ref(), (value != 0)); - } QCOMPARE(atomic.loadRelaxed(), T(value)); - if (!needToPreventOverflow) { QCOMPARE(++atomic, nextValue); QCOMPARE(--atomic, T(value)); - } - if (!needToPreventUnderflow) { QCOMPARE(--atomic, prevValue); QCOMPARE(++atomic, T(value)); - } - if (!needToPreventOverflow) { QCOMPARE(atomic++, T(value)); QCOMPARE(atomic--, nextValue); - } - if (!needToPreventUnderflow) { QCOMPARE(atomic--, T(value)); QCOMPARE(atomic++, prevValue); - } QCOMPARE(atomic.loadRelaxed(), T(value)); } @@ -491,80 +420,55 @@ void tst_QAtomicIntegerXX::fetchAndAdd() QFETCH(LargeInt, value); QAtomicInteger<T> atomic(value); + // We perform the additions using the unsigned type U to avoid signed + // integer overflows in the non-atomic portion (atomics have well-defined, + // two's complement overflow, even signed ones). T parcel1 = 42; T parcel2 = T(0-parcel1); + T newValue1 = T(U(value) + parcel1); + T newValue2 = T(U(value) + parcel2); - const bool needToPreventOverflow = TypeIsSigned && value > std::numeric_limits<T>::max() + parcel2; - const bool needToPreventUnderflow = TypeIsSigned && value < std::numeric_limits<T>::min() + parcel1; - - T newValue1 = T(value); - if (!needToPreventOverflow) - newValue1 += parcel1; - T newValue2 = T(value); - if (!needToPreventUnderflow) - newValue2 += parcel2; - - if (!needToPreventOverflow) { QCOMPARE(atomic.fetchAndAddRelaxed(parcel1), T(value)); QCOMPARE(atomic.loadRelaxed(), newValue1); QCOMPARE(atomic.fetchAndAddRelaxed(parcel2), newValue1); - } QCOMPARE(atomic.loadRelaxed(), T(value)); - if (!needToPreventUnderflow) { QCOMPARE(atomic.fetchAndAddRelaxed(parcel2), T(value)); QCOMPARE(atomic.loadRelaxed(), newValue2); QCOMPARE(atomic.fetchAndAddRelaxed(parcel1), newValue2); - } QCOMPARE(atomic.loadRelaxed(), T(value)); - if (!needToPreventOverflow) { QCOMPARE(atomic.fetchAndAddAcquire(parcel1), T(value)); QCOMPARE(atomic.loadRelaxed(), newValue1); QCOMPARE(atomic.fetchAndAddAcquire(parcel2), newValue1); - } QCOMPARE(atomic.loadRelaxed(), T(value)); - if (!needToPreventUnderflow) { QCOMPARE(atomic.fetchAndAddAcquire(parcel2), T(value)); QCOMPARE(atomic.loadRelaxed(), newValue2); QCOMPARE(atomic.fetchAndAddAcquire(parcel1), newValue2); - } QCOMPARE(atomic.loadRelaxed(), T(value)); - if (!needToPreventOverflow) { QCOMPARE(atomic.fetchAndAddRelease(parcel1), T(value)); QCOMPARE(atomic.loadAcquire(), newValue1); QCOMPARE(atomic.fetchAndAddRelease(parcel2), newValue1); - } QCOMPARE(atomic.loadAcquire(), T(value)); - if (!needToPreventUnderflow) { QCOMPARE(atomic.fetchAndAddRelease(parcel2), T(value)); QCOMPARE(atomic.loadAcquire(), newValue2); QCOMPARE(atomic.fetchAndAddRelease(parcel1), newValue2); - } QCOMPARE(atomic.loadAcquire(), T(value)); - if (!needToPreventOverflow) { QCOMPARE(atomic.fetchAndAddOrdered(parcel1), T(value)); QCOMPARE(atomic.loadAcquire(), newValue1); QCOMPARE(atomic.fetchAndAddOrdered(parcel2), newValue1); - } QCOMPARE(atomic.loadAcquire(), T(value)); - if (!needToPreventUnderflow) { QCOMPARE(atomic.fetchAndAddOrdered(parcel2), T(value)); QCOMPARE(atomic.loadAcquire(), newValue2); QCOMPARE(atomic.fetchAndAddOrdered(parcel1), newValue2); - } QCOMPARE(atomic.loadAcquire(), T(value)); // operator+= - if (!needToPreventOverflow) { QCOMPARE(atomic += parcel1, newValue1); QCOMPARE(atomic += parcel2, T(value)); - } - if (!needToPreventUnderflow) { QCOMPARE(atomic += parcel2, newValue2); QCOMPARE(atomic += parcel1, T(value)); - } } void tst_QAtomicIntegerXX::fetchAndSub() @@ -572,80 +476,55 @@ void tst_QAtomicIntegerXX::fetchAndSub() QFETCH(LargeInt, value); QAtomicInteger<T> atomic(value); + // We perform the subtractions using the unsigned type U to avoid signed + // integer underrflows in the non-atomic portion (atomics have well-defined, + // two's complement underflow, even signed ones). T parcel1 = 42; T parcel2 = T(0-parcel1); + T newValue1 = T(U(value) - parcel1); + T newValue2 = T(U(value) - parcel2); - const bool needToPreventOverflow = TypeIsSigned && value > std::numeric_limits<T>::max() - parcel1; - const bool needToPreventUnderflow = TypeIsSigned && value < std::numeric_limits<T>::min() - parcel2; - - T newValue1 = T(value); - if (!needToPreventUnderflow) - newValue1 -= parcel1; - T newValue2 = T(value); - if (!needToPreventOverflow) - newValue2 -= parcel2; - - if (!needToPreventUnderflow) { QCOMPARE(atomic.fetchAndSubRelaxed(parcel1), T(value)); QCOMPARE(atomic.loadRelaxed(), newValue1); QCOMPARE(atomic.fetchAndSubRelaxed(parcel2), newValue1); - } QCOMPARE(atomic.loadRelaxed(), T(value)); - if (!needToPreventOverflow) { QCOMPARE(atomic.fetchAndSubRelaxed(parcel2), T(value)); QCOMPARE(atomic.loadRelaxed(), newValue2); QCOMPARE(atomic.fetchAndSubRelaxed(parcel1), newValue2); - } QCOMPARE(atomic.loadRelaxed(), T(value)); - if (!needToPreventUnderflow) { QCOMPARE(atomic.fetchAndSubAcquire(parcel1), T(value)); QCOMPARE(atomic.loadRelaxed(), newValue1); QCOMPARE(atomic.fetchAndSubAcquire(parcel2), newValue1); - } QCOMPARE(atomic.loadRelaxed(), T(value)); - if (!needToPreventOverflow) { QCOMPARE(atomic.fetchAndSubAcquire(parcel2), T(value)); QCOMPARE(atomic.loadRelaxed(), newValue2); QCOMPARE(atomic.fetchAndSubAcquire(parcel1), newValue2); - } QCOMPARE(atomic.loadRelaxed(), T(value)); - if (!needToPreventUnderflow) { QCOMPARE(atomic.fetchAndSubRelease(parcel1), T(value)); QCOMPARE(atomic.loadAcquire(), newValue1); QCOMPARE(atomic.fetchAndSubRelease(parcel2), newValue1); - } QCOMPARE(atomic.loadAcquire(), T(value)); - if (!needToPreventOverflow) { QCOMPARE(atomic.fetchAndSubRelease(parcel2), T(value)); QCOMPARE(atomic.loadAcquire(), newValue2); QCOMPARE(atomic.fetchAndSubRelease(parcel1), newValue2); - } QCOMPARE(atomic.loadAcquire(), T(value)); - if (!needToPreventUnderflow) { QCOMPARE(atomic.fetchAndSubOrdered(parcel1), T(value)); QCOMPARE(atomic.loadAcquire(), newValue1); QCOMPARE(atomic.fetchAndSubOrdered(parcel2), newValue1); - } QCOMPARE(atomic.loadAcquire(), T(value)); - if (!needToPreventOverflow) { QCOMPARE(atomic.fetchAndSubOrdered(parcel2), T(value)); QCOMPARE(atomic.loadAcquire(), newValue2); QCOMPARE(atomic.fetchAndSubOrdered(parcel1), newValue2); - } QCOMPARE(atomic.loadAcquire(), T(value)); // operator-= - if (!needToPreventUnderflow) { QCOMPARE(atomic -= parcel1, newValue1); QCOMPARE(atomic -= parcel2, T(value)); - } - if (!needToPreventOverflow) { QCOMPARE(atomic -= parcel2, newValue2); QCOMPARE(atomic -= parcel1, T(value)); - } } void tst_QAtomicIntegerXX::fetchAndOr() @@ -795,8 +674,9 @@ void tst_QAtomicIntegerXX::fetchAndXor() QCOMPARE(atomic ^= minusOne, T(~value)); QCOMPARE(atomic ^= minusOne, T(value)); } - -#include "tst_qatomicinteger.moc" +} QTEST_APPLESS_MAIN(tst_QAtomicIntegerXX) +#include "tst_qatomicinteger.moc" + |