* [patch libstdc++] Add POSIX variant of shared_timed_mutex.
@ 2015-01-16 13:20 Torvald Riegel
2015-01-16 13:31 ` Jonathan Wakely
0 siblings, 1 reply; 3+ messages in thread
From: Torvald Riegel @ 2015-01-16 13:20 UTC (permalink / raw)
To: GCC Patches; +Cc: jwakely
[-- Attachment #1: Type: text/plain, Size: 427 bytes --]
[Resend. Sorry for the noise on gcc@.]
This adds a POSIX-based implementation of shared_timed_mutex, using
pthread_rwlock_* operations directly instead of implementing with
mutexes and two condvars. This enables using an optimized
pthread_rwlock_t on POSIX.
Tested on x86_64-linux.
OK?
2015-01-16 Torvald Riegel <triegel@redhat.com>
* include/std/shared_mutex (shared_timed_mutex): Add POSIX-based
implementation.
[-- Attachment #2: shared_timed_mutex.patch --]
[-- Type: text/x-patch, Size: 6484 bytes --]
commit e0a32ddb058d8b4dd563f89130d03bce220ace8c
Author: Torvald Riegel <triegel@redhat.com>
Date: Thu Jan 15 22:29:23 2015 +0100
libstdc++: Add POSIX variant of shared_timed_mutex.
* include/std/shared_mutex (shared_timed_mutex): Add POSIX-based
implementation.
diff --git a/libstdc++-v3/include/std/shared_mutex b/libstdc++-v3/include/std/shared_mutex
index 8bfede3..643768c 100644
--- a/libstdc++-v3/include/std/shared_mutex
+++ b/libstdc++-v3/include/std/shared_mutex
@@ -57,6 +57,188 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// shared_timed_mutex
class shared_timed_mutex
{
+#if defined(__GTHREADS_CXX0X)
+ typedef chrono::system_clock __clock_t;
+
+ pthread_rwlock_t _M_rwlock;
+
+ public:
+ shared_timed_mutex()
+ {
+ int __ret = pthread_rwlock_init(&_M_rwlock, NULL);
+ if (__ret == ENOMEM)
+ throw bad_alloc();
+ else if (__ret == EAGAIN)
+ __throw_system_error(int(errc::resource_unavailable_try_again));
+ else if (__ret == EPERM)
+ __throw_system_error(int(errc::operation_not_permitted));
+ // Errors not handled: EBUSY, EINVAL
+ _GLIBCXX_DEBUG_ASSERT(__ret == 0);
+ }
+
+ ~shared_timed_mutex()
+ {
+ int __ret __attribute((unused)) = pthread_rwlock_destroy(&_M_rwlock);
+ // Errors not handled: EBUSY, EINVAL
+ _GLIBCXX_DEBUG_ASSERT(__ret == 0);
+ }
+
+ shared_timed_mutex(const shared_timed_mutex&) = delete;
+ shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
+
+ // Exclusive ownership
+
+ void
+ lock()
+ {
+ int __ret = pthread_rwlock_wrlock(&_M_rwlock);
+ if (__ret == EDEADLK)
+ __throw_system_error(int(errc::resource_deadlock_would_occur));
+ // Errors not handled: EINVAL
+ _GLIBCXX_DEBUG_ASSERT(__ret == 0);
+ }
+
+ bool
+ try_lock()
+ {
+ int __ret = pthread_rwlock_trywrlock(&_M_rwlock);
+ if (__ret == EBUSY) return false;
+ // Errors not handled: EINVAL
+ _GLIBCXX_DEBUG_ASSERT(__ret == 0);
+ return true;
+ }
+
+ template<typename _Rep, typename _Period>
+ bool
+ try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
+ {
+ return try_lock_until(__clock_t::now() + __rel_time);
+ }
+
+ template<typename _Duration>
+ bool
+ try_lock_until(const chrono::time_point<__clock_t, _Duration>& __atime)
+ {
+ auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+ auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+ __gthread_time_t __ts =
+ {
+ static_cast<std::time_t>(__s.time_since_epoch().count()),
+ static_cast<long>(__ns.count())
+ };
+
+ int __ret = pthread_rwlock_timedwrlock(&_M_rwlock, &__ts);
+ // On self-deadlock, we just fail to acquire the lock. Technically,
+ // the program violated the precondition.
+ if (__ret == ETIMEDOUT || __ret == EDEADLK)
+ return false;
+ // Errors not handled: EINVAL
+ _GLIBCXX_DEBUG_ASSERT(__ret == 0);
+ return true;
+ }
+
+ template<typename _Clock, typename _Duration>
+ bool
+ try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time)
+ {
+ // DR 887 - Sync unknown clock to known clock.
+ const typename _Clock::time_point __c_entry = _Clock::now();
+ const __clock_t::time_point __s_entry = __clock_t::now();
+ const auto __delta = __abs_time - __c_entry;
+ const auto __s_atime = __s_entry + __delta;
+ return try_lock_until(__s_atime);
+ }
+
+ void
+ unlock()
+ {
+ int __ret __attribute((unused)) = pthread_rwlock_unlock(&_M_rwlock);
+ // Errors not handled: EPERM, EBUSY, EINVAL
+ _GLIBCXX_DEBUG_ASSERT(__ret == 0);
+ }
+
+ // Shared ownership
+
+ void
+ lock_shared()
+ {
+ int __ret = pthread_rwlock_rdlock(&_M_rwlock);
+ 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);
+ }
+
+ bool
+ try_lock_shared()
+ {
+ int __ret = pthread_rwlock_tryrdlock(&_M_rwlock);
+ // If the maximum number of read locks has been exceeded, we just fail
+ // to acquire the lock. Unlike for lock(), we are not allowed to throw
+ // an exception.
+ if (__ret == EBUSY || __ret == EAGAIN) return false;
+ // Errors not handled: EINVAL
+ _GLIBCXX_DEBUG_ASSERT(__ret == 0);
+ return true;
+ }
+
+ template<typename _Rep, typename _Period>
+ bool
+ try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
+ {
+ return try_lock_shared_until(__clock_t::now() + __rel_time);
+ }
+
+ template<typename _Duration>
+ bool
+ try_lock_shared_until(const chrono::time_point<__clock_t,
+ _Duration>& __atime)
+ {
+ auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+ auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+ __gthread_time_t __ts =
+ {
+ static_cast<std::time_t>(__s.time_since_epoch().count()),
+ 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)
+ return false;
+ // Errors not handled: EINVAL
+ _GLIBCXX_DEBUG_ASSERT(__ret == 0);
+ return true;
+ }
+
+ template<typename _Clock, typename _Duration>
+ bool
+ try_lock_shared_until(const chrono::time_point<_Clock,
+ _Duration>& __abs_time)
+ {
+ // DR 887 - Sync unknown clock to known clock.
+ const typename _Clock::time_point __c_entry = _Clock::now();
+ const __clock_t::time_point __s_entry = __clock_t::now();
+ const auto __delta = __abs_time - __c_entry;
+ const auto __s_atime = __s_entry + __delta;
+ return try_lock_shared_until(__s_atime);
+ }
+
+ void
+ unlock_shared()
+ {
+ unlock();
+ }
+
+#else // defined(__GTHREADS_CXX0X)
+
#if _GTHREAD_USE_MUTEX_TIMEDLOCK
struct _Mutex : mutex, __timed_mutex_impl<_Mutex>
{
@@ -252,6 +434,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_M_gate1.notify_one();
}
}
+#endif // !defined(__GTHREADS_CXX0X)
};
#endif // _GLIBCXX_HAS_GTHREADS
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [patch libstdc++] Add POSIX variant of shared_timed_mutex.
2015-01-16 13:20 [patch libstdc++] Add POSIX variant of shared_timed_mutex Torvald Riegel
@ 2015-01-16 13:31 ` Jonathan Wakely
2015-01-16 13:55 ` Paolo Carlini
0 siblings, 1 reply; 3+ messages in thread
From: Jonathan Wakely @ 2015-01-16 13:31 UTC (permalink / raw)
To: Torvald Riegel; +Cc: GCC Patches, libstdc++
On 16/01/15 14:12 +0100, Torvald Riegel wrote:
>[Resend. Sorry for the noise on gcc@.]
>
>This adds a POSIX-based implementation of shared_timed_mutex, using
>pthread_rwlock_* operations directly instead of implementing with
>mutexes and two condvars. This enables using an optimized
>pthread_rwlock_t on POSIX.
>
>Tested on x86_64-linux.
>
>OK?
OK for trunk - thanks.
>diff --git a/libstdc++-v3/include/std/shared_mutex b/libstdc++-v3/include/std/shared_mutex
>index 8bfede3..643768c 100644
>--- a/libstdc++-v3/include/std/shared_mutex
>+++ b/libstdc++-v3/include/std/shared_mutex
>@@ -57,6 +57,188 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> /// shared_timed_mutex
> class shared_timed_mutex
> {
>+#if defined(__GTHREADS_CXX0X)
N.B. I advised Torvald that this macro was OK to check that we have
pthread_rwlock_t available. It's not strictly correct, but currently
only gthr-posix.h defines __GTHREADS_CXX0X so it works in practice. We
should come up with something better at a later date though, or if any
other gthreads model ever supports C++11 threads.
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [patch libstdc++] Add POSIX variant of shared_timed_mutex.
2015-01-16 13:31 ` Jonathan Wakely
@ 2015-01-16 13:55 ` Paolo Carlini
0 siblings, 0 replies; 3+ messages in thread
From: Paolo Carlini @ 2015-01-16 13:55 UTC (permalink / raw)
To: Jonathan Wakely, Torvald Riegel; +Cc: GCC Patches, libstdc++
Hi,
On 01/16/2015 02:18 PM, Jonathan Wakely wrote:
> +#if defined(__GTHREADS_CXX0X)
>
> N.B. I advised Torvald that this macro was OK to check that we have
> pthread_rwlock_t available. It's not strictly correct, but currently
> only gthr-posix.h defines __GTHREADS_CXX0X so it works in practice. We
> should come up with something better at a later date though, or if any
> other gthreads model ever supports C++11 threads.
Maybe add a comment summarizing the above?
Thanks,
Paolo.
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2015-01-16 13:49 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-16 13:20 [patch libstdc++] Add POSIX variant of shared_timed_mutex Torvald Riegel
2015-01-16 13:31 ` Jonathan Wakely
2015-01-16 13:55 ` Paolo Carlini
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).