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