Home | History | Annotate | Download | only in include
      1 // -*- C++ -*-
      2 //===----------------------------------------------------------------------===//
      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___MUTEX_BASE
     12 #define _LIBCPP___MUTEX_BASE
     13 
     14 #include <__config>
     15 #include <chrono>
     16 #include <system_error>
     17 #include <pthread.h>
     18 
     19 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
     20 #pragma GCC system_header
     21 #endif
     22 
     23 _LIBCPP_BEGIN_NAMESPACE_STD
     24 
     25 #if !_LIBCPP_SINGLE_THREADED
     26 
     27 class _LIBCPP_TYPE_VIS mutex
     28 {
     29     pthread_mutex_t __m_;
     30 
     31 public:
     32     _LIBCPP_INLINE_VISIBILITY
     33 
     34 #ifndef _LIBCPP_HAS_NO_CONSTEXPR
     35      constexpr mutex() _NOEXCEPT : __m_(PTHREAD_MUTEX_INITIALIZER) {}
     36 #else
     37      mutex() _NOEXCEPT {__m_ = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;}
     38 #endif
     39      ~mutex();
     40 
     41 private:
     42     mutex(const mutex&);// = delete;
     43     mutex& operator=(const mutex&);// = delete;
     44 
     45 public:
     46     void lock();
     47     bool try_lock() _NOEXCEPT;
     48     void unlock() _NOEXCEPT;
     49 
     50     typedef pthread_mutex_t* native_handle_type;
     51     _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;}
     52 };
     53 #endif // !_LIBCPP_SINGLE_THREADED
     54 
     55 struct _LIBCPP_TYPE_VIS defer_lock_t {};
     56 struct _LIBCPP_TYPE_VIS try_to_lock_t {};
     57 struct _LIBCPP_TYPE_VIS adopt_lock_t {};
     58 
     59 #if defined(_LIBCPP_HAS_NO_CONSTEXPR) || defined(_LIBCPP_BUILDING_MUTEX)
     60 
     61 extern const defer_lock_t  defer_lock;
     62 extern const try_to_lock_t try_to_lock;
     63 extern const adopt_lock_t  adopt_lock;
     64 
     65 #else
     66 
     67 constexpr defer_lock_t  defer_lock  = defer_lock_t();
     68 constexpr try_to_lock_t try_to_lock = try_to_lock_t();
     69 constexpr adopt_lock_t  adopt_lock  = adopt_lock_t();
     70 
     71 #endif
     72 
     73 template <class _Mutex>
     74 class _LIBCPP_TYPE_VIS_ONLY lock_guard
     75 {
     76 public:
     77     typedef _Mutex mutex_type;
     78 
     79 private:
     80     mutex_type& __m_;
     81 public:
     82 
     83     _LIBCPP_INLINE_VISIBILITY
     84     explicit lock_guard(mutex_type& __m)
     85         : __m_(__m) {__m_.lock();}
     86     _LIBCPP_INLINE_VISIBILITY
     87     lock_guard(mutex_type& __m, adopt_lock_t)
     88         : __m_(__m) {}
     89     _LIBCPP_INLINE_VISIBILITY
     90     ~lock_guard() {__m_.unlock();}
     91 
     92 private:
     93     lock_guard(lock_guard const&);// = delete;
     94     lock_guard& operator=(lock_guard const&);// = delete;
     95 };
     96 
     97 template <class _Mutex>
     98 class _LIBCPP_TYPE_VIS_ONLY unique_lock
     99 {
    100 public:
    101     typedef _Mutex mutex_type;
    102 
    103 private:
    104     mutex_type* __m_;
    105     bool __owns_;
    106 
    107 public:
    108     _LIBCPP_INLINE_VISIBILITY
    109     unique_lock() _NOEXCEPT : __m_(nullptr), __owns_(false) {}
    110     _LIBCPP_INLINE_VISIBILITY
    111     explicit unique_lock(mutex_type& __m)
    112         : __m_(&__m), __owns_(true) {__m_->lock();}
    113     _LIBCPP_INLINE_VISIBILITY
    114     unique_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
    115         : __m_(&__m), __owns_(false) {}
    116     _LIBCPP_INLINE_VISIBILITY
    117     unique_lock(mutex_type& __m, try_to_lock_t)
    118         : __m_(&__m), __owns_(__m.try_lock()) {}
    119     _LIBCPP_INLINE_VISIBILITY
    120     unique_lock(mutex_type& __m, adopt_lock_t)
    121         : __m_(&__m), __owns_(true) {}
    122     template <class _Clock, class _Duration>
    123     _LIBCPP_INLINE_VISIBILITY
    124         unique_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __t)
    125             : __m_(&__m), __owns_(__m.try_lock_until(__t)) {}
    126     template <class _Rep, class _Period>
    127     _LIBCPP_INLINE_VISIBILITY
    128         unique_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __d)
    129             : __m_(&__m), __owns_(__m.try_lock_for(__d)) {}
    130     _LIBCPP_INLINE_VISIBILITY
    131     ~unique_lock()
    132     {
    133         if (__owns_)
    134             __m_->unlock();
    135     }
    136 
    137 private:
    138     unique_lock(unique_lock const&); // = delete;
    139     unique_lock& operator=(unique_lock const&); // = delete;
    140 
    141 public:
    142 #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
    143     _LIBCPP_INLINE_VISIBILITY
    144     unique_lock(unique_lock&& __u) _NOEXCEPT
    145         : __m_(__u.__m_), __owns_(__u.__owns_)
    146         {__u.__m_ = nullptr; __u.__owns_ = false;}
    147     _LIBCPP_INLINE_VISIBILITY
    148     unique_lock& operator=(unique_lock&& __u) _NOEXCEPT
    149         {
    150             if (__owns_)
    151                 __m_->unlock();
    152             __m_ = __u.__m_;
    153             __owns_ = __u.__owns_;
    154             __u.__m_ = nullptr;
    155             __u.__owns_ = false;
    156             return *this;
    157         }
    158 
    159 #endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
    160 
    161     void lock();
    162     bool try_lock();
    163 
    164     template <class _Rep, class _Period>
    165         bool try_lock_for(const chrono::duration<_Rep, _Period>& __d);
    166     template <class _Clock, class _Duration>
    167         bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
    168 
    169     void unlock();
    170 
    171     _LIBCPP_INLINE_VISIBILITY
    172     void swap(unique_lock& __u) _NOEXCEPT
    173     {
    174         _VSTD::swap(__m_, __u.__m_);
    175         _VSTD::swap(__owns_, __u.__owns_);
    176     }
    177     _LIBCPP_INLINE_VISIBILITY
    178     mutex_type* release() _NOEXCEPT
    179     {
    180         mutex_type* __m = __m_;
    181         __m_ = nullptr;
    182         __owns_ = false;
    183         return __m;
    184     }
    185 
    186     _LIBCPP_INLINE_VISIBILITY
    187     bool owns_lock() const _NOEXCEPT {return __owns_;}
    188     _LIBCPP_INLINE_VISIBILITY
    189     _LIBCPP_EXPLICIT
    190         operator bool () const _NOEXCEPT {return __owns_;}
    191     _LIBCPP_INLINE_VISIBILITY
    192     mutex_type* mutex() const _NOEXCEPT {return __m_;}
    193 };
    194 
    195 template <class _Mutex>
    196 void
    197 unique_lock<_Mutex>::lock()
    198 {
    199     if (__m_ == nullptr)
    200         __throw_system_error(EPERM, "unique_lock::lock: references null mutex");
    201     if (__owns_)
    202         __throw_system_error(EDEADLK, "unique_lock::lock: already locked");
    203     __m_->lock();
    204     __owns_ = true;
    205 }
    206 
    207 template <class _Mutex>
    208 bool
    209 unique_lock<_Mutex>::try_lock()
    210 {
    211     if (__m_ == nullptr)
    212         __throw_system_error(EPERM, "unique_lock::try_lock: references null mutex");
    213     if (__owns_)
    214         __throw_system_error(EDEADLK, "unique_lock::try_lock: already locked");
    215     __owns_ = __m_->try_lock();
    216     return __owns_;
    217 }
    218 
    219 template <class _Mutex>
    220 template <class _Rep, class _Period>
    221 bool
    222 unique_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
    223 {
    224     if (__m_ == nullptr)
    225         __throw_system_error(EPERM, "unique_lock::try_lock_for: references null mutex");
    226     if (__owns_)
    227         __throw_system_error(EDEADLK, "unique_lock::try_lock_for: already locked");
    228     __owns_ = __m_->try_lock_for(__d);
    229     return __owns_;
    230 }
    231 
    232 template <class _Mutex>
    233 template <class _Clock, class _Duration>
    234 bool
    235 unique_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
    236 {
    237     if (__m_ == nullptr)
    238         __throw_system_error(EPERM, "unique_lock::try_lock_until: references null mutex");
    239     if (__owns_)
    240         __throw_system_error(EDEADLK, "unique_lock::try_lock_until: already locked");
    241     __owns_ = __m_->try_lock_until(__t);
    242     return __owns_;
    243 }
    244 
    245 template <class _Mutex>
    246 void
    247 unique_lock<_Mutex>::unlock()
    248 {
    249     if (!__owns_)
    250         __throw_system_error(EPERM, "unique_lock::unlock: not locked");
    251     __m_->unlock();
    252     __owns_ = false;
    253 }
    254 
    255 template <class _Mutex>
    256 inline _LIBCPP_INLINE_VISIBILITY
    257 void
    258 swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) _NOEXCEPT
    259     {__x.swap(__y);}
    260 
    261 //enum class cv_status
    262 _LIBCPP_DECLARE_STRONG_ENUM(cv_status)
    263 {
    264     no_timeout,
    265     timeout
    266 };
    267 _LIBCPP_DECLARE_STRONG_ENUM_EPILOG(cv_status)
    268 
    269 #if !_LIBCPP_SINGLE_THREADED
    270 class _LIBCPP_TYPE_VIS condition_variable
    271 {
    272     pthread_cond_t __cv_;
    273 public:
    274     _LIBCPP_INLINE_VISIBILITY
    275 #ifndef _LIBCPP_HAS_NO_CONSTEXPR
    276     constexpr condition_variable() : __cv_(PTHREAD_COND_INITIALIZER) {}
    277 #else
    278     condition_variable() {__cv_ = (pthread_cond_t)PTHREAD_COND_INITIALIZER;}
    279 #endif
    280     ~condition_variable();
    281 
    282 private:
    283     condition_variable(const condition_variable&); // = delete;
    284     condition_variable& operator=(const condition_variable&); // = delete;
    285 
    286 public:
    287     void notify_one() _NOEXCEPT;
    288     void notify_all() _NOEXCEPT;
    289 
    290     void wait(unique_lock<mutex>& __lk) _NOEXCEPT;
    291     template <class _Predicate>
    292         void wait(unique_lock<mutex>& __lk, _Predicate __pred);
    293 
    294     template <class _Clock, class _Duration>
    295         cv_status
    296         wait_until(unique_lock<mutex>& __lk,
    297                    const chrono::time_point<_Clock, _Duration>& __t);
    298 
    299     template <class _Clock, class _Duration, class _Predicate>
    300         bool
    301         wait_until(unique_lock<mutex>& __lk,
    302                    const chrono::time_point<_Clock, _Duration>& __t,
    303                    _Predicate __pred);
    304 
    305     template <class _Rep, class _Period>
    306         cv_status
    307         wait_for(unique_lock<mutex>& __lk,
    308                  const chrono::duration<_Rep, _Period>& __d);
    309 
    310     template <class _Rep, class _Period, class _Predicate>
    311         bool
    312         wait_for(unique_lock<mutex>& __lk,
    313                  const chrono::duration<_Rep, _Period>& __d,
    314                  _Predicate __pred);
    315 
    316     typedef pthread_cond_t* native_handle_type;
    317     _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;}
    318 
    319 private:
    320     void __do_timed_wait(unique_lock<mutex>& __lk,
    321        chrono::time_point<chrono::system_clock, chrono::nanoseconds>) _NOEXCEPT;
    322 };
    323 #endif // !_LIBCPP_SINGLE_THREADED
    324 
    325 template <class _To, class _Rep, class _Period>
    326 inline _LIBCPP_INLINE_VISIBILITY
    327 typename enable_if
    328 <
    329     chrono::__is_duration<_To>::value,
    330     _To
    331 >::type
    332 __ceil(chrono::duration<_Rep, _Period> __d)
    333 {
    334     using namespace chrono;
    335     _To __r = duration_cast<_To>(__d);
    336     if (__r < __d)
    337         ++__r;
    338     return __r;
    339 }
    340 
    341 #if !_LIBCPP_SINGLE_THREADED
    342 template <class _Predicate>
    343 void
    344 condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred)
    345 {
    346     while (!__pred())
    347         wait(__lk);
    348 }
    349 
    350 template <class _Clock, class _Duration>
    351 cv_status
    352 condition_variable::wait_until(unique_lock<mutex>& __lk,
    353                                const chrono::time_point<_Clock, _Duration>& __t)
    354 {
    355     using namespace chrono;
    356     wait_for(__lk, __t - _Clock::now());
    357     return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
    358 }
    359 
    360 template <class _Clock, class _Duration, class _Predicate>
    361 bool
    362 condition_variable::wait_until(unique_lock<mutex>& __lk,
    363                    const chrono::time_point<_Clock, _Duration>& __t,
    364                    _Predicate __pred)
    365 {
    366     while (!__pred())
    367     {
    368         if (wait_until(__lk, __t) == cv_status::timeout)
    369             return __pred();
    370     }
    371     return true;
    372 }
    373 
    374 template <class _Rep, class _Period>
    375 cv_status
    376 condition_variable::wait_for(unique_lock<mutex>& __lk,
    377                              const chrono::duration<_Rep, _Period>& __d)
    378 {
    379     using namespace chrono;
    380     if (__d <= __d.zero())
    381         return cv_status::timeout;
    382     typedef time_point<system_clock, duration<long double, nano> > __sys_tpf;
    383     typedef time_point<system_clock, nanoseconds> __sys_tpi;
    384     __sys_tpf _Max = __sys_tpi::max();
    385     system_clock::time_point __s_now = system_clock::now();
    386     steady_clock::time_point __c_now = steady_clock::now();
    387     if (_Max - __d > __s_now)
    388         __do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__d));
    389     else
    390         __do_timed_wait(__lk, __sys_tpi::max());
    391     return steady_clock::now() - __c_now < __d ? cv_status::no_timeout :
    392                                                  cv_status::timeout;
    393 }
    394 
    395 template <class _Rep, class _Period, class _Predicate>
    396 inline _LIBCPP_INLINE_VISIBILITY
    397 bool
    398 condition_variable::wait_for(unique_lock<mutex>& __lk,
    399                              const chrono::duration<_Rep, _Period>& __d,
    400                              _Predicate __pred)
    401 {
    402     return wait_until(__lk, chrono::steady_clock::now() + __d,
    403                       _VSTD::move(__pred));
    404 }
    405 
    406 #endif // !_LIBCPP_SINGLE_THREADED
    407 
    408 _LIBCPP_END_NAMESPACE_STD
    409 
    410 #endif  // _LIBCPP___MUTEX_BASE
    411