diff options
author | Dan Albert <danalbert@google.com> | 2019-09-18 18:13:32 +0000 |
---|---|---|
committer | Dan Albert <danalbert@google.com> | 2019-09-18 18:13:32 +0000 |
commit | 85e26f56cbf3e1ae3aed155b817912f02172bbef (patch) | |
tree | d3e2a3990b8ccad3b5469822a6dfcc3a12b5f658 /libcxx/include | |
parent | 4b661f94e288b56f49579da2dea7a70cdf5b66e3 (diff) | |
download | bcm5719-llvm-85e26f56cbf3e1ae3aed155b817912f02172bbef.tar.gz bcm5719-llvm-85e26f56cbf3e1ae3aed155b817912f02172bbef.zip |
Revert "Revert "Implement std::condition_variable via pthread_cond_clockwait() where available""
With the fix for non-Linux.
This reverts commit c1c519d2f1a66dd2eeaa4c321d8d7b50f623eb71.
llvm-svn: 372242
Diffstat (limited to 'libcxx/include')
-rw-r--r-- | libcxx/include/__config | 10 | ||||
-rw-r--r-- | libcxx/include/__mutex_base | 145 |
2 files changed, 138 insertions, 17 deletions
diff --git a/libcxx/include/__config b/libcxx/include/__config index 0a5e8e5ddf4..ee7351e9313 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -1087,6 +1087,16 @@ _LIBCPP_FUNC_VIS extern "C" void __sanitizer_annotate_contiguous_container( # endif // _LIBCPP_HAS_THREAD_API #endif // _LIBCPP_HAS_NO_THREADS +#if defined(_LIBCPP_HAS_THREAD_API_PTHREAD) +#if defined(__ANDROID__) && __ANDROID_API__ >= 30 +#define _LIBCPP_HAS_COND_CLOCKWAIT +#elif defined(_LIBCPP_GLIBC_PREREQ) +#if _LIBCPP_GLIBC_PREREQ(2, 30) +#define _LIBCPP_HAS_COND_CLOCKWAIT +#endif +#endif +#endif + #if defined(_LIBCPP_HAS_NO_THREADS) && defined(_LIBCPP_HAS_THREAD_API_PTHREAD) #error _LIBCPP_HAS_THREAD_API_PTHREAD may only be defined when \ _LIBCPP_HAS_NO_THREADS is not defined. diff --git a/libcxx/include/__mutex_base b/libcxx/include/__mutex_base index a85ded8341e..a4ac36161cb 100644 --- a/libcxx/include/__mutex_base +++ b/libcxx/include/__mutex_base @@ -15,6 +15,7 @@ #include <system_error> #include <__threading_support> +#include <time.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header @@ -337,23 +338,75 @@ public: private: void __do_timed_wait(unique_lock<mutex>& __lk, chrono::time_point<chrono::system_clock, chrono::nanoseconds>) _NOEXCEPT; +#if defined(_LIBCPP_HAS_COND_CLOCKWAIT) + void __do_timed_wait(unique_lock<mutex>& __lk, + chrono::time_point<chrono::steady_clock, chrono::nanoseconds>) _NOEXCEPT; +#endif + template <class _Clock> + void __do_timed_wait(unique_lock<mutex>& __lk, + chrono::time_point<_Clock, chrono::nanoseconds>) _NOEXCEPT; }; #endif // !_LIBCPP_HAS_NO_THREADS -template <class _To, class _Rep, class _Period> +template <class _Rep, class _Period> inline _LIBCPP_INLINE_VISIBILITY typename enable_if < - chrono::__is_duration<_To>::value, - _To + is_floating_point<_Rep>::value, + chrono::nanoseconds >::type -__ceil(chrono::duration<_Rep, _Period> __d) +__safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d) { using namespace chrono; - _To __r = duration_cast<_To>(__d); - if (__r < __d) - ++__r; - return __r; + using __ratio = ratio_divide<_Period, nano>; + using __ns_rep = nanoseconds::rep; + _Rep __result_float = __d.count() * __ratio::num / __ratio::den; + + _Rep __result_max = numeric_limits<__ns_rep>::max(); + if (__result_float >= __result_max) { + return nanoseconds::max(); + } + + _Rep __result_min = numeric_limits<__ns_rep>::min(); + if (__result_float <= __result_min) { + return nanoseconds::min(); + } + + return nanoseconds(static_cast<__ns_rep>(__result_float)); +} + +template <class _Rep, class _Period> +inline _LIBCPP_INLINE_VISIBILITY +typename enable_if +< + !is_floating_point<_Rep>::value, + chrono::nanoseconds +>::type +__safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d) +{ + using namespace chrono; + if (__d.count() == 0) { + return nanoseconds(0); + } + + using __ratio = ratio_divide<_Period, nano>; + using __ns_rep = nanoseconds::rep; + __ns_rep __result_max = std::numeric_limits<__ns_rep>::max(); + if (__d.count() > 0 && __d.count() > __result_max / __ratio::num) { + return nanoseconds::max(); + } + + __ns_rep __result_min = std::numeric_limits<__ns_rep>::min(); + if (__d.count() < 0 && __d.count() < __result_min / __ratio::num) { + return nanoseconds::min(); + } + + __ns_rep __result = __d.count() * __ratio::num / __ratio::den; + if (__result == 0) { + return nanoseconds(1); + } + + return nanoseconds(__result); } #ifndef _LIBCPP_HAS_NO_THREADS @@ -371,7 +424,15 @@ condition_variable::wait_until(unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t) { using namespace chrono; - wait_for(__lk, __t - _Clock::now()); + using __clock_tp_ns = time_point<_Clock, nanoseconds>; + + typename _Clock::time_point __now = _Clock::now(); + if (__t <= __now) + return cv_status::timeout; + + __clock_tp_ns __t_ns = __clock_tp_ns(__safe_nanosecond_cast(__t.time_since_epoch())); + + __do_timed_wait(__lk, __t_ns); return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout; } @@ -397,15 +458,25 @@ condition_variable::wait_for(unique_lock<mutex>& __lk, using namespace chrono; if (__d <= __d.zero()) return cv_status::timeout; - typedef time_point<system_clock, duration<long double, nano> > __sys_tpf; - typedef time_point<system_clock, nanoseconds> __sys_tpi; - __sys_tpf _Max = __sys_tpi::max(); + using __ns_rep = nanoseconds::rep; steady_clock::time_point __c_now = steady_clock::now(); - system_clock::time_point __s_now = system_clock::now(); - if (_Max - __d > __s_now) - __do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__d)); - else - __do_timed_wait(__lk, __sys_tpi::max()); + +#if defined(_LIBCPP_HAS_COND_CLOCKWAIT) + using __clock_tp_ns = time_point<steady_clock, nanoseconds>; + __ns_rep __now_count_ns = __safe_nanosecond_cast(__c_now.time_since_epoch()).count(); +#else + using __clock_tp_ns = time_point<system_clock, nanoseconds>; + __ns_rep __now_count_ns = __safe_nanosecond_cast(system_clock::now().time_since_epoch()).count(); +#endif + + __ns_rep __d_ns_count = __safe_nanosecond_cast(__d).count(); + + if (__now_count_ns > numeric_limits<__ns_rep>::max() - __d_ns_count) { + __do_timed_wait(__lk, __clock_tp_ns::max()); + } else { + __do_timed_wait(__lk, __clock_tp_ns(nanoseconds(__now_count_ns + __d_ns_count))); + } + return steady_clock::now() - __c_now < __d ? cv_status::no_timeout : cv_status::timeout; } @@ -421,6 +492,46 @@ condition_variable::wait_for(unique_lock<mutex>& __lk, _VSTD::move(__pred)); } +#if defined(_LIBCPP_HAS_COND_CLOCKWAIT) +inline +void +condition_variable::__do_timed_wait(unique_lock<mutex>& __lk, + chrono::time_point<chrono::steady_clock, chrono::nanoseconds> __tp) _NOEXCEPT +{ + using namespace chrono; + if (!__lk.owns_lock()) + __throw_system_error(EPERM, + "condition_variable::timed wait: mutex not locked"); + nanoseconds __d = __tp.time_since_epoch(); + timespec __ts; + seconds __s = duration_cast<seconds>(__d); + using __ts_sec = decltype(__ts.tv_sec); + const __ts_sec __ts_sec_max = numeric_limits<__ts_sec>::max(); + if (__s.count() < __ts_sec_max) + { + __ts.tv_sec = static_cast<__ts_sec>(__s.count()); + __ts.tv_nsec = (__d - __s).count(); + } + else + { + __ts.tv_sec = __ts_sec_max; + __ts.tv_nsec = giga::num - 1; + } + int __ec = pthread_cond_clockwait(&__cv_, __lk.mutex()->native_handle(), CLOCK_MONOTONIC, &__ts); + if (__ec != 0 && __ec != ETIMEDOUT) + __throw_system_error(__ec, "condition_variable timed_wait failed"); +} +#endif // _LIBCPP_HAS_COND_CLOCKWAIT + +template <class _Clock> +inline +void +condition_variable::__do_timed_wait(unique_lock<mutex>& __lk, + chrono::time_point<_Clock, chrono::nanoseconds> __tp) _NOEXCEPT +{ + wait_for(__lk, __tp - _Clock::now()); +} + #endif // !_LIBCPP_HAS_NO_THREADS _LIBCPP_END_NAMESPACE_STD |