From 5e0216f173c1bef5bec3e709345d8170b1484d2f Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Wed, 18 Mar 2015 10:53:38 +0000 Subject: [PATCH] acinclude.m4 (GLIBCXX_CHECK_GTHREADS): Check for pthread_rwlock_t. 2015-03-18 Jonathan Wakely Torvald Riegel * acinclude.m4 (GLIBCXX_CHECK_GTHREADS): Check for pthread_rwlock_t. * config.h.in: Regenerate. * configure: Regenerate. * include/std/shared_mutex: Check _GLIBCXX_USE_PTHREAD_RWLOCK_T. (shared_timed_mutex::_M_rwlock): Use PTHREAD_RWLOCK_INITIALIZER. (shared_timed_mutex::lock_shared()): Retry on EAGAIN. (shared_timed_mutex::try_lock_shared_until()): Retry on EAGAIN and EDEADLK. Co-Authored-By: Torvald Riegel From-SVN: r221484 --- libstdc++-v3/ChangeLog | 12 ++++ libstdc++-v3/acinclude.m4 | 7 +++ libstdc++-v3/config.h.in | 3 + libstdc++-v3/configure | 84 +++++++++++++++++++++++---- libstdc++-v3/include/std/shared_mutex | 51 +++++++++++----- 5 files changed, 134 insertions(+), 23 deletions(-) diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 103d7098adb..ae6445e3b86 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,15 @@ +2015-03-18 Jonathan Wakely + Torvald Riegel + + * acinclude.m4 (GLIBCXX_CHECK_GTHREADS): Check for pthread_rwlock_t. + * config.h.in: Regenerate. + * configure: Regenerate. + * include/std/shared_mutex: Check _GLIBCXX_USE_PTHREAD_RWLOCK_T. + (shared_timed_mutex::_M_rwlock): Use PTHREAD_RWLOCK_INITIALIZER. + (shared_timed_mutex::lock_shared()): Retry on EAGAIN. + (shared_timed_mutex::try_lock_shared_until()): Retry on EAGAIN and + EDEADLK. + 2015-03-17 Jonathan Wakely * libsupc++/nested_exception.h: Do not try to derive from final diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4 index 0b8c0f0b111..74f5a652fb7 100644 --- a/libstdc++-v3/acinclude.m4 +++ b/libstdc++-v3/acinclude.m4 @@ -3563,6 +3563,13 @@ AC_DEFUN([GLIBCXX_CHECK_GTHREADS], [ if test x"$ac_has_gthreads" = x"yes"; then AC_DEFINE(_GLIBCXX_HAS_GTHREADS, 1, [Define if gthreads library is available.]) + + # Also check for pthread_rwlock_t for std::shared_timed_mutex in C++14 + AC_CHECK_TYPE([pthread_rwlock_t], + [AC_DEFINE([_GLIBCXX_USE_PTHREAD_RWLOCK_T], 1, + [Define if POSIX read/write locks are available in .])], + [], + [#include "gthr.h"]) fi CXXFLAGS="$ac_save_CXXFLAGS" diff --git a/libstdc++-v3/config.h.in b/libstdc++-v3/config.h.in index adc7d44ee48..26ccd22de2d 100644 --- a/libstdc++-v3/config.h.in +++ b/libstdc++-v3/config.h.in @@ -851,6 +851,9 @@ /* Define if pthreads_num_processors_np is available in . */ #undef _GLIBCXX_USE_PTHREADS_NUM_PROCESSORS_NP +/* Define if POSIX read/write locks are available in . */ +#undef _GLIBCXX_USE_PTHREAD_RWLOCK_T + /* Define if /dev/random and /dev/urandom are available for the random_device of TR1 (Chapter 5.1). */ #undef _GLIBCXX_USE_RANDOM_TR1 diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure index bcdb93178b0..2507ff7e490 100755 --- a/libstdc++-v3/configure +++ b/libstdc++-v3/configure @@ -2498,6 +2498,60 @@ $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_type + +# ac_fn_cxx_check_type LINENO TYPE VAR INCLUDES +# --------------------------------------------- +# Tests whether TYPE exists after having included INCLUDES, setting cache +# variable VAR accordingly. +ac_fn_cxx_check_type () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof ($2)) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof (($2))) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + eval "$3=yes" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_cxx_check_type cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. @@ -11539,7 +11593,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11542 "configure" +#line 11596 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11645,7 +11699,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11648 "configure" +#line 11702 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -15065,7 +15119,7 @@ fi # # Fake what AC_TRY_COMPILE does. XXX Look at redoing this new-style. cat > conftest.$ac_ext << EOF -#line 15068 "configure" +#line 15122 "configure" struct S { ~S(); }; void bar(); void foo() @@ -15417,7 +15471,7 @@ $as_echo "$glibcxx_cv_atomic_long_long" >&6; } # Fake what AC_TRY_COMPILE does. cat > conftest.$ac_ext << EOF -#line 15420 "configure" +#line 15474 "configure" int main() { typedef bool atomic_type; @@ -15452,7 +15506,7 @@ $as_echo "$glibcxx_cv_atomic_bool" >&6; } rm -f conftest* cat > conftest.$ac_ext << EOF -#line 15455 "configure" +#line 15509 "configure" int main() { typedef short atomic_type; @@ -15487,7 +15541,7 @@ $as_echo "$glibcxx_cv_atomic_short" >&6; } rm -f conftest* cat > conftest.$ac_ext << EOF -#line 15490 "configure" +#line 15544 "configure" int main() { // NB: _Atomic_word not necessarily int. @@ -15523,7 +15577,7 @@ $as_echo "$glibcxx_cv_atomic_int" >&6; } rm -f conftest* cat > conftest.$ac_ext << EOF -#line 15526 "configure" +#line 15580 "configure" int main() { typedef long long atomic_type; @@ -15602,7 +15656,7 @@ $as_echo "$as_me: WARNING: Performance of certain classes will degrade as a resu # unnecessary for this test. cat > conftest.$ac_ext << EOF -#line 15605 "configure" +#line 15659 "configure" int main() { _Decimal32 d1; @@ -15644,7 +15698,7 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu # unnecessary for this test. cat > conftest.$ac_ext << EOF -#line 15647 "configure" +#line 15701 "configure" template struct same { typedef T2 type; }; @@ -15678,7 +15732,7 @@ $as_echo "$enable_int128" >&6; } rm -f conftest* cat > conftest.$ac_ext << EOF -#line 15681 "configure" +#line 15735 "configure" template struct same { typedef T2 type; }; @@ -78786,6 +78840,16 @@ $as_echo "$ac_has_gthreads" >&6; } $as_echo "#define _GLIBCXX_HAS_GTHREADS 1" >>confdefs.h + + # Also check for pthread_rwlock_t for std::shared_timed_mutex in C++14 + ac_fn_cxx_check_type "$LINENO" "pthread_rwlock_t" "ac_cv_type_pthread_rwlock_t" "#include \"gthr.h\" +" +if test "x$ac_cv_type_pthread_rwlock_t" = x""yes; then : + +$as_echo "#define _GLIBCXX_USE_PTHREAD_RWLOCK_T 1" >>confdefs.h + +fi + fi CXXFLAGS="$ac_save_CXXFLAGS" diff --git a/libstdc++-v3/include/std/shared_mutex b/libstdc++-v3/include/std/shared_mutex index 5dcc295746b..ab1b45b87ac 100644 --- a/libstdc++-v3/include/std/shared_mutex +++ b/libstdc++-v3/include/std/shared_mutex @@ -57,10 +57,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// shared_timed_mutex class shared_timed_mutex { -#if defined(__GTHREADS_CXX0X) +#ifdef _GLIBCXX_USE_PTHREAD_RWLOCK_T typedef chrono::system_clock __clock_t; - pthread_rwlock_t _M_rwlock; +#ifdef PTHREAD_RWLOCK_INITIALIZER + pthread_rwlock_t _M_rwlock = PTHREAD_RWLOCK_INITIALIZER; + + public: + shared_timed_mutex() = default; + ~shared_timed_mutex() = default; +#else + pthread_rwlock_t _M_rwlock; public: shared_timed_mutex() @@ -82,6 +89,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Errors not handled: EBUSY, EINVAL _GLIBCXX_DEBUG_ASSERT(__ret == 0); } +#endif shared_timed_mutex(const shared_timed_mutex&) = delete; shared_timed_mutex& operator=(const shared_timed_mutex&) = delete; @@ -165,12 +173,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void lock_shared() { - int __ret = pthread_rwlock_rdlock(&_M_rwlock); + int __ret; + // We retry if we exceeded the maximum number of read locks supported by + // the POSIX implementation; this can result in busy-waiting, but this + // is okay based on the current specification of forward progress + // guarantees by the standard. + do + __ret = pthread_rwlock_rdlock(&_M_rwlock); + while (__ret == EAGAIN); if (__ret == EDEADLK) __throw_system_error(int(errc::resource_deadlock_would_occur)); - if (__ret == EAGAIN) - // Maximum number of read locks has been exceeded. - __throw_system_error(int(errc::device_or_resource_busy)); // Errors not handled: EINVAL _GLIBCXX_DEBUG_ASSERT(__ret == 0); } @@ -210,11 +222,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static_cast(__ns.count()) }; - int __ret = pthread_rwlock_timedrdlock(&_M_rwlock, &__ts); - // If the maximum number of read locks has been exceeded, or we would - // deadlock, we just fail to acquire the lock. Unlike for lock(), - // we are not allowed to throw an exception. - if (__ret == ETIMEDOUT || __ret == EAGAIN || __ret == EDEADLK) + int __ret; + // Unlike for lock(), we are not allowed to throw an exception so if + // the maximum number of read locks has been exceeded, or we would + // deadlock, we just try to acquire the lock again (and will time out + // eventually). + // In cases where we would exceed the maximum number of read locks + // throughout the whole time until the timeout, we will fail to + // acquire the lock even if it would be logically free; however, this + // is allowed by the standard, and we made a "strong effort" + // (see C++14 30.4.1.4p26). + // For cases where the implementation detects a deadlock we + // intentionally block and timeout so that an early return isn't + // mistaken for a spurious failure, which might help users realise + // there is a deadlock. + do + __ret = pthread_rwlock_timedrdlock(&_M_rwlock, &__ts); + while (__ret == EAGAIN || __ret == EDEADLK); + if (__ret == ETIMEDOUT) return false; // Errors not handled: EINVAL _GLIBCXX_DEBUG_ASSERT(__ret == 0); @@ -241,7 +266,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION unlock(); } -#else // defined(__GTHREADS_CXX0X) +#else // ! _GLIBCXX_USE_PTHREAD_RWLOCK_T #if _GTHREAD_USE_MUTEX_TIMEDLOCK struct _Mutex : mutex, __timed_mutex_impl<_Mutex> @@ -438,7 +463,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_gate1.notify_one(); } } -#endif // !defined(__GTHREADS_CXX0X) +#endif // ! _GLIBCXX_USE_PTHREAD_RWLOCK_T }; #endif // _GLIBCXX_HAS_GTHREADS -- 2.30.2