aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/include/std/shared_mutex
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2015-03-18 10:53:38 +0000
committerJonathan Wakely <redi@gcc.gnu.org>2015-03-18 10:53:38 +0000
commit5e0216f173c1bef5bec3e709345d8170b1484d2f (patch)
tree589296fb247ee2147b0d907485aa46457dc7a4c8 /libstdc++-v3/include/std/shared_mutex
parent41cee85a347099bbd151f46cc55f8974970624ba (diff)
downloadgcc-5e0216f173c1bef5bec3e709345d8170b1484d2f.zip
gcc-5e0216f173c1bef5bec3e709345d8170b1484d2f.tar.gz
gcc-5e0216f173c1bef5bec3e709345d8170b1484d2f.tar.bz2
acinclude.m4 (GLIBCXX_CHECK_GTHREADS): Check for pthread_rwlock_t.
2015-03-18 Jonathan Wakely <jwakely@redhat.com> Torvald Riegel <triegel@redhat.com> * 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 <triegel@redhat.com> From-SVN: r221484
Diffstat (limited to 'libstdc++-v3/include/std/shared_mutex')
-rw-r--r--libstdc++-v3/include/std/shared_mutex51
1 files changed, 38 insertions, 13 deletions
diff --git a/libstdc++-v3/include/std/shared_mutex b/libstdc++-v3/include/std/shared_mutex
index 5dcc295..ab1b45b 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<long>(__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