From 2398e225abdea36321670d34a8238b6e64dba281 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 8 Sep 2015 20:35:33 -0300 Subject: Auto-detect whether 64-bit std::atomic really works The C++ standard says it must, but some badly-configured toolchains seem to be lacking support. In particular, for some 32-bit platforms without native support for them, GCC implements 64-bit atomics via out-of-line functions in libatomic. If that library is missing... well, then std::atomic 64-bit doesn't work and we mustn't try to use it. This was found when trying to compile Qt 5.6 for MIPS 32-bit: Linking library libQt5Core.so.5.6.0 .obj/qsimd.o: In function `std::__atomic_base::load(std::memory_order) const': /opt/poky/1.7/sysroots/mips32r2-poky-linux/usr/include/c++/4.9.1/bits/atomic_base.h:500: undefined reference to `__atomic_load_8' .obj/qsimd.o: In function `std::__atomic_base::store(unsigned long long, std::memory_order)': /opt/poky/1.7/sysroots/mips32r2-poky-linux/usr/include/c++/4.9.1/bits/atomic_base.h:478: undefined reference to `__atomic_store_8' Yocto bug report: https://bugzilla.yoctoproject.org/show_bug.cgi?id=8274 Change-Id: I42e7ef1a481840699a8dffff140224d6614e5c36 Reviewed-by: Oswald Buddenhagen Reviewed-by: Lars Knoll Reviewed-by: Thiago Macieira (cherry picked from commit 3d7586b760550b7d89594c8d7462fc30b868ecc6) Reviewed-by: Dmitry Shachnev --- config.tests/common/atomic64/atomic64.cpp | 54 +++++++++++++++++++++++++++++++ config.tests/common/atomic64/atomic64.pro | 3 ++ configure | 20 +++++++++++- src/corelib/arch/arch.pri | 2 ++ src/corelib/arch/qatomic_cxx11.h | 12 ++++--- tools/configure/configureapp.cpp | 17 +++++++++- 6 files changed, 101 insertions(+), 7 deletions(-) create mode 100644 config.tests/common/atomic64/atomic64.cpp create mode 100644 config.tests/common/atomic64/atomic64.pro diff --git a/config.tests/common/atomic64/atomic64.cpp b/config.tests/common/atomic64/atomic64.cpp new file mode 100644 index 0000000000..8dbea96c8b --- /dev/null +++ b/config.tests/common/atomic64/atomic64.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Intel Corporation. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +void test(volatile std::atomic &a) +{ + std::int64_t v = a.load(std::memory_order_acquire); + while (!a.compare_exchange_strong(v, v + 1, + std::memory_order_acq_rel, + std::memory_order_acquire)) { + v = a.exchange(v - 1); + } + + a.store(v + 1, std::memory_order_release); +} + +int main(int, char **) +{ + void *ptr = (void*)0xffffffc0; // any random pointer + test(*reinterpret_cast *>(ptr)); + return 0; +} diff --git a/config.tests/common/atomic64/atomic64.pro b/config.tests/common/atomic64/atomic64.pro new file mode 100644 index 0000000000..c9a85817ca --- /dev/null +++ b/config.tests/common/atomic64/atomic64.pro @@ -0,0 +1,3 @@ +SOURCES = atomic64.cpp +CONFIG += c++11 console +CONFIG -= qt diff --git a/configure b/configure index c29c113da3..61f0ea0bea 100755 --- a/configure +++ b/configure @@ -2,7 +2,7 @@ ############################################################################# ## ## Copyright (C) 2015 The Qt Company Ltd. -## Copyright (C) 2013 Intel Corporation. +## Copyright (C) 2015 Intel Corporation. ## Contact: http://www.qt.io/licensing/ ## ## This file is the build configuration utility of the Qt Toolkit. @@ -661,6 +661,7 @@ CFG_SYSTEM_PROXIES=no CFG_ANDROID_STYLE_ASSETS=yes CFG_GSTREAMER=auto CFG_GSTREAMER_VERSION="" +CFG_ATOMIC64=auto # Target architecture CFG_ARCH= @@ -4328,6 +4329,15 @@ if [ "$CFG_CXX11" != "no" ]; then fi fi +# Detect whether 64-bit std::atomic works -- some 32-bit platforms require extra library support +if compileTest common/atomic64 "64-bit std::atomic"; then + CFG_ATOMIC64=yes +elif compileTest common/atomic64 "64-bit std::atomic in -latomic" -latomic; then + CFG_ATOMIC64=libatomic +else + CFG_ATOMIC64=no +fi + # detect sse2 support if [ "${CFG_SSE2}" = "auto" ]; then if compileTest common/sse2 "sse2"; then @@ -6016,6 +6026,10 @@ fi [ "$CFG_CXX11" = "yes" ] && QT_CONFIG="$QT_CONFIG c++11" +if [ "$CFG_ATOMIC64" = "libatomic" ]; then + QMAKE_CONFIG="$QMAKE_CONFIG atomic64-libatomic" +fi + if [ "$CFG_SILENT" = "yes" ]; then QMAKE_CONFIG="$QMAKE_CONFIG silent" fi @@ -6567,6 +6581,10 @@ else echo "#define QT_POINTER_SIZE $?" >>"$outpath/src/corelib/global/qconfig.h.new" fi +if [ "$CFG_ATOMIC64" = "no" ]; then + echo "#define QT_NO_STD_ATOMIC64" >> "$outpath/src/corelib/global/qconfig.h.new" +fi + #REDUCE_RELOCATIONS is a elf/unix only thing, so not in windows configure.exe if [ "$CFG_REDUCE_RELOCATIONS" = "yes" ]; then echo "#define QT_REDUCE_RELOCATIONS" >>"$outpath/src/corelib/global/qconfig.h.new" diff --git a/src/corelib/arch/arch.pri b/src/corelib/arch/arch.pri index 16fe8b8e5c..083d912331 100644 --- a/src/corelib/arch/arch.pri +++ b/src/corelib/arch/arch.pri @@ -10,6 +10,8 @@ HEADERS += \ arch/qatomic_gcc.h \ arch/qatomic_cxx11.h +atomic64-libatomic: LIBS += -latomic + unix { # fallback implementation when no other appropriate qatomic_*.h exists HEADERS += arch/qatomic_unix.h diff --git a/src/corelib/arch/qatomic_cxx11.h b/src/corelib/arch/qatomic_cxx11.h index 0e06ca951a..4136e09ce2 100644 --- a/src/corelib/arch/qatomic_cxx11.h +++ b/src/corelib/arch/qatomic_cxx11.h @@ -78,11 +78,13 @@ template<> struct QAtomicOpsSupport<8> { enum { IsSupported = 1 }; }; #define Q_ATOMIC_INT16_FETCH_AND_STORE_IS_ALWAYS_NATIVE #define Q_ATOMIC_INT16_FETCH_AND_ADD_IS_ALWAYS_NATIVE -#define Q_ATOMIC_INT64_IS_SUPPORTED -#define Q_ATOMIC_INT64_REFERENCE_COUNTING_IS_ALWAYS_NATIVE -#define Q_ATOMIC_INT64_TEST_AND_SET_IS_ALWAYS_NATIVE -#define Q_ATOMIC_INT64_FETCH_AND_STORE_IS_ALWAYS_NATIVE -#define Q_ATOMIC_INT64_FETCH_AND_ADD_IS_ALWAYS_NATIVE +#ifndef QT_NO_STD_ATOMIC64 +# define Q_ATOMIC_INT64_IS_SUPPORTED +# define Q_ATOMIC_INT64_REFERENCE_COUNTING_IS_ALWAYS_NATIVE +# define Q_ATOMIC_INT64_TEST_AND_SET_IS_ALWAYS_NATIVE +# define Q_ATOMIC_INT64_FETCH_AND_STORE_IS_ALWAYS_NATIVE +# define Q_ATOMIC_INT64_FETCH_AND_ADD_IS_ALWAYS_NATIVE +#endif template struct QAtomicOps { diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index 3bf0546ac1..5df8f7d645 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. -** Copyright (C) 2014 Intel Corporation +** Copyright (C) 2015 Intel Corporation ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. @@ -192,6 +192,7 @@ Configure::Configure(int& argc, char** argv) dictionary[ "SYSTEM_PROXIES" ] = "no"; dictionary[ "WERROR" ] = "auto"; dictionary[ "QREAL" ] = "double"; + dictionary[ "ATOMIC64" ] = "auto"; //Only used when cross compiling. dictionary[ "QT_INSTALL_SETTINGS" ] = "/etc/xdg"; @@ -2195,6 +2196,12 @@ bool Configure::checkAvailability(const QString &part) else if (part == "OBJCOPY") available = tryCompileProject("unix/objcopy"); + else if (part == "ATOMIC64") + available = tryCompileProject("common/atomic64"); + + else if (part == "ATOMIC64-LIBATOMIC") + available = tryCompileProject("common/atomic64", "LIBS+=-latomic"); + else if (part == "ZLIB") available = findFile("zlib.h"); @@ -2343,6 +2350,10 @@ void Configure::autoDetection() dictionary["C++11"] = tryCompileProject("common/c++11") ? "yes" : "no"; } + if (dictionary["ATOMIC64"] == "auto") + dictionary["ATOMIC64"] = checkAvailability("ATOMIC64") ? "yes" : + checkAvailability("ATOMIC64-LIBATOMIC") ? "libatomic" : "no"; + // Style detection if (dictionary["STYLE_WINDOWSXP"] == "auto") dictionary["STYLE_WINDOWSXP"] = checkAvailability("STYLE_WINDOWSXP") ? defaultTo("STYLE_WINDOWSXP") : "no"; @@ -2862,6 +2873,9 @@ void Configure::generateOutputVars() } } + if (dictionary["ATOMIC64"] == "libatomic") + qmakeConfig += "atomic64-libatomic"; + if (dictionary[ "ACCESSIBILITY" ] == "yes") qtConfig += "accessibility"; @@ -3661,6 +3675,7 @@ void Configure::generateConfigfiles() if (dictionary["QT_GLIB"] == "no") qconfigList += "QT_NO_GLIB"; if (dictionary["QT_INOTIFY"] == "no") qconfigList += "QT_NO_INOTIFY"; if (dictionary["QT_EVENTFD"] == "no") qconfigList += "QT_NO_EVENTFD"; + if (dictionary["ATOMIC64"] == "no") qconfigList += "QT_NO_STD_ATOMIC64"; if (dictionary["REDUCE_EXPORTS"] == "yes") qconfigList += "QT_VISIBILITY_AVAILABLE"; if (dictionary["REDUCE_RELOCATIONS"] == "yes") qconfigList += "QT_REDUCE_RELOCATIONS"; -- cgit v1.2.3