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