condition_variable.h 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. //===----------------------------------------------------------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #ifndef _LIBCPP___CONDITION_VARIABLE_CONDITION_VARIABLE_H
  9. #define _LIBCPP___CONDITION_VARIABLE_CONDITION_VARIABLE_H
  10. #include <__chrono/steady_clock.h>
  11. #include <__chrono/system_clock.h>
  12. #include <__chrono/time_point.h>
  13. #include <__config>
  14. #include <__mutex/mutex.h>
  15. #include <__mutex/unique_lock.h>
  16. #include <__system_error/system_error.h>
  17. #include <__threading_support>
  18. #include <__type_traits/enable_if.h>
  19. #include <__type_traits/is_floating_point.h>
  20. #include <__utility/move.h>
  21. #include <limits>
  22. #include <ratio>
  23. #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
  24. # pragma GCC system_header
  25. #endif
  26. _LIBCPP_PUSH_MACROS
  27. #include <__undef_macros>
  28. _LIBCPP_BEGIN_NAMESPACE_STD
  29. #ifndef _LIBCPP_HAS_NO_THREADS
  30. // enum class cv_status
  31. _LIBCPP_DECLARE_STRONG_ENUM(cv_status){no_timeout, timeout};
  32. _LIBCPP_DECLARE_STRONG_ENUM_EPILOG(cv_status)
  33. class _LIBCPP_EXPORTED_FROM_ABI condition_variable {
  34. __libcpp_condvar_t __cv_ = _LIBCPP_CONDVAR_INITIALIZER;
  35. public:
  36. _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR condition_variable() _NOEXCEPT = default;
  37. # ifdef _LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION
  38. ~condition_variable() = default;
  39. # else
  40. ~condition_variable();
  41. # endif
  42. condition_variable(const condition_variable&) = delete;
  43. condition_variable& operator=(const condition_variable&) = delete;
  44. void notify_one() _NOEXCEPT;
  45. void notify_all() _NOEXCEPT;
  46. void wait(unique_lock<mutex>& __lk) _NOEXCEPT;
  47. template <class _Predicate>
  48. _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS void wait(unique_lock<mutex>& __lk, _Predicate __pred);
  49. template <class _Clock, class _Duration>
  50. _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS cv_status
  51. wait_until(unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t);
  52. template <class _Clock, class _Duration, class _Predicate>
  53. _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool
  54. wait_until(unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t, _Predicate __pred);
  55. template <class _Rep, class _Period>
  56. _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS cv_status
  57. wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d);
  58. template <class _Rep, class _Period, class _Predicate>
  59. bool _LIBCPP_HIDE_FROM_ABI
  60. wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d, _Predicate __pred);
  61. typedef __libcpp_condvar_t* native_handle_type;
  62. _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return &__cv_; }
  63. private:
  64. void
  65. __do_timed_wait(unique_lock<mutex>& __lk, chrono::time_point<chrono::system_clock, chrono::nanoseconds>) _NOEXCEPT;
  66. # if defined(_LIBCPP_HAS_COND_CLOCKWAIT)
  67. _LIBCPP_HIDE_FROM_ABI void
  68. __do_timed_wait(unique_lock<mutex>& __lk, chrono::time_point<chrono::steady_clock, chrono::nanoseconds>) _NOEXCEPT;
  69. # endif
  70. template <class _Clock>
  71. _LIBCPP_HIDE_FROM_ABI void
  72. __do_timed_wait(unique_lock<mutex>& __lk, chrono::time_point<_Clock, chrono::nanoseconds>) _NOEXCEPT;
  73. };
  74. #endif // !_LIBCPP_HAS_NO_THREADS
  75. template <class _Rep, class _Period, __enable_if_t<is_floating_point<_Rep>::value, int> = 0>
  76. inline _LIBCPP_HIDE_FROM_ABI chrono::nanoseconds __safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d) {
  77. using namespace chrono;
  78. using __ratio = ratio_divide<_Period, nano>;
  79. using __ns_rep = nanoseconds::rep;
  80. _Rep __result_float = __d.count() * __ratio::num / __ratio::den;
  81. _Rep __result_max = numeric_limits<__ns_rep>::max();
  82. if (__result_float >= __result_max) {
  83. return nanoseconds::max();
  84. }
  85. _Rep __result_min = numeric_limits<__ns_rep>::min();
  86. if (__result_float <= __result_min) {
  87. return nanoseconds::min();
  88. }
  89. return nanoseconds(static_cast<__ns_rep>(__result_float));
  90. }
  91. template <class _Rep, class _Period, __enable_if_t<!is_floating_point<_Rep>::value, int> = 0>
  92. inline _LIBCPP_HIDE_FROM_ABI chrono::nanoseconds __safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d) {
  93. using namespace chrono;
  94. if (__d.count() == 0) {
  95. return nanoseconds(0);
  96. }
  97. using __ratio = ratio_divide<_Period, nano>;
  98. using __ns_rep = nanoseconds::rep;
  99. __ns_rep __result_max = numeric_limits<__ns_rep>::max();
  100. if (__d.count() > 0 && __d.count() > __result_max / __ratio::num) {
  101. return nanoseconds::max();
  102. }
  103. __ns_rep __result_min = numeric_limits<__ns_rep>::min();
  104. if (__d.count() < 0 && __d.count() < __result_min / __ratio::num) {
  105. return nanoseconds::min();
  106. }
  107. __ns_rep __result = __d.count() * __ratio::num / __ratio::den;
  108. if (__result == 0) {
  109. return nanoseconds(1);
  110. }
  111. return nanoseconds(__result);
  112. }
  113. #ifndef _LIBCPP_HAS_NO_THREADS
  114. template <class _Predicate>
  115. void condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred) {
  116. while (!__pred())
  117. wait(__lk);
  118. }
  119. template <class _Clock, class _Duration>
  120. cv_status condition_variable::wait_until(unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t) {
  121. using namespace chrono;
  122. using __clock_tp_ns = time_point<_Clock, nanoseconds>;
  123. typename _Clock::time_point __now = _Clock::now();
  124. if (__t <= __now)
  125. return cv_status::timeout;
  126. __clock_tp_ns __t_ns = __clock_tp_ns(std::__safe_nanosecond_cast(__t.time_since_epoch()));
  127. __do_timed_wait(__lk, __t_ns);
  128. return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
  129. }
  130. template <class _Clock, class _Duration, class _Predicate>
  131. bool condition_variable::wait_until(
  132. unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t, _Predicate __pred) {
  133. while (!__pred()) {
  134. if (wait_until(__lk, __t) == cv_status::timeout)
  135. return __pred();
  136. }
  137. return true;
  138. }
  139. template <class _Rep, class _Period>
  140. cv_status condition_variable::wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d) {
  141. using namespace chrono;
  142. if (__d <= __d.zero())
  143. return cv_status::timeout;
  144. using __ns_rep = nanoseconds::rep;
  145. steady_clock::time_point __c_now = steady_clock::now();
  146. # if defined(_LIBCPP_HAS_COND_CLOCKWAIT)
  147. using __clock_tp_ns = time_point<steady_clock, nanoseconds>;
  148. __ns_rep __now_count_ns = std::__safe_nanosecond_cast(__c_now.time_since_epoch()).count();
  149. # else
  150. using __clock_tp_ns = time_point<system_clock, nanoseconds>;
  151. __ns_rep __now_count_ns = std::__safe_nanosecond_cast(system_clock::now().time_since_epoch()).count();
  152. # endif
  153. __ns_rep __d_ns_count = std::__safe_nanosecond_cast(__d).count();
  154. if (__now_count_ns > numeric_limits<__ns_rep>::max() - __d_ns_count) {
  155. __do_timed_wait(__lk, __clock_tp_ns::max());
  156. } else {
  157. __do_timed_wait(__lk, __clock_tp_ns(nanoseconds(__now_count_ns + __d_ns_count)));
  158. }
  159. return steady_clock::now() - __c_now < __d ? cv_status::no_timeout : cv_status::timeout;
  160. }
  161. template <class _Rep, class _Period, class _Predicate>
  162. inline bool
  163. condition_variable::wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d, _Predicate __pred) {
  164. return wait_until(__lk, chrono::steady_clock::now() + __d, std::move(__pred));
  165. }
  166. # if defined(_LIBCPP_HAS_COND_CLOCKWAIT)
  167. inline void condition_variable::__do_timed_wait(
  168. unique_lock<mutex>& __lk, chrono::time_point<chrono::steady_clock, chrono::nanoseconds> __tp) _NOEXCEPT {
  169. using namespace chrono;
  170. if (!__lk.owns_lock())
  171. __throw_system_error(EPERM, "condition_variable::timed wait: mutex not locked");
  172. nanoseconds __d = __tp.time_since_epoch();
  173. timespec __ts;
  174. seconds __s = duration_cast<seconds>(__d);
  175. using __ts_sec = decltype(__ts.tv_sec);
  176. const __ts_sec __ts_sec_max = numeric_limits<__ts_sec>::max();
  177. if (__s.count() < __ts_sec_max) {
  178. __ts.tv_sec = static_cast<__ts_sec>(__s.count());
  179. __ts.tv_nsec = (__d - __s).count();
  180. } else {
  181. __ts.tv_sec = __ts_sec_max;
  182. __ts.tv_nsec = giga::num - 1;
  183. }
  184. int __ec = pthread_cond_clockwait(&__cv_, __lk.mutex()->native_handle(), CLOCK_MONOTONIC, &__ts);
  185. if (__ec != 0 && __ec != ETIMEDOUT)
  186. __throw_system_error(__ec, "condition_variable timed_wait failed");
  187. }
  188. # endif // _LIBCPP_HAS_COND_CLOCKWAIT
  189. template <class _Clock>
  190. inline void condition_variable::__do_timed_wait(unique_lock<mutex>& __lk,
  191. chrono::time_point<_Clock, chrono::nanoseconds> __tp) _NOEXCEPT {
  192. wait_for(__lk, __tp - _Clock::now());
  193. }
  194. #endif // _LIBCPP_HAS_NO_THREADS
  195. _LIBCPP_END_NAMESPACE_STD
  196. _LIBCPP_POP_MACROS
  197. #endif // _LIBCPP___CONDITION_VARIABLE_CONDITION_VARIABLE_H