diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 4de7cc85174..fd61db5c9ee 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,28 @@ +2018-11-27 Jonathan Wakely + + PR libstdc++/67843 + * acinclude.m4 (GLIBCXX_ENABLE_LOCK_POLICY): Add new macro + that defines _GLIBCXX_HAVE_ATOMIC_LOCK_POLICY. + * config.h.in: Regenerate. + * configure: Regenerate. + * configure.ac: Use GLIBCXX_ENABLE_LOCK_POLICY. + * doc/xml/manual/configure.xml: Document new configure option. + * include/bits/fs_dir.h (directory_iterator): Use __shared_ptr + instead of shared_ptr. + (recursive_directory_iterator): Likewise. + (__shared_ptr<_Dir>): Add explicit instantiation declaration. + (__shared_ptr): Likewise. + * include/bits/shared_ptr_base.h (__allocate_shared, __make_shared): + Add default template argument for _Lock_policy template parameter. + * include/ext/concurrence.h (__default_lock_policy): Check macro + _GLIBCXX_HAVE_ATOMIC_LOCK_POLICY instead of checking if the current + target supports the builtins for compare-and-swap. + * src/filesystem/std-dir.cc (__shared_ptr<_Dir>): Add explicit + instantiation definition. + (__shared_ptr): Likewise. + (directory_iterator, recursive_directory_iterator): Use __make_shared + instead of make_shared. + 2018-11-27 François Dumont PR libstdc++/88199 diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4 index 82a25e5f2f1..6bcd29dc8c3 100644 --- a/libstdc++-v3/acinclude.m4 +++ b/libstdc++-v3/acinclude.m4 @@ -3562,6 +3562,72 @@ EOF ]) +dnl +dnl Set default lock policy for synchronizing shared_ptr reference counting. +dnl +dnl --with-libstdcxx-lock-policy=auto +dnl Use atomic operations for shared_ptr reference counting only if +dnl the default target supports atomic compare-and-swap. +dnl --with-libstdcxx-lock-policy=atomic +dnl Use atomic operations for shared_ptr reference counting. +dnl --with-libstdcxx-lock-policy=mutex +dnl Use a mutex to synchronize shared_ptr reference counting. +dnl +dnl This controls the value of __gnu_cxx::__default_lock_policy, which +dnl determines how shared_ptr reference counts are synchronized. +dnl The option "atomic" means that atomic operations should be used, +dnl "mutex" means that a mutex will be used. The default option, "auto", +dnl will check if the target supports the compiler-generated builtins +dnl for atomic compare-and-swap operations for 2-byte and 4-byte integers, +dnl and will use "atomic" if supported, "mutex" otherwise. +dnl This option is ignored if the thread model used by GCC is "single", +dnl as no synchronization is used at all in that case. +dnl This option affects the library ABI (except in the "single" thread model). +dnl +dnl Defines _GLIBCXX_HAVE_ATOMIC_LOCK_POLICY to 1 if atomics should be used. +dnl +AC_DEFUN([GLIBCXX_ENABLE_LOCK_POLICY], [ + + AC_ARG_WITH([libstdcxx-lock-policy], + AC_HELP_STRING([--with-libstdcxx-lock-policy={atomic,mutex,auto}], + [synchronization policy for shared_ptr reference counting [default=auto]]), + [libstdcxx_atomic_lock_policy=$withval], + [libstdcxx_atomic_lock_policy=auto]) + + case "$libstdcxx_atomic_lock_policy" in + atomic|mutex|auto) ;; + *) AC_MSG_ERROR([Invalid argument for --with-libstdcxx-lock-policy]) ;; + esac + AC_MSG_CHECKING([for lock policy for shared_ptr reference counts]) + + if test x"$libstdcxx_atomic_lock_policy" = x"auto"; then + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + ac_save_CXXFLAGS="$CXXFLAGS" + + dnl Why do we care about 2-byte CAS on targets with 4-byte _Atomic_word?! + AC_TRY_COMPILE([ + #if ! defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 + # error "No 2-byte compare-and-swap" + #elif ! defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 + # error "No 4-byte compare-and-swap" + #endif + ],, + [libstdcxx_atomic_lock_policy=atomic], + [libstdcxx_atomic_lock_policy=mutex]) + AC_LANG_RESTORE + CXXFLAGS="$ac_save_CXXFLAGS" + fi + + if test x"$libstdcxx_atomic_lock_policy" = x"atomic"; then + AC_MSG_RESULT(atomic) + AC_DEFINE(HAVE_ATOMIC_LOCK_POLICY,1, + [Defined if shared_ptr reference counting should use atomic operations.]) + else + AC_MSG_RESULT(mutex) + fi + +]) dnl dnl Allow visibility attributes to be used on namespaces, objects, etc. diff --git a/libstdc++-v3/config.h.in b/libstdc++-v3/config.h.in index fa69b7a0895..9c45c8c6628 100644 --- a/libstdc++-v3/config.h.in +++ b/libstdc++-v3/config.h.in @@ -33,6 +33,9 @@ /* Define to 1 if you have the `atanl' function. */ #undef HAVE_ATANL +/* Defined if shared_ptr reference counting should use atomic operations. */ +#undef HAVE_ATOMIC_LOCK_POLICY + /* Define to 1 if you have the `at_quick_exit' function. */ #undef HAVE_AT_QUICK_EXIT diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure index 39f83e239d7..77805e8680f 100755 --- a/libstdc++-v3/configure +++ b/libstdc++-v3/configure @@ -907,6 +907,7 @@ enable_libtool_lock enable_hosted_libstdcxx enable_libstdcxx_verbose enable_libstdcxx_pch +with_libstdcxx_lock_policy enable_cstdio enable_clocale enable_nls @@ -1652,6 +1653,9 @@ Optional Packages: --with-pic try to use only PIC/non-PIC objects [default=use both] --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-libstdcxx-lock-policy={atomic,mutex,auto} + synchronization policy for shared_ptr reference + counting [default=auto] --with-python-dir the location to install Python modules. This path is relative starting from the prefix. --with-gnu-ld assume the C compiler uses GNU ld default=no @@ -11840,7 +11844,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11843 "configure" +#line 11847 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11946,7 +11950,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11949 "configure" +#line 11953 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -15632,7 +15636,7 @@ $as_echo "$glibcxx_cv_atomic_long_long" >&6; } # Fake what AC_TRY_COMPILE does. cat > conftest.$ac_ext << EOF -#line 15635 "configure" +#line 15639 "configure" int main() { typedef bool atomic_type; @@ -15667,7 +15671,7 @@ $as_echo "$glibcxx_cv_atomic_bool" >&6; } rm -f conftest* cat > conftest.$ac_ext << EOF -#line 15670 "configure" +#line 15674 "configure" int main() { typedef short atomic_type; @@ -15702,7 +15706,7 @@ $as_echo "$glibcxx_cv_atomic_short" >&6; } rm -f conftest* cat > conftest.$ac_ext << EOF -#line 15705 "configure" +#line 15709 "configure" int main() { // NB: _Atomic_word not necessarily int. @@ -15738,7 +15742,7 @@ $as_echo "$glibcxx_cv_atomic_int" >&6; } rm -f conftest* cat > conftest.$ac_ext << EOF -#line 15741 "configure" +#line 15745 "configure" int main() { typedef long long atomic_type; @@ -15815,11 +15819,83 @@ $as_echo "$as_me: WARNING: Performance of certain classes will degrade as a resu + +# Check whether --with-libstdcxx-lock-policy was given. +if test "${with_libstdcxx_lock_policy+set}" = set; then : + withval=$with_libstdcxx_lock_policy; libstdcxx_atomic_lock_policy=$withval +else + libstdcxx_atomic_lock_policy=auto +fi + + + case "$libstdcxx_atomic_lock_policy" in + atomic|mutex|auto) ;; + *) as_fn_error $? "Invalid argument for --with-libstdcxx-lock-policy" "$LINENO" 5 ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lock policy for shared_ptr reference counts" >&5 +$as_echo_n "checking for lock policy for shared_ptr reference counts... " >&6; } + + if test x"$libstdcxx_atomic_lock_policy" = x"auto"; then + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + ac_save_CXXFLAGS="$CXXFLAGS" + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #if ! defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 + # error "No 2-byte compare-and-swap" + #elif ! defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 + # error "No 4-byte compare-and-swap" + #endif + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + libstdcxx_atomic_lock_policy=atomic +else + libstdcxx_atomic_lock_policy=mutex +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + CXXFLAGS="$ac_save_CXXFLAGS" + fi + + if test x"$libstdcxx_atomic_lock_policy" = x"atomic"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: atomic" >&5 +$as_echo "atomic" >&6; } + +$as_echo "#define HAVE_ATOMIC_LOCK_POLICY 1" >>confdefs.h + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: mutex" >&5 +$as_echo "mutex" >&6; } + fi + + + + # Fake what AC_TRY_COMPILE does, without linking as this is # unnecessary for this test. cat > conftest.$ac_ext << EOF -#line 15822 "configure" +#line 15898 "configure" int main() { _Decimal32 d1; @@ -15861,7 +15937,7 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu # unnecessary for this test. cat > conftest.$ac_ext << EOF -#line 15864 "configure" +#line 15940 "configure" template struct same { typedef T2 type; }; @@ -15895,7 +15971,7 @@ $as_echo "$enable_int128" >&6; } rm -f conftest* cat > conftest.$ac_ext << EOF -#line 15898 "configure" +#line 15974 "configure" template struct same { typedef T2 type; }; diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac index a657a726778..ad5b4117cfd 100644 --- a/libstdc++-v3/configure.ac +++ b/libstdc++-v3/configure.ac @@ -149,6 +149,7 @@ GLIBCXX_ENABLE_VERBOSE GLIBCXX_ENABLE_PCH($is_hosted) GLIBCXX_ENABLE_THREADS GLIBCXX_ENABLE_ATOMIC_BUILTINS +GLIBCXX_ENABLE_LOCK_POLICY GLIBCXX_ENABLE_DECIMAL_FLOAT GLIBCXX_ENABLE_INT128_FLOAT128 if test "$enable_float128" = yes; then diff --git a/libstdc++-v3/doc/xml/manual/configure.xml b/libstdc++-v3/doc/xml/manual/configure.xml index ac383cf7fa7..d296c8d8a49 100644 --- a/libstdc++-v3/doc/xml/manual/configure.xml +++ b/libstdc++-v3/doc/xml/manual/configure.xml @@ -399,6 +399,28 @@ + --with-libstdcxx-lock-policy=OPTION + Sets the lock policy that controls how + shared_ptr reference counting is + synchronized. + The choice OPTION=atomic enables use of atomics for updates to + shared_ptr reference counts. + The choice OPTION=mutex enables use of a mutex to synchronize updates + to shared_ptr reference counts. + If the compiler's thread model is "single" then this option has no + effect, as no synchronization is used for the reference counts. + The default is OPTION=auto, which checks for the availability of + compiler built-ins for 2-byte and 4-byte atomic compare-and-swap, + and uses OPTION=atomic if they're available, OPTION=mutex otherwise. + This option can change the library ABI. + If the library is configured to use atomics and user programs are + compiled using a target that doesn't natively support the atomic + operations (e.g. the library is configured for armv7 and then code + is compiled with ) then the program + might rely on support in libgcc to provide the atomics. + + + --enable-vtable-verify[default] Use -fvtable-verify=std to compile the C++ diff --git a/libstdc++-v3/include/bits/fs_dir.h b/libstdc++-v3/include/bits/fs_dir.h index 9ee1cb66b61..2f81a1709e4 100644 --- a/libstdc++-v3/include/bits/fs_dir.h +++ b/libstdc++-v3/include/bits/fs_dir.h @@ -403,7 +403,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 friend class recursive_directory_iterator; - std::shared_ptr<_Dir> _M_dir; + std::__shared_ptr<_Dir> _M_dir; }; inline directory_iterator @@ -494,7 +494,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 const recursive_directory_iterator& __rhs); struct _Dir_stack; - std::shared_ptr<_Dir_stack> _M_dirs; + std::__shared_ptr<_Dir_stack> _M_dirs; directory_options _M_options = {}; bool _M_pending = false; }; @@ -525,6 +525,14 @@ _GLIBCXX_END_NAMESPACE_CXX11 // @} group filesystem } // namespace filesystem + // Use explicit instantiations of these types. Any inconsistency in the + // value of __default_lock_policy between code including this header and + // the library will cause a linker error. + extern template class + __shared_ptr; + extern template class + __shared_ptr; + _GLIBCXX_END_NAMESPACE_VERSION } // namespace std diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h b/libstdc++-v3/include/bits/shared_ptr_base.h index 46ff4a7cf29..21debf362aa 100644 --- a/libstdc++-v3/include/bits/shared_ptr_base.h +++ b/libstdc++-v3/include/bits/shared_ptr_base.h @@ -1803,7 +1803,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION mutable __weak_ptr<_Tp, _Lp> _M_weak_this; }; - template + template inline __shared_ptr<_Tp, _Lp> __allocate_shared(const _Alloc& __a, _Args&&... __args) { @@ -1811,7 +1812,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::forward<_Args>(__args)...); } - template + template inline __shared_ptr<_Tp, _Lp> __make_shared(_Args&&... __args) { diff --git a/libstdc++-v3/include/ext/concurrence.h b/libstdc++-v3/include/ext/concurrence.h index 302cddfa473..33ad9e06c9f 100644 --- a/libstdc++-v3/include/ext/concurrence.h +++ b/libstdc++-v3/include/ext/concurrence.h @@ -51,16 +51,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Compile time constant that indicates prefered locking policy in // the current configuration. static const _Lock_policy __default_lock_policy = -#ifdef __GTHREADS -#if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) \ - && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)) +#ifndef __GTHREADS + _S_single; +#elif defined _GLIBCXX_HAVE_ATOMIC_LOCK_POLICY _S_atomic; #else _S_mutex; #endif -#else - _S_single; -#endif // NB: As this is used in libsupc++, need to only depend on // exception. No stdexception classes, no use of std::string. diff --git a/libstdc++-v3/src/filesystem/std-dir.cc b/libstdc++-v3/src/filesystem/std-dir.cc index 4c9a287ad80..038f635a712 100644 --- a/libstdc++-v3/src/filesystem/std-dir.cc +++ b/libstdc++-v3/src/filesystem/std-dir.cc @@ -39,6 +39,9 @@ namespace fs = std::filesystem; namespace posix = std::filesystem::__gnu_posix; +template class std::__shared_ptr; +template class std::__shared_ptr; + struct fs::_Dir : _Dir_base { _Dir(const fs::path& p, bool skip_permission_denied, error_code& ec) @@ -125,7 +128,7 @@ directory_iterator(const path& p, directory_options options, error_code* ecptr) if (dir.dirp) { - auto sp = std::make_shared(std::move(dir)); + auto sp = std::__make_shared(std::move(dir)); if (sp->advance(skip_permission_denied, ec)) _M_dir.swap(sp); } @@ -185,7 +188,7 @@ recursive_directory_iterator(const path& p, directory_options options, { if (ecptr) ecptr->clear(); - auto sp = std::make_shared<_Dir_stack>(); + auto sp = std::__make_shared<_Dir_stack>(); sp->push(_Dir{ dirp, p }); if (ecptr ? sp->top().advance(*ecptr) : sp->top().advance()) _M_dirs.swap(sp);