+2018-11-27 Jonathan Wakely <jwakely@redhat.com>
+
+ 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<recursive_directory_iterator::_Dir_stack>): 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<recursive_directory_iterator::_Dir_stack>): Likewise.
+ (directory_iterator, recursive_directory_iterator): Use __make_shared
+ instead of make_shared.
+
2018-11-27 François Dumont <fdumont@gcc.gnu.org>
PR libstdc++/88199
])
+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.
/* 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
enable_hosted_libstdcxx
enable_libstdcxx_verbose
enable_libstdcxx_pch
+with_libstdcxx_lock_policy
enable_cstdio
enable_clocale
enable_nls
--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
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
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
# Fake what AC_TRY_COMPILE does.
cat > conftest.$ac_ext << EOF
-#line 15635 "configure"
+#line 15639 "configure"
int main()
{
typedef bool atomic_type;
rm -f conftest*
cat > conftest.$ac_ext << EOF
-#line 15670 "configure"
+#line 15674 "configure"
int main()
{
typedef short atomic_type;
rm -f conftest*
cat > conftest.$ac_ext << EOF
-#line 15705 "configure"
+#line 15709 "configure"
int main()
{
// NB: _Atomic_word not necessarily int.
rm -f conftest*
cat > conftest.$ac_ext << EOF
-#line 15741 "configure"
+#line 15745 "configure"
int main()
{
typedef long long atomic_type;
+
+# 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;
# unnecessary for this test.
cat > conftest.$ac_ext << EOF
-#line 15864 "configure"
+#line 15940 "configure"
template<typename T1, typename T2>
struct same
{ typedef T2 type; };
rm -f conftest*
cat > conftest.$ac_ext << EOF
-#line 15898 "configure"
+#line 15974 "configure"
template<typename T1, typename T2>
struct same
{ typedef T2 type; };
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
</para>
</listitem></varlistentry>
+ <varlistentry><term><code>--with-libstdcxx-lock-policy=OPTION</code></term>
+ <listitem><para>Sets the lock policy that controls how
+ <classname>shared_ptr</classname> reference counting is
+ synchronized.
+ The choice OPTION=atomic enables use of atomics for updates to
+ <classname>shared_ptr</classname> reference counts.
+ The choice OPTION=mutex enables use of a mutex to synchronize updates
+ to <classname>shared_ptr</classname> 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 <option>-march=armv5t</option>) then the program
+ might rely on support in libgcc to provide the atomics.
+ </para>
+ </listitem></varlistentry>
+
<varlistentry><term><code>--enable-vtable-verify</code>[default]</term>
<listitem>
<para>Use <code>-fvtable-verify=std</code> to compile the C++
friend class recursive_directory_iterator;
- std::shared_ptr<_Dir> _M_dir;
+ std::__shared_ptr<_Dir> _M_dir;
};
inline directory_iterator
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;
};
// @} 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<filesystem::_Dir>;
+ extern template class
+ __shared_ptr<filesystem::recursive_directory_iterator::_Dir_stack>;
+
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
mutable __weak_ptr<_Tp, _Lp> _M_weak_this;
};
- template<typename _Tp, _Lock_policy _Lp, typename _Alloc, typename... _Args>
+ template<typename _Tp, _Lock_policy _Lp = __default_lock_policy,
+ typename _Alloc, typename... _Args>
inline __shared_ptr<_Tp, _Lp>
__allocate_shared(const _Alloc& __a, _Args&&... __args)
{
std::forward<_Args>(__args)...);
}
- template<typename _Tp, _Lock_policy _Lp, typename... _Args>
+ template<typename _Tp, _Lock_policy _Lp = __default_lock_policy,
+ typename... _Args>
inline __shared_ptr<_Tp, _Lp>
__make_shared(_Args&&... __args)
{
// 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.
namespace fs = std::filesystem;
namespace posix = std::filesystem::__gnu_posix;
+template class std::__shared_ptr<fs::_Dir>;
+template class std::__shared_ptr<fs::recursive_directory_iterator::_Dir_stack>;
+
struct fs::_Dir : _Dir_base
{
_Dir(const fs::path& p, bool skip_permission_denied, error_code& ec)
if (dir.dirp)
{
- auto sp = std::make_shared<fs::_Dir>(std::move(dir));
+ auto sp = std::__make_shared<fs::_Dir>(std::move(dir));
if (sp->advance(skip_permission_denied, ec))
_M_dir.swap(sp);
}
{
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);