libcxx

libcxx mirror with random patches
git clone https://git.neptards.moe/neptards/libcxx.git
Log | Files | Refs

__mutex_base (13523B)


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