Path: blob/main/contrib/llvm-project/libcxx/include/__condition_variable/condition_variable.h
35234 views
//===----------------------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#ifndef _LIBCPP___CONDITION_VARIABLE_CONDITION_VARIABLE_H9#define _LIBCPP___CONDITION_VARIABLE_CONDITION_VARIABLE_H1011#include <__chrono/duration.h>12#include <__chrono/steady_clock.h>13#include <__chrono/system_clock.h>14#include <__chrono/time_point.h>15#include <__config>16#include <__mutex/mutex.h>17#include <__mutex/unique_lock.h>18#include <__system_error/system_error.h>19#include <__thread/support.h>20#include <__type_traits/enable_if.h>21#include <__type_traits/is_floating_point.h>22#include <__utility/move.h>23#include <limits>24#include <ratio>2526#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)27# pragma GCC system_header28#endif2930_LIBCPP_PUSH_MACROS31#include <__undef_macros>3233_LIBCPP_BEGIN_NAMESPACE_STD3435#ifndef _LIBCPP_HAS_NO_THREADS3637// enum class cv_status38_LIBCPP_DECLARE_STRONG_ENUM(cv_status){no_timeout, timeout};39_LIBCPP_DECLARE_STRONG_ENUM_EPILOG(cv_status)4041class _LIBCPP_EXPORTED_FROM_ABI condition_variable {42__libcpp_condvar_t __cv_ = _LIBCPP_CONDVAR_INITIALIZER;4344public:45_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR condition_variable() _NOEXCEPT = default;4647# ifdef _LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION48~condition_variable() = default;49# else50~condition_variable();51# endif5253condition_variable(const condition_variable&) = delete;54condition_variable& operator=(const condition_variable&) = delete;5556void notify_one() _NOEXCEPT;57void notify_all() _NOEXCEPT;5859void wait(unique_lock<mutex>& __lk) _NOEXCEPT;60template <class _Predicate>61_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS void wait(unique_lock<mutex>& __lk, _Predicate __pred);6263template <class _Clock, class _Duration>64_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS cv_status65wait_until(unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t);6667template <class _Clock, class _Duration, class _Predicate>68_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool69wait_until(unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t, _Predicate __pred);7071template <class _Rep, class _Period>72_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS cv_status73wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d);7475template <class _Rep, class _Period, class _Predicate>76bool _LIBCPP_HIDE_FROM_ABI77wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d, _Predicate __pred);7879typedef __libcpp_condvar_t* native_handle_type;80_LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return &__cv_; }8182private:83void84__do_timed_wait(unique_lock<mutex>& __lk, chrono::time_point<chrono::system_clock, chrono::nanoseconds>) _NOEXCEPT;85# if defined(_LIBCPP_HAS_COND_CLOCKWAIT)86_LIBCPP_HIDE_FROM_ABI void87__do_timed_wait(unique_lock<mutex>& __lk, chrono::time_point<chrono::steady_clock, chrono::nanoseconds>) _NOEXCEPT;88# endif89template <class _Clock>90_LIBCPP_HIDE_FROM_ABI void91__do_timed_wait(unique_lock<mutex>& __lk, chrono::time_point<_Clock, chrono::nanoseconds>) _NOEXCEPT;92};93#endif // !_LIBCPP_HAS_NO_THREADS9495template <class _Rep, class _Period, __enable_if_t<is_floating_point<_Rep>::value, int> = 0>96inline _LIBCPP_HIDE_FROM_ABI chrono::nanoseconds __safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d) {97using namespace chrono;98using __ratio = ratio_divide<_Period, nano>;99using __ns_rep = nanoseconds::rep;100_Rep __result_float = __d.count() * __ratio::num / __ratio::den;101102_Rep __result_max = numeric_limits<__ns_rep>::max();103if (__result_float >= __result_max) {104return nanoseconds::max();105}106107_Rep __result_min = numeric_limits<__ns_rep>::min();108if (__result_float <= __result_min) {109return nanoseconds::min();110}111112return nanoseconds(static_cast<__ns_rep>(__result_float));113}114115template <class _Rep, class _Period, __enable_if_t<!is_floating_point<_Rep>::value, int> = 0>116inline _LIBCPP_HIDE_FROM_ABI chrono::nanoseconds __safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d) {117using namespace chrono;118if (__d.count() == 0) {119return nanoseconds(0);120}121122using __ratio = ratio_divide<_Period, nano>;123using __ns_rep = nanoseconds::rep;124__ns_rep __result_max = numeric_limits<__ns_rep>::max();125if (__d.count() > 0 && __d.count() > __result_max / __ratio::num) {126return nanoseconds::max();127}128129__ns_rep __result_min = numeric_limits<__ns_rep>::min();130if (__d.count() < 0 && __d.count() < __result_min / __ratio::num) {131return nanoseconds::min();132}133134__ns_rep __result = __d.count() * __ratio::num / __ratio::den;135if (__result == 0) {136return nanoseconds(1);137}138139return nanoseconds(__result);140}141142#ifndef _LIBCPP_HAS_NO_THREADS143template <class _Predicate>144void condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred) {145while (!__pred())146wait(__lk);147}148149template <class _Clock, class _Duration>150cv_status condition_variable::wait_until(unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t) {151using namespace chrono;152using __clock_tp_ns = time_point<_Clock, nanoseconds>;153154typename _Clock::time_point __now = _Clock::now();155if (__t <= __now)156return cv_status::timeout;157158__clock_tp_ns __t_ns = __clock_tp_ns(std::__safe_nanosecond_cast(__t.time_since_epoch()));159160__do_timed_wait(__lk, __t_ns);161return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;162}163164template <class _Clock, class _Duration, class _Predicate>165bool condition_variable::wait_until(166unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t, _Predicate __pred) {167while (!__pred()) {168if (wait_until(__lk, __t) == cv_status::timeout)169return __pred();170}171return true;172}173174template <class _Rep, class _Period>175cv_status condition_variable::wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d) {176using namespace chrono;177if (__d <= __d.zero())178return cv_status::timeout;179using __ns_rep = nanoseconds::rep;180steady_clock::time_point __c_now = steady_clock::now();181182# if defined(_LIBCPP_HAS_COND_CLOCKWAIT)183using __clock_tp_ns = time_point<steady_clock, nanoseconds>;184__ns_rep __now_count_ns = std::__safe_nanosecond_cast(__c_now.time_since_epoch()).count();185# else186using __clock_tp_ns = time_point<system_clock, nanoseconds>;187__ns_rep __now_count_ns = std::__safe_nanosecond_cast(system_clock::now().time_since_epoch()).count();188# endif189190__ns_rep __d_ns_count = std::__safe_nanosecond_cast(__d).count();191192if (__now_count_ns > numeric_limits<__ns_rep>::max() - __d_ns_count) {193__do_timed_wait(__lk, __clock_tp_ns::max());194} else {195__do_timed_wait(__lk, __clock_tp_ns(nanoseconds(__now_count_ns + __d_ns_count)));196}197198return steady_clock::now() - __c_now < __d ? cv_status::no_timeout : cv_status::timeout;199}200201template <class _Rep, class _Period, class _Predicate>202inline bool203condition_variable::wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d, _Predicate __pred) {204return wait_until(__lk, chrono::steady_clock::now() + __d, std::move(__pred));205}206207# if defined(_LIBCPP_HAS_COND_CLOCKWAIT)208inline void condition_variable::__do_timed_wait(209unique_lock<mutex>& __lk, chrono::time_point<chrono::steady_clock, chrono::nanoseconds> __tp) _NOEXCEPT {210using namespace chrono;211if (!__lk.owns_lock())212__throw_system_error(EPERM, "condition_variable::timed wait: mutex not locked");213nanoseconds __d = __tp.time_since_epoch();214timespec __ts;215seconds __s = duration_cast<seconds>(__d);216using __ts_sec = decltype(__ts.tv_sec);217const __ts_sec __ts_sec_max = numeric_limits<__ts_sec>::max();218if (__s.count() < __ts_sec_max) {219__ts.tv_sec = static_cast<__ts_sec>(__s.count());220__ts.tv_nsec = (__d - __s).count();221} else {222__ts.tv_sec = __ts_sec_max;223__ts.tv_nsec = giga::num - 1;224}225int __ec = pthread_cond_clockwait(&__cv_, __lk.mutex()->native_handle(), CLOCK_MONOTONIC, &__ts);226if (__ec != 0 && __ec != ETIMEDOUT)227__throw_system_error(__ec, "condition_variable timed_wait failed");228}229# endif // _LIBCPP_HAS_COND_CLOCKWAIT230231template <class _Clock>232inline void condition_variable::__do_timed_wait(unique_lock<mutex>& __lk,233chrono::time_point<_Clock, chrono::nanoseconds> __tp) _NOEXCEPT {234wait_for(__lk, __tp - _Clock::now());235}236237#endif // _LIBCPP_HAS_NO_THREADS238239_LIBCPP_END_NAMESPACE_STD240241_LIBCPP_POP_MACROS242243#endif // _LIBCPP___CONDITION_VARIABLE_CONDITION_VARIABLE_H244245246