Home | History | Annotate | Line # | Download | only in include
      1 // -*- C++ -*-
      2 //===---------------------- condition_variable ----------------------------===//
      3 //
      4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      5 // See https://llvm.org/LICENSE.txt for license information.
      6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #ifndef _LIBCPP_CONDITION_VARIABLE
     11 #define _LIBCPP_CONDITION_VARIABLE
     12 
     13 /*
     14     condition_variable synopsis
     15 
     16 namespace std
     17 {
     18 
     19 enum class cv_status { no_timeout, timeout };
     20 
     21 class condition_variable
     22 {
     23 public:
     24     condition_variable();
     25     ~condition_variable();
     26 
     27     condition_variable(const condition_variable&) = delete;
     28     condition_variable& operator=(const condition_variable&) = delete;
     29 
     30     void notify_one() noexcept;
     31     void notify_all() noexcept;
     32 
     33     void wait(unique_lock<mutex>& lock);
     34     template <class Predicate>
     35         void wait(unique_lock<mutex>& lock, Predicate pred);
     36 
     37     template <class Clock, class Duration>
     38         cv_status
     39         wait_until(unique_lock<mutex>& lock,
     40                    const chrono::time_point<Clock, Duration>& abs_time);
     41 
     42     template <class Clock, class Duration, class Predicate>
     43         bool
     44         wait_until(unique_lock<mutex>& lock,
     45                    const chrono::time_point<Clock, Duration>& abs_time,
     46                    Predicate pred);
     47 
     48     template <class Rep, class Period>
     49         cv_status
     50         wait_for(unique_lock<mutex>& lock,
     51                  const chrono::duration<Rep, Period>& rel_time);
     52 
     53     template <class Rep, class Period, class Predicate>
     54         bool
     55         wait_for(unique_lock<mutex>& lock,
     56                  const chrono::duration<Rep, Period>& rel_time,
     57                  Predicate pred);
     58 
     59     typedef pthread_cond_t* native_handle_type;
     60     native_handle_type native_handle();
     61 };
     62 
     63 void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
     64 
     65 class condition_variable_any
     66 {
     67 public:
     68     condition_variable_any();
     69     ~condition_variable_any();
     70 
     71     condition_variable_any(const condition_variable_any&) = delete;
     72     condition_variable_any& operator=(const condition_variable_any&) = delete;
     73 
     74     void notify_one() noexcept;
     75     void notify_all() noexcept;
     76 
     77     template <class Lock>
     78         void wait(Lock& lock);
     79     template <class Lock, class Predicate>
     80         void wait(Lock& lock, Predicate pred);
     81 
     82     template <class Lock, class Clock, class Duration>
     83         cv_status
     84         wait_until(Lock& lock,
     85                    const chrono::time_point<Clock, Duration>& abs_time);
     86 
     87     template <class Lock, class Clock, class Duration, class Predicate>
     88         bool
     89         wait_until(Lock& lock,
     90                    const chrono::time_point<Clock, Duration>& abs_time,
     91                    Predicate pred);
     92 
     93     template <class Lock, class Rep, class Period>
     94         cv_status
     95         wait_for(Lock& lock,
     96                  const chrono::duration<Rep, Period>& rel_time);
     97 
     98     template <class Lock, class Rep, class Period, class Predicate>
     99         bool
    100         wait_for(Lock& lock,
    101                  const chrono::duration<Rep, Period>& rel_time,
    102                  Predicate pred);
    103 };
    104 
    105 }  // std
    106 
    107 */
    108 
    109 #include <__config>
    110 #include <__mutex_base>
    111 #include <memory>
    112 
    113 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
    114 #pragma GCC system_header
    115 #endif
    116 
    117 #ifndef _LIBCPP_HAS_NO_THREADS
    118 
    119 _LIBCPP_BEGIN_NAMESPACE_STD
    120 
    121 class _LIBCPP_TYPE_VIS condition_variable_any
    122 {
    123     condition_variable __cv_;
    124     shared_ptr<mutex>  __mut_;
    125 public:
    126     _LIBCPP_INLINE_VISIBILITY
    127     condition_variable_any();
    128 
    129     _LIBCPP_INLINE_VISIBILITY
    130     void notify_one() _NOEXCEPT;
    131     _LIBCPP_INLINE_VISIBILITY
    132     void notify_all() _NOEXCEPT;
    133 
    134     template <class _Lock>
    135         _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
    136         void wait(_Lock& __lock);
    137     template <class _Lock, class _Predicate>
    138         _LIBCPP_INLINE_VISIBILITY
    139         void wait(_Lock& __lock, _Predicate __pred);
    140 
    141     template <class _Lock, class _Clock, class _Duration>
    142         _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
    143         cv_status
    144         wait_until(_Lock& __lock,
    145                    const chrono::time_point<_Clock, _Duration>& __t);
    146 
    147     template <class _Lock, class _Clock, class _Duration, class _Predicate>
    148         bool
    149         _LIBCPP_INLINE_VISIBILITY
    150         wait_until(_Lock& __lock,
    151                    const chrono::time_point<_Clock, _Duration>& __t,
    152                    _Predicate __pred);
    153 
    154     template <class _Lock, class _Rep, class _Period>
    155         cv_status
    156         _LIBCPP_INLINE_VISIBILITY
    157         wait_for(_Lock& __lock,
    158                  const chrono::duration<_Rep, _Period>& __d);
    159 
    160     template <class _Lock, class _Rep, class _Period, class _Predicate>
    161         bool
    162         _LIBCPP_INLINE_VISIBILITY
    163         wait_for(_Lock& __lock,
    164                  const chrono::duration<_Rep, _Period>& __d,
    165                  _Predicate __pred);
    166 };
    167 
    168 inline
    169 condition_variable_any::condition_variable_any()
    170     : __mut_(make_shared<mutex>()) {}
    171 
    172 inline
    173 void
    174 condition_variable_any::notify_one() _NOEXCEPT
    175 {
    176     {lock_guard<mutex> __lx(*__mut_);}
    177     __cv_.notify_one();
    178 }
    179 
    180 inline
    181 void
    182 condition_variable_any::notify_all() _NOEXCEPT
    183 {
    184     {lock_guard<mutex> __lx(*__mut_);}
    185     __cv_.notify_all();
    186 }
    187 
    188 struct __lock_external
    189 {
    190     template <class _Lock>
    191     void operator()(_Lock* __m) {__m->lock();}
    192 };
    193 
    194 template <class _Lock>
    195 void
    196 condition_variable_any::wait(_Lock& __lock)
    197 {
    198     shared_ptr<mutex> __mut = __mut_;
    199     unique_lock<mutex> __lk(*__mut);
    200     __lock.unlock();
    201     unique_ptr<_Lock, __lock_external> __lxx(&__lock);
    202     lock_guard<unique_lock<mutex> > __lx(__lk, adopt_lock);
    203     __cv_.wait(__lk);
    204 }  // __mut_.unlock(), __lock.lock()
    205 
    206 template <class _Lock, class _Predicate>
    207 inline
    208 void
    209 condition_variable_any::wait(_Lock& __lock, _Predicate __pred)
    210 {
    211     while (!__pred())
    212         wait(__lock);
    213 }
    214 
    215 template <class _Lock, class _Clock, class _Duration>
    216 cv_status
    217 condition_variable_any::wait_until(_Lock& __lock,
    218                                    const chrono::time_point<_Clock, _Duration>& __t)
    219 {
    220     shared_ptr<mutex> __mut = __mut_;
    221     unique_lock<mutex> __lk(*__mut);
    222     __lock.unlock();
    223     unique_ptr<_Lock, __lock_external> __lxx(&__lock);
    224     lock_guard<unique_lock<mutex> > __lx(__lk, adopt_lock);
    225     return __cv_.wait_until(__lk, __t);
    226 }  // __mut_.unlock(), __lock.lock()
    227 
    228 template <class _Lock, class _Clock, class _Duration, class _Predicate>
    229 inline
    230 bool
    231 condition_variable_any::wait_until(_Lock& __lock,
    232                                    const chrono::time_point<_Clock, _Duration>& __t,
    233                                    _Predicate __pred)
    234 {
    235     while (!__pred())
    236         if (wait_until(__lock, __t) == cv_status::timeout)
    237             return __pred();
    238     return true;
    239 }
    240 
    241 template <class _Lock, class _Rep, class _Period>
    242 inline
    243 cv_status
    244 condition_variable_any::wait_for(_Lock& __lock,
    245                                  const chrono::duration<_Rep, _Period>& __d)
    246 {
    247     return wait_until(__lock, chrono::steady_clock::now() + __d);
    248 }
    249 
    250 template <class _Lock, class _Rep, class _Period, class _Predicate>
    251 inline
    252 bool
    253 condition_variable_any::wait_for(_Lock& __lock,
    254                                  const chrono::duration<_Rep, _Period>& __d,
    255                                  _Predicate __pred)
    256 {
    257     return wait_until(__lock, chrono::steady_clock::now() + __d,
    258                       _VSTD::move(__pred));
    259 }
    260 
    261 _LIBCPP_FUNC_VIS
    262 void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
    263 
    264 _LIBCPP_END_NAMESPACE_STD
    265 
    266 #endif // !_LIBCPP_HAS_NO_THREADS
    267 
    268 #endif // _LIBCPP_CONDITION_VARIABLE
    269