brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.8 KiB · af03250 Raw
245 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef _LIBCPP___CXX03___CONDITION_VARIABLE_CONDITION_VARIABLE_H10#define _LIBCPP___CXX03___CONDITION_VARIABLE_CONDITION_VARIABLE_H11 12#include <__cxx03/__chrono/duration.h>13#include <__cxx03/__chrono/steady_clock.h>14#include <__cxx03/__chrono/system_clock.h>15#include <__cxx03/__chrono/time_point.h>16#include <__cxx03/__config>17#include <__cxx03/__mutex/mutex.h>18#include <__cxx03/__mutex/unique_lock.h>19#include <__cxx03/__system_error/system_error.h>20#include <__cxx03/__thread/support.h>21#include <__cxx03/__type_traits/enable_if.h>22#include <__cxx03/__type_traits/is_floating_point.h>23#include <__cxx03/__utility/move.h>24#include <__cxx03/limits>25#include <__cxx03/ratio>26 27#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)28#  pragma GCC system_header29#endif30 31_LIBCPP_PUSH_MACROS32#include <__cxx03/__undef_macros>33 34_LIBCPP_BEGIN_NAMESPACE_STD35 36#ifndef _LIBCPP_HAS_NO_THREADS37 38// enum class cv_status39_LIBCPP_DECLARE_STRONG_ENUM(cv_status){no_timeout, timeout};40_LIBCPP_DECLARE_STRONG_ENUM_EPILOG(cv_status)41 42class _LIBCPP_EXPORTED_FROM_ABI condition_variable {43  __libcpp_condvar_t __cv_ = _LIBCPP_CONDVAR_INITIALIZER;44 45public:46  _LIBCPP_HIDE_FROM_ABI condition_variable() _NOEXCEPT = default;47 48#  ifdef _LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION49  ~condition_variable() = default;50#  else51  ~condition_variable();52#  endif53 54  condition_variable(const condition_variable&)            = delete;55  condition_variable& operator=(const condition_variable&) = delete;56 57  void notify_one() _NOEXCEPT;58  void notify_all() _NOEXCEPT;59 60  void wait(unique_lock<mutex>& __lk) _NOEXCEPT;61  template <class _Predicate>62  _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS void wait(unique_lock<mutex>& __lk, _Predicate __pred);63 64  template <class _Clock, class _Duration>65  _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS cv_status66  wait_until(unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t);67 68  template <class _Clock, class _Duration, class _Predicate>69  _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool70  wait_until(unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t, _Predicate __pred);71 72  template <class _Rep, class _Period>73  _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS cv_status74  wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d);75 76  template <class _Rep, class _Period, class _Predicate>77  bool _LIBCPP_HIDE_FROM_ABI78  wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d, _Predicate __pred);79 80  typedef __libcpp_condvar_t* native_handle_type;81  _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return &__cv_; }82 83private:84  void85  __do_timed_wait(unique_lock<mutex>& __lk, chrono::time_point<chrono::system_clock, chrono::nanoseconds>) _NOEXCEPT;86#  if defined(_LIBCPP_HAS_COND_CLOCKWAIT)87  _LIBCPP_HIDE_FROM_ABI void88  __do_timed_wait(unique_lock<mutex>& __lk, chrono::time_point<chrono::steady_clock, chrono::nanoseconds>) _NOEXCEPT;89#  endif90  template <class _Clock>91  _LIBCPP_HIDE_FROM_ABI void92  __do_timed_wait(unique_lock<mutex>& __lk, chrono::time_point<_Clock, chrono::nanoseconds>) _NOEXCEPT;93};94#endif // !_LIBCPP_HAS_NO_THREADS95 96template <class _Rep, class _Period, __enable_if_t<is_floating_point<_Rep>::value, int> = 0>97inline _LIBCPP_HIDE_FROM_ABI chrono::nanoseconds __safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d) {98  using namespace chrono;99  using __ratio       = ratio_divide<_Period, nano>;100  using __ns_rep      = nanoseconds::rep;101  _Rep __result_float = __d.count() * __ratio::num / __ratio::den;102 103  _Rep __result_max = numeric_limits<__ns_rep>::max();104  if (__result_float >= __result_max) {105    return nanoseconds::max();106  }107 108  _Rep __result_min = numeric_limits<__ns_rep>::min();109  if (__result_float <= __result_min) {110    return nanoseconds::min();111  }112 113  return nanoseconds(static_cast<__ns_rep>(__result_float));114}115 116template <class _Rep, class _Period, __enable_if_t<!is_floating_point<_Rep>::value, int> = 0>117inline _LIBCPP_HIDE_FROM_ABI chrono::nanoseconds __safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d) {118  using namespace chrono;119  if (__d.count() == 0) {120    return nanoseconds(0);121  }122 123  using __ratio         = ratio_divide<_Period, nano>;124  using __ns_rep        = nanoseconds::rep;125  __ns_rep __result_max = numeric_limits<__ns_rep>::max();126  if (__d.count() > 0 && __d.count() > __result_max / __ratio::num) {127    return nanoseconds::max();128  }129 130  __ns_rep __result_min = numeric_limits<__ns_rep>::min();131  if (__d.count() < 0 && __d.count() < __result_min / __ratio::num) {132    return nanoseconds::min();133  }134 135  __ns_rep __result = __d.count() * __ratio::num / __ratio::den;136  if (__result == 0) {137    return nanoseconds(1);138  }139 140  return nanoseconds(__result);141}142 143#ifndef _LIBCPP_HAS_NO_THREADS144template <class _Predicate>145void condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred) {146  while (!__pred())147    wait(__lk);148}149 150template <class _Clock, class _Duration>151cv_status condition_variable::wait_until(unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t) {152  using namespace chrono;153  using __clock_tp_ns = time_point<_Clock, nanoseconds>;154 155  typename _Clock::time_point __now = _Clock::now();156  if (__t <= __now)157    return cv_status::timeout;158 159  __clock_tp_ns __t_ns = __clock_tp_ns(std::__safe_nanosecond_cast(__t.time_since_epoch()));160 161  __do_timed_wait(__lk, __t_ns);162  return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;163}164 165template <class _Clock, class _Duration, class _Predicate>166bool condition_variable::wait_until(167    unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t, _Predicate __pred) {168  while (!__pred()) {169    if (wait_until(__lk, __t) == cv_status::timeout)170      return __pred();171  }172  return true;173}174 175template <class _Rep, class _Period>176cv_status condition_variable::wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d) {177  using namespace chrono;178  if (__d <= __d.zero())179    return cv_status::timeout;180  using __ns_rep                   = nanoseconds::rep;181  steady_clock::time_point __c_now = steady_clock::now();182 183#  if defined(_LIBCPP_HAS_COND_CLOCKWAIT)184  using __clock_tp_ns     = time_point<steady_clock, nanoseconds>;185  __ns_rep __now_count_ns = std::__safe_nanosecond_cast(__c_now.time_since_epoch()).count();186#  else187  using __clock_tp_ns     = time_point<system_clock, nanoseconds>;188  __ns_rep __now_count_ns = std::__safe_nanosecond_cast(system_clock::now().time_since_epoch()).count();189#  endif190 191  __ns_rep __d_ns_count = std::__safe_nanosecond_cast(__d).count();192 193  if (__now_count_ns > numeric_limits<__ns_rep>::max() - __d_ns_count) {194    __do_timed_wait(__lk, __clock_tp_ns::max());195  } else {196    __do_timed_wait(__lk, __clock_tp_ns(nanoseconds(__now_count_ns + __d_ns_count)));197  }198 199  return steady_clock::now() - __c_now < __d ? cv_status::no_timeout : cv_status::timeout;200}201 202template <class _Rep, class _Period, class _Predicate>203inline bool204condition_variable::wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d, _Predicate __pred) {205  return wait_until(__lk, chrono::steady_clock::now() + __d, std::move(__pred));206}207 208#  if defined(_LIBCPP_HAS_COND_CLOCKWAIT)209inline void condition_variable::__do_timed_wait(210    unique_lock<mutex>& __lk, chrono::time_point<chrono::steady_clock, chrono::nanoseconds> __tp) _NOEXCEPT {211  using namespace chrono;212  if (!__lk.owns_lock())213    __throw_system_error(EPERM, "condition_variable::timed wait: mutex not locked");214  nanoseconds __d = __tp.time_since_epoch();215  timespec __ts;216  seconds __s                 = duration_cast<seconds>(__d);217  using __ts_sec              = decltype(__ts.tv_sec);218  const __ts_sec __ts_sec_max = numeric_limits<__ts_sec>::max();219  if (__s.count() < __ts_sec_max) {220    __ts.tv_sec  = static_cast<__ts_sec>(__s.count());221    __ts.tv_nsec = (__d - __s).count();222  } else {223    __ts.tv_sec  = __ts_sec_max;224    __ts.tv_nsec = giga::num - 1;225  }226  int __ec = pthread_cond_clockwait(&__cv_, __lk.mutex()->native_handle(), CLOCK_MONOTONIC, &__ts);227  if (__ec != 0 && __ec != ETIMEDOUT)228    __throw_system_error(__ec, "condition_variable timed_wait failed");229}230#  endif // _LIBCPP_HAS_COND_CLOCKWAIT231 232template <class _Clock>233inline void condition_variable::__do_timed_wait(unique_lock<mutex>& __lk,234                                                chrono::time_point<_Clock, chrono::nanoseconds> __tp) _NOEXCEPT {235  wait_for(__lk, __tp - _Clock::now());236}237 238#endif // _LIBCPP_HAS_NO_THREADS239 240_LIBCPP_END_NAMESPACE_STD241 242_LIBCPP_POP_MACROS243 244#endif // _LIBCPP___CXX03___CONDITION_VARIABLE_CONDITION_VARIABLE_H245