File indexing completed on 2026-05-03 08:13:16
0001
0002
0003
0004
0005
0006
0007
0008
0009 #ifndef _LIBCPP___CONDITION_VARIABLE_CONDITION_VARIABLE_H
0010 #define _LIBCPP___CONDITION_VARIABLE_CONDITION_VARIABLE_H
0011
0012 #include <__chrono/duration.h>
0013 #include <__chrono/steady_clock.h>
0014 #include <__chrono/system_clock.h>
0015 #include <__chrono/time_point.h>
0016 #include <__config>
0017 #include <__mutex/mutex.h>
0018 #include <__mutex/unique_lock.h>
0019 #include <__system_error/throw_system_error.h>
0020 #include <__thread/support.h>
0021 #include <__type_traits/enable_if.h>
0022 #include <__type_traits/is_floating_point.h>
0023 #include <__utility/move.h>
0024 #include <limits>
0025 #include <ratio>
0026
0027 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
0028 # pragma GCC system_header
0029 #endif
0030
0031 _LIBCPP_PUSH_MACROS
0032 #include <__undef_macros>
0033
0034 _LIBCPP_BEGIN_NAMESPACE_STD
0035
0036 #if _LIBCPP_HAS_THREADS
0037
0038
0039 _LIBCPP_DECLARE_STRONG_ENUM(cv_status){no_timeout, timeout};
0040 _LIBCPP_DECLARE_STRONG_ENUM_EPILOG(cv_status)
0041
0042 class _LIBCPP_EXPORTED_FROM_ABI condition_variable {
0043 __libcpp_condvar_t __cv_ = _LIBCPP_CONDVAR_INITIALIZER;
0044
0045 public:
0046 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR condition_variable() _NOEXCEPT = default;
0047
0048 # if _LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION
0049 ~condition_variable() = default;
0050 # else
0051 ~condition_variable();
0052 # endif
0053
0054 condition_variable(const condition_variable&) = delete;
0055 condition_variable& operator=(const condition_variable&) = delete;
0056
0057 void notify_one() _NOEXCEPT;
0058 void notify_all() _NOEXCEPT;
0059
0060 void wait(unique_lock<mutex>& __lk) _NOEXCEPT;
0061 template <class _Predicate>
0062 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS void wait(unique_lock<mutex>& __lk, _Predicate __pred);
0063
0064 template <class _Clock, class _Duration>
0065 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS cv_status
0066 wait_until(unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t);
0067
0068 template <class _Clock, class _Duration, class _Predicate>
0069 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool
0070 wait_until(unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t, _Predicate __pred);
0071
0072 template <class _Rep, class _Period>
0073 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS cv_status
0074 wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d);
0075
0076 template <class _Rep, class _Period, class _Predicate>
0077 bool _LIBCPP_HIDE_FROM_ABI
0078 wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d, _Predicate __pred);
0079
0080 typedef __libcpp_condvar_t* native_handle_type;
0081 _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return &__cv_; }
0082
0083 private:
0084 void
0085 __do_timed_wait(unique_lock<mutex>& __lk, chrono::time_point<chrono::system_clock, chrono::nanoseconds>) _NOEXCEPT;
0086 # if _LIBCPP_HAS_COND_CLOCKWAIT
0087 _LIBCPP_HIDE_FROM_ABI void
0088 __do_timed_wait(unique_lock<mutex>& __lk, chrono::time_point<chrono::steady_clock, chrono::nanoseconds>) _NOEXCEPT;
0089 # endif
0090 template <class _Clock>
0091 _LIBCPP_HIDE_FROM_ABI void
0092 __do_timed_wait(unique_lock<mutex>& __lk, chrono::time_point<_Clock, chrono::nanoseconds>) _NOEXCEPT;
0093 };
0094 #endif
0095
0096 template <class _Rep, class _Period, __enable_if_t<is_floating_point<_Rep>::value, int> = 0>
0097 inline _LIBCPP_HIDE_FROM_ABI chrono::nanoseconds __safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d) {
0098 using namespace chrono;
0099 using __ratio = ratio_divide<_Period, nano>;
0100 using __ns_rep = nanoseconds::rep;
0101 _Rep __result_float = __d.count() * __ratio::num / __ratio::den;
0102
0103 _Rep __result_max = numeric_limits<__ns_rep>::max();
0104 if (__result_float >= __result_max) {
0105 return nanoseconds::max();
0106 }
0107
0108 _Rep __result_min = numeric_limits<__ns_rep>::min();
0109 if (__result_float <= __result_min) {
0110 return nanoseconds::min();
0111 }
0112
0113 return nanoseconds(static_cast<__ns_rep>(__result_float));
0114 }
0115
0116 template <class _Rep, class _Period, __enable_if_t<!is_floating_point<_Rep>::value, int> = 0>
0117 inline _LIBCPP_HIDE_FROM_ABI chrono::nanoseconds __safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d) {
0118 using namespace chrono;
0119 if (__d.count() == 0) {
0120 return nanoseconds(0);
0121 }
0122
0123 using __ratio = ratio_divide<_Period, nano>;
0124 using __ns_rep = nanoseconds::rep;
0125 __ns_rep __result_max = numeric_limits<__ns_rep>::max();
0126 if (__d.count() > 0 && __d.count() > __result_max / __ratio::num) {
0127 return nanoseconds::max();
0128 }
0129
0130 __ns_rep __result_min = numeric_limits<__ns_rep>::min();
0131 if (__d.count() < 0 && __d.count() < __result_min / __ratio::num) {
0132 return nanoseconds::min();
0133 }
0134
0135 __ns_rep __result = __d.count() * __ratio::num / __ratio::den;
0136 if (__result == 0) {
0137 return nanoseconds(1);
0138 }
0139
0140 return nanoseconds(__result);
0141 }
0142
0143 #if _LIBCPP_HAS_THREADS
0144 template <class _Predicate>
0145 void condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred) {
0146 while (!__pred())
0147 wait(__lk);
0148 }
0149
0150 template <class _Clock, class _Duration>
0151 cv_status condition_variable::wait_until(unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t) {
0152 using namespace chrono;
0153 using __clock_tp_ns = time_point<_Clock, nanoseconds>;
0154
0155 typename _Clock::time_point __now = _Clock::now();
0156 if (__t <= __now)
0157 return cv_status::timeout;
0158
0159 __clock_tp_ns __t_ns = __clock_tp_ns(std::__safe_nanosecond_cast(__t.time_since_epoch()));
0160
0161 __do_timed_wait(__lk, __t_ns);
0162 return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
0163 }
0164
0165 template <class _Clock, class _Duration, class _Predicate>
0166 bool condition_variable::wait_until(
0167 unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t, _Predicate __pred) {
0168 while (!__pred()) {
0169 if (wait_until(__lk, __t) == cv_status::timeout)
0170 return __pred();
0171 }
0172 return true;
0173 }
0174
0175 template <class _Rep, class _Period>
0176 cv_status condition_variable::wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d) {
0177 using namespace chrono;
0178 if (__d <= __d.zero())
0179 return cv_status::timeout;
0180 using __ns_rep = nanoseconds::rep;
0181 steady_clock::time_point __c_now = steady_clock::now();
0182
0183 # if _LIBCPP_HAS_COND_CLOCKWAIT
0184 using __clock_tp_ns = time_point<steady_clock, nanoseconds>;
0185 __ns_rep __now_count_ns = std::__safe_nanosecond_cast(__c_now.time_since_epoch()).count();
0186 # else
0187 using __clock_tp_ns = time_point<system_clock, nanoseconds>;
0188 __ns_rep __now_count_ns = std::__safe_nanosecond_cast(system_clock::now().time_since_epoch()).count();
0189 # endif
0190
0191 __ns_rep __d_ns_count = std::__safe_nanosecond_cast(__d).count();
0192
0193 if (__now_count_ns > numeric_limits<__ns_rep>::max() - __d_ns_count) {
0194 __do_timed_wait(__lk, __clock_tp_ns::max());
0195 } else {
0196 __do_timed_wait(__lk, __clock_tp_ns(nanoseconds(__now_count_ns + __d_ns_count)));
0197 }
0198
0199 return steady_clock::now() - __c_now < __d ? cv_status::no_timeout : cv_status::timeout;
0200 }
0201
0202 template <class _Rep, class _Period, class _Predicate>
0203 inline bool
0204 condition_variable::wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d, _Predicate __pred) {
0205 return wait_until(__lk, chrono::steady_clock::now() + __d, std::move(__pred));
0206 }
0207
0208 # if _LIBCPP_HAS_COND_CLOCKWAIT
0209 inline void condition_variable::__do_timed_wait(
0210 unique_lock<mutex>& __lk, chrono::time_point<chrono::steady_clock, chrono::nanoseconds> __tp) _NOEXCEPT {
0211 using namespace chrono;
0212 if (!__lk.owns_lock())
0213 __throw_system_error(EPERM, "condition_variable::timed wait: mutex not locked");
0214 nanoseconds __d = __tp.time_since_epoch();
0215 timespec __ts;
0216 seconds __s = duration_cast<seconds>(__d);
0217 using __ts_sec = decltype(__ts.tv_sec);
0218 const __ts_sec __ts_sec_max = numeric_limits<__ts_sec>::max();
0219 if (__s.count() < __ts_sec_max) {
0220 __ts.tv_sec = static_cast<__ts_sec>(__s.count());
0221 __ts.tv_nsec = (__d - __s).count();
0222 } else {
0223 __ts.tv_sec = __ts_sec_max;
0224 __ts.tv_nsec = giga::num - 1;
0225 }
0226 int __ec = pthread_cond_clockwait(&__cv_, __lk.mutex()->native_handle(), CLOCK_MONOTONIC, &__ts);
0227 if (__ec != 0 && __ec != ETIMEDOUT)
0228 __throw_system_error(__ec, "condition_variable timed_wait failed");
0229 }
0230 # endif
0231
0232 template <class _Clock>
0233 inline void condition_variable::__do_timed_wait(unique_lock<mutex>& __lk,
0234 chrono::time_point<_Clock, chrono::nanoseconds> __tp) _NOEXCEPT {
0235 wait_for(__lk, __tp - _Clock::now());
0236 }
0237
0238 #endif
0239
0240 _LIBCPP_END_NAMESPACE_STD
0241
0242 _LIBCPP_POP_MACROS
0243
0244 #endif