diff options
Diffstat (limited to 'src/corelib/thread/qatomic_cxx11.h')
-rw-r--r-- | src/corelib/thread/qatomic_cxx11.h | 111 |
1 files changed, 42 insertions, 69 deletions
diff --git a/src/corelib/thread/qatomic_cxx11.h b/src/corelib/thread/qatomic_cxx11.h index 9669554515..47a7bc9a10 100644 --- a/src/corelib/thread/qatomic_cxx11.h +++ b/src/corelib/thread/qatomic_cxx11.h @@ -1,47 +1,12 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Thiago Macieira <thiago@kde.org> -** Copyright (C) 2016 Intel Corporation. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2011 Thiago Macieira <thiago@kde.org> +// Copyright (C) 2016 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QATOMIC_CXX11_H #define QATOMIC_CXX11_H #include <QtCore/qgenericatomic.h> +#include <QtCore/qyieldcpu.h> #include <atomic> QT_BEGIN_NAMESPACE @@ -70,10 +35,8 @@ QT_END_NAMESPACE * QAtomicInteger requires a constexpr answer (defect introduced in Qt 5.0). So * we'll err in the side of caution and say it isn't. */ - -// ### Qt 6: make non-constexpr (see above) template <int N> struct QAtomicTraits -{ static Q_DECL_CONSTEXPR inline bool isLockFree(); }; +{ static inline bool isLockFree(); }; #define Q_ATOMIC_INT32_IS_SUPPORTED #if ATOMIC_INT_LOCK_FREE == 2 @@ -86,7 +49,7 @@ template <int N> struct QAtomicTraits # define Q_ATOMIC_INT32_FETCH_AND_STORE_IS_ALWAYS_NATIVE # define Q_ATOMIC_INT32_FETCH_AND_ADD_IS_ALWAYS_NATIVE -template <> Q_DECL_CONSTEXPR inline bool QAtomicTraits<4>::isLockFree() +template <> inline bool QAtomicTraits<4>::isLockFree() { return true; } #elif ATOMIC_INT_LOCK_FREE == 1 # define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_SOMETIMES_NATIVE @@ -98,7 +61,7 @@ template <> Q_DECL_CONSTEXPR inline bool QAtomicTraits<4>::isLockFree() # define Q_ATOMIC_INT32_FETCH_AND_STORE_IS_SOMETIMES_NATIVE # define Q_ATOMIC_INT32_FETCH_AND_ADD_IS_SOMETIMES_NATIVE -template <> Q_DECL_CONSTEXPR inline bool QAtomicTraits<4>::isLockFree() +template <> inline bool QAtomicTraits<4>::isLockFree() { return false; } #else # define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NEVER_NATIVE @@ -110,7 +73,7 @@ template <> Q_DECL_CONSTEXPR inline bool QAtomicTraits<4>::isLockFree() # define Q_ATOMIC_INT32_FETCH_AND_STORE_IS_NEVER_NATIVE # define Q_ATOMIC_INT32_FETCH_AND_ADD_IS_NEVER_NATIVE -template <> Q_DECL_CONSTEXPR inline bool QAtomicTraits<4>::isLockFree() +template <> inline bool QAtomicTraits<4>::isLockFree() { return false; } #endif @@ -139,7 +102,7 @@ template<> struct QAtomicOpsSupport<1> { enum { IsSupported = 1 }; }; # define Q_ATOMIC_INT8_FETCH_AND_STORE_IS_ALWAYS_NATIVE # define Q_ATOMIC_INT8_FETCH_AND_ADD_IS_ALWAYS_NATIVE -template <> Q_DECL_CONSTEXPR inline bool QAtomicTraits<1>::isLockFree() +template <> inline bool QAtomicTraits<1>::isLockFree() { return true; } #elif ATOMIC_CHAR_LOCK_FREE == 1 # define Q_ATOMIC_INT8_REFERENCE_COUNTING_IS_SOMETIMES_NATIVE @@ -147,7 +110,7 @@ template <> Q_DECL_CONSTEXPR inline bool QAtomicTraits<1>::isLockFree() # define Q_ATOMIC_INT8_FETCH_AND_STORE_IS_SOMETIMES_NATIVE # define Q_ATOMIC_INT8_FETCH_AND_ADD_IS_SOMETIMES_NATIVE -template <> Q_DECL_CONSTEXPR inline bool QAtomicTraits<1>::isLockFree() +template <> inline bool QAtomicTraits<1>::isLockFree() { return false; } #else # define Q_ATOMIC_INT8_REFERENCE_COUNTING_IS_NEVER_NATIVE @@ -155,7 +118,7 @@ template <> Q_DECL_CONSTEXPR inline bool QAtomicTraits<1>::isLockFree() # define Q_ATOMIC_INT8_FETCH_AND_STORE_IS_NEVER_NATIVE # define Q_ATOMIC_INT8_FETCH_AND_ADD_IS_NEVER_NATIVE -template <> Q_DECL_CONSTEXPR bool QAtomicTraits<1>::isLockFree() +template <> bool QAtomicTraits<1>::isLockFree() { return false; } #endif @@ -167,7 +130,7 @@ template<> struct QAtomicOpsSupport<2> { enum { IsSupported = 1 }; }; # define Q_ATOMIC_INT16_FETCH_AND_STORE_IS_ALWAYS_NATIVE # define Q_ATOMIC_INT16_FETCH_AND_ADD_IS_ALWAYS_NATIVE -template <> Q_DECL_CONSTEXPR inline bool QAtomicTraits<2>::isLockFree() +template <> inline bool QAtomicTraits<2>::isLockFree() { return false; } #elif ATOMIC_SHORT_LOCK_FREE == 1 # define Q_ATOMIC_INT16_REFERENCE_COUNTING_IS_SOMETIMES_NATIVE @@ -175,7 +138,7 @@ template <> Q_DECL_CONSTEXPR inline bool QAtomicTraits<2>::isLockFree() # define Q_ATOMIC_INT16_FETCH_AND_STORE_IS_SOMETIMES_NATIVE # define Q_ATOMIC_INT16_FETCH_AND_ADD_IS_SOMETIMES_NATIVE -template <> Q_DECL_CONSTEXPR inline bool QAtomicTraits<2>::isLockFree() +template <> inline bool QAtomicTraits<2>::isLockFree() { return false; } #else # define Q_ATOMIC_INT16_REFERENCE_COUNTING_IS_NEVER_NATIVE @@ -183,11 +146,11 @@ template <> Q_DECL_CONSTEXPR inline bool QAtomicTraits<2>::isLockFree() # define Q_ATOMIC_INT16_FETCH_AND_STORE_IS_NEVER_NATIVE # define Q_ATOMIC_INT16_FETCH_AND_ADD_IS_NEVER_NATIVE -template <> Q_DECL_CONSTEXPR inline bool QAtomicTraits<2>::isLockFree() +template <> inline bool QAtomicTraits<2>::isLockFree() { return false; } #endif -#if QT_CONFIG(std_atomic64) +#if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(std_atomic64) template<> struct QAtomicOpsSupport<8> { enum { IsSupported = 1 }; }; # define Q_ATOMIC_INT64_IS_SUPPORTED # if ATOMIC_LLONG_LOCK_FREE == 2 @@ -196,7 +159,7 @@ template<> struct QAtomicOpsSupport<8> { enum { IsSupported = 1 }; }; # define Q_ATOMIC_INT64_FETCH_AND_STORE_IS_ALWAYS_NATIVE # define Q_ATOMIC_INT64_FETCH_AND_ADD_IS_ALWAYS_NATIVE -template <> Q_DECL_CONSTEXPR inline bool QAtomicTraits<8>::isLockFree() +template <> inline bool QAtomicTraits<8>::isLockFree() { return true; } # elif ATOMIC_LLONG_LOCK_FREE == 1 # define Q_ATOMIC_INT64_REFERENCE_COUNTING_IS_SOMETIMES_NATIVE @@ -204,7 +167,7 @@ template <> Q_DECL_CONSTEXPR inline bool QAtomicTraits<8>::isLockFree() # define Q_ATOMIC_INT64_FETCH_AND_STORE_IS_SOMETIMES_NATIVE # define Q_ATOMIC_INT64_FETCH_AND_ADD_IS_SOMETIMES_NATIVE -template <> Q_DECL_CONSTEXPR inline bool QAtomicTraits<8>::isLockFree() +template <> inline bool QAtomicTraits<8>::isLockFree() { return false; } # else # define Q_ATOMIC_INT64_REFERENCE_COUNTING_IS_NEVER_NATIVE @@ -212,7 +175,7 @@ template <> Q_DECL_CONSTEXPR inline bool QAtomicTraits<8>::isLockFree() # define Q_ATOMIC_INT64_FETCH_AND_STORE_IS_NEVER_NATIVE # define Q_ATOMIC_INT64_FETCH_AND_ADD_IS_NEVER_NATIVE -template <> Q_DECL_CONSTEXPR inline bool QAtomicTraits<8>::isLockFree() +template <> inline bool QAtomicTraits<8>::isLockFree() { return false; } # endif #endif @@ -275,23 +238,37 @@ template <typename X> struct QAtomicOps _q_value.store(newValue, std::memory_order_release); } - static inline Q_DECL_CONSTEXPR bool isReferenceCountingNative() noexcept { return isTestAndSetNative(); } - static inline Q_DECL_CONSTEXPR bool isReferenceCountingWaitFree() noexcept { return false; } + static inline bool isReferenceCountingNative() noexcept { return isTestAndSetNative(); } + static inline constexpr bool isReferenceCountingWaitFree() noexcept { return false; } template <typename T> static inline bool ref(std::atomic<T> &_q_value) { - return ++_q_value != 0; + /* Conceptually, we want to + * return ++_q_value != 0; + * However, that would be sequentially consistent, and thus stronger + * than what we need. Based on + * http://eel.is/c++draft/atomics.types.memop#6, we know that + * pre-increment is equivalent to fetch_add(1) + 1. Unlike + * pre-increment, fetch_add takes a memory order argument, so we can get + * the desired acquire-release semantics. + * One last gotcha is that fetch_add(1) + 1 would need to be converted + * back to T, because it's susceptible to integer promotion. To sidestep + * this issue and to avoid UB on signed overflow, we rewrite the + * expression to: + */ + return _q_value.fetch_add(1, std::memory_order_acq_rel) != T(-1); } template <typename T> static inline bool deref(std::atomic<T> &_q_value) noexcept { - return --_q_value != 0; + // compare with ref + return _q_value.fetch_sub(1, std::memory_order_acq_rel) != T(1); } - static inline Q_DECL_CONSTEXPR bool isTestAndSetNative() noexcept + static inline bool isTestAndSetNative() noexcept { return QAtomicTraits<sizeof(X)>::isLockFree(); } - static inline Q_DECL_CONSTEXPR bool isTestAndSetWaitFree() noexcept { return false; } + static inline constexpr bool isTestAndSetWaitFree() noexcept { return false; } template <typename T> static bool testAndSetRelaxed(std::atomic<T> &_q_value, T expectedValue, T newValue, T *currentValue = nullptr) noexcept @@ -329,8 +306,8 @@ template <typename X> struct QAtomicOps return tmp; } - static inline Q_DECL_CONSTEXPR bool isFetchAndStoreNative() noexcept { return isTestAndSetNative(); } - static inline Q_DECL_CONSTEXPR bool isFetchAndStoreWaitFree() noexcept { return false; } + static inline bool isFetchAndStoreNative() noexcept { return isTestAndSetNative(); } + static inline constexpr bool isFetchAndStoreWaitFree() noexcept { return false; } template <typename T> static T fetchAndStoreRelaxed(std::atomic<T> &_q_value, T newValue) noexcept @@ -356,8 +333,8 @@ template <typename X> struct QAtomicOps return _q_value.exchange(newValue, std::memory_order_acq_rel); } - static inline Q_DECL_CONSTEXPR bool isFetchAndAddNative() noexcept { return isTestAndSetNative(); } - static inline Q_DECL_CONSTEXPR bool isFetchAndAddWaitFree() noexcept { return false; } + static inline bool isFetchAndAddNative() noexcept { return isTestAndSetNative(); } + static inline constexpr bool isFetchAndAddWaitFree() noexcept { return false; } template <typename T> static inline T fetchAndAddRelaxed(std::atomic<T> &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd) noexcept @@ -480,11 +457,7 @@ template <typename X> struct QAtomicOps } }; -#if defined(Q_COMPILER_CONSTEXPR) # define Q_BASIC_ATOMIC_INITIALIZER(a) { a } -#else -# define Q_BASIC_ATOMIC_INITIALIZER(a) { ATOMIC_VAR_INIT(a) } -#endif QT_END_NAMESPACE |