#include <chrono>
#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
+#include <exception> // std::terminate
#include <sys/time.h>
#endif
return __atomic_wait_status::timeout;
}
}
-#endif
+#else // ! FUTEX
#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
template<typename _Duration>
__atomic_wait_status
- __cond_wait_until_impl(__gthread_cond_t* __cv,
- unique_lock<mutex>& __lock,
+ __cond_wait_until_impl(__condvar& __cv, mutex& __mx,
const chrono::time_point<chrono::steady_clock, _Duration>& __atime)
{
auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
static_cast<long>(__ns.count())
};
- pthread_cond_clockwait(__cv, __lock.mutex()->native_handle(),
- CLOCK_MONOTONIC,
- &__ts);
+ __cv.wait_until(__mx, CLOCK_MONOTONIC, __ts);
+
return (chrono::steady_clock::now() < __atime)
? __atomic_wait_status::no_timeout
: __atomic_wait_status::timeout;
}
#endif
- template<typename _Duration>
- __atomic_wait_status
- __cond_wait_until_impl(__gthread_cond_t* __cv,
- unique_lock<std::mutex>& __lock,
- const chrono::time_point<chrono::system_clock, _Duration>& __atime)
+ template<typename _Duration>
+ __atomic_wait_status
+ __cond_wait_until_impl(__condvar& __cv, mutex& __mx,
+ const chrono::time_point<chrono::system_clock, _Duration>& __atime)
+ {
+ auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+ auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+ __gthread_time_t __ts =
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+ static_cast<std::time_t>(__s.time_since_epoch().count()),
+ static_cast<long>(__ns.count())
+ };
- __gthread_time_t __ts =
- {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
+ __cv.wait_until(__mx, __ts);
- __gthread_cond_timedwait(__cv, __lock.mutex()->native_handle(),
- &__ts);
- return (chrono::system_clock::now() < __atime)
- ? __atomic_wait_status::no_timeout
- : __atomic_wait_status::timeout;
- }
+ return (chrono::system_clock::now() < __atime)
+ ? __atomic_wait_status::no_timeout
+ : __atomic_wait_status::timeout;
+ }
- // return true if timeout
- template<typename _Clock, typename _Duration>
- __atomic_wait_status
- __cond_wait_until(__gthread_cond_t* __cv,
- unique_lock<std::mutex>& __lock,
- const chrono::time_point<_Clock, _Duration>& __atime)
- {
+ // return true if timeout
+ template<typename _Clock, typename _Duration>
+ __atomic_wait_status
+ __cond_wait_until(__condvar& __cv, mutex& __mx,
+ const chrono::time_point<_Clock, _Duration>& __atime)
+ {
#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
- using __clock_t = chrono::steady_clock;
+ using __clock_t = chrono::steady_clock;
#else
- using __clock_t = chrono::system_clock;
+ using __clock_t = chrono::system_clock;
#endif
- const typename _Clock::time_point __c_entry = _Clock::now();
- const __clock_t::time_point __s_entry = __clock_t::now();
- const auto __delta = __atime - __c_entry;
- const auto __s_atime = __s_entry + __delta;
- if (std::__detail::__cond_wait_until_impl(__cv, __lock, __s_atime))
- return __atomic_wait_status::no_timeout;
- // We got a timeout when measured against __clock_t but
- // we need to check against the caller-supplied clock
- // to tell whether we should return a timeout.
- if (_Clock::now() < __atime)
- return __atomic_wait_status::no_timeout;
- return __atomic_wait_status::timeout;
- }
+ const typename _Clock::time_point __c_entry = _Clock::now();
+ const __clock_t::time_point __s_entry = __clock_t::now();
+ const auto __delta = __atime - __c_entry;
+ const auto __s_atime = __s_entry + __delta;
+ if (__detail::__cond_wait_until_impl(__cv, __mx, __s_atime)
+ == __atomic_wait_status::no_timeout)
+ return __atomic_wait_status::no_timeout;
+ // We got a timeout when measured against __clock_t but
+ // we need to check against the caller-supplied clock
+ // to tell whether we should return a timeout.
+ if (_Clock::now() < __atime)
+ return __atomic_wait_status::no_timeout;
+ return __atomic_wait_status::timeout;
+ }
+#endif // FUTEX
struct __timed_waiters : __waiters
{
__waiters::__lock_t __l(_M_mtx);
while (__cur <= __version)
{
- if (__detail::__cond_wait_until(&_M_cv, __l, __atime)
+ if (__detail::__cond_wait_until(_M_cv, _M_mtx, __atime)
== __atomic_wait_status::timeout)
return __atomic_wait_status::timeout;
if (__reltime < __rtime)
++__reltime;
-
return __atomic_wait_until(__addr, __old, std::move(__pred),
chrono::steady_clock::now() + __reltime);
}
#if defined _GLIBCXX_HAS_GTHREADS || _GLIBCXX_HAVE_LINUX_FUTEX
#include <bits/functional_hash.h>
#include <bits/gthr.h>
-#include <bits/std_mutex.h>
-#include <bits/unique_lock.h>
#include <ext/numeric_traits.h>
#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
-#include <climits>
-#include <unistd.h>
-#include <syscall.h>
+# include <cerrno>
+# include <climits>
+# include <unistd.h>
+# include <syscall.h>
+# include <bits/functexcept.h>
+// TODO get this from Autoconf
+# define _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE 1
+#else
+# include <bits/std_mutex.h> // std::mutex, std::__condvar
#endif
-// TODO get this from Autoconf
-#define _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE 1
-
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
constexpr auto __atomic_spin_count_1 = 16;
constexpr auto __atomic_spin_count_2 = 12;
- inline constexpr
- auto __platform_wait_max_value =
- __gnu_cxx::__int_traits<__platform_wait_t>::__max;
-
template<typename _Tp>
inline constexpr bool __platform_wait_uses_type
#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
struct __waiters
{
- alignas(64) __platform_wait_t _M_ver = 0;
- alignas(64) __platform_wait_t _M_wait = 0;
+ alignas(64) __platform_wait_t _M_ver = 0;
+ alignas(64) __platform_wait_t _M_wait = 0;
#ifndef _GLIBCXX_HAVE_LINUX_FUTEX
- using __lock_t = std::unique_lock<std::mutex>;
- mutable __lock_t::mutex_type _M_mtx;
+ using __lock_t = lock_guard<mutex>;
+ mutex _M_mtx;
+ __condvar _M_cv;
-# ifdef __GTHREAD_COND_INIT
- mutable __gthread_cond_t _M_cv = __GTHREAD_COND_INIT;
__waiters() noexcept = default;
-# else
- mutable __gthread_cond_t _M_cv;
- __waiters() noexcept
- {
- __GTHREAD_COND_INIT_FUNCTION(&_M_cv);
- }
-# endif
#endif
__platform_wait_t
while (__cur <= __version)
{
__waiters::__lock_t __l(_M_mtx);
- auto __e = __gthread_cond_wait(&_M_cv, __l.mutex()->native_handle());
- if (__e)
- __throw_system_error(__e);
+ _M_cv.wait(_M_mtx);
__platform_wait_t __last = __cur;
__atomic_load(&_M_ver, &__cur, __ATOMIC_ACQUIRE);
if (__cur < __last)
#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
__platform_notify(&_M_ver, __all);
#else
- auto __e = __gthread_cond_broadcast(&_M_cv);
- if (__e)
- __throw_system_error(__e);
+ if (__all)
+ _M_cv.notify_all();
+ else
+ _M_cv.notify_one();
#endif
}
{ return &_M_mutex; }
};
+ // Implementation details for std::condition_variable
+ class __condvar
+ {
+ using timespec = __gthread_time_t;
+
+ public:
+ __condvar() noexcept
+ {
+#ifndef __GTHREAD_COND_INIT
+ __GTHREAD_COND_INIT_FUNCTION(&_M_cond);
+#endif
+ }
+
+ ~__condvar()
+ {
+ int __e __attribute__((__unused__)) = __gthread_cond_destroy(&_M_cond);
+ __glibcxx_assert(__e != EBUSY); // threads are still blocked
+ }
+
+ __condvar(const __condvar&) = delete;
+ __condvar& operator=(const __condvar&) = delete;
+
+ __gthread_cond_t* native_handle() noexcept { return &_M_cond; }
+
+ // Expects: Calling thread has locked __m.
+ void
+ wait(mutex& __m) noexcept
+ {
+ int __e __attribute__((__unused__))
+ = __gthread_cond_wait(&_M_cond, __m.native_handle());
+ __glibcxx_assert(__e == 0);
+ }
+
+ void
+ wait_until(mutex& __m, timespec& __abs_time) noexcept
+ {
+ __gthread_cond_timedwait(&_M_cond, __m.native_handle(), &__abs_time);
+ }
+
+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
+ void
+ wait_until(mutex& __m, clockid_t __clock, timespec& __abs_time) noexcept
+ {
+ pthread_cond_clockwait(&_M_cond, __m.native_handle(), __clock,
+ &__abs_time);
+ }
+#endif
+
+ void
+ notify_one() noexcept
+ {
+ int __e __attribute__((__unused__)) = __gthread_cond_signal(&_M_cond);
+ __glibcxx_assert(__e == 0);
+ }
+
+ void
+ notify_all() noexcept
+ {
+ int __e __attribute__((__unused__)) = __gthread_cond_broadcast(&_M_cond);
+ __glibcxx_assert(__e == 0);
+ }
+
+ protected:
+#ifdef __GTHREAD_COND_INIT
+ __gthread_cond_t _M_cond = __GTHREAD_COND_INIT;
+#else
+ __gthread_cond_t _M_cond;
+#endif
+ };
+
#endif // _GLIBCXX_HAS_GTHREADS
/// Do not acquire ownership of the mutex.
#else
using __clock_t = system_clock;
#endif
- typedef __gthread_cond_t __native_type;
-#ifdef __GTHREAD_COND_INIT
- __native_type _M_cond = __GTHREAD_COND_INIT;
-#else
- __native_type _M_cond;
-#endif
+ __condvar _M_cond;
public:
- typedef __native_type* native_handle_type;
+ typedef __gthread_cond_t* native_handle_type;
condition_variable() noexcept;
~condition_variable() noexcept;
native_handle_type
native_handle()
- { return &_M_cond; }
+ { return _M_cond.native_handle(); }
private:
#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
static_cast<long>(__ns.count())
};
- pthread_cond_clockwait(&_M_cond, __lock.mutex()->native_handle(),
- CLOCK_MONOTONIC,
- &__ts);
+ _M_cond.wait_until(*__lock.mutex(), CLOCK_MONOTONIC, __ts);
return (steady_clock::now() < __atime
? cv_status::no_timeout : cv_status::timeout);
static_cast<long>(__ns.count())
};
- __gthread_cond_timedwait(&_M_cond, __lock.mutex()->native_handle(),
- &__ts);
+ _M_cond.wait_until(*__lock.mutex(), __ts);
return (system_clock::now() < __atime
? cv_status::no_timeout : cv_status::timeout);
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
-#ifdef __GTHREAD_COND_INIT
condition_variable::condition_variable() noexcept = default;
-#else
- condition_variable::condition_variable() noexcept
- {
- __GTHREAD_COND_INIT_FUNCTION(&_M_cond);
- }
-#endif
- condition_variable::~condition_variable() noexcept
- {
- // XXX no thread blocked
- /* int __e = */ __gthread_cond_destroy(&_M_cond);
- // if __e == EBUSY then blocked
- }
+ condition_variable::~condition_variable() noexcept = default;
void
condition_variable::wait(unique_lock<mutex>& __lock) noexcept
{
- int __e = __gthread_cond_wait(&_M_cond, __lock.mutex()->native_handle());
-
- if (__e)
- std::terminate();
+ _M_cond.wait(*__lock.mutex());
}
void
condition_variable::notify_one() noexcept
{
- int __e = __gthread_cond_signal(&_M_cond);
-
- // XXX not in spec
- // EINVAL
- if (__e)
- __throw_system_error(__e);
+ _M_cond.notify_one();
}
void
condition_variable::notify_all() noexcept
{
- int __e = __gthread_cond_broadcast(&_M_cond);
-
- // XXX not in spec
- // EINVAL
- if (__e)
- __throw_system_error(__e);
+ _M_cond.notify_all();
}
extern void