Home | History | Annotate | Download | only in include
      1 // -*- C++ -*-
      2 //===--------------------------- mutex ------------------------------------===//
      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
     12 #define _LIBCPP_MUTEX
     13 
     14 /*
     15     mutex synopsis
     16 
     17 namespace std
     18 {
     19 
     20 class mutex
     21 {
     22 public:
     23      constexpr mutex() noexcept;
     24      ~mutex();
     25 
     26     mutex(const mutex&) = delete;
     27     mutex& operator=(const mutex&) = delete;
     28 
     29     void lock();
     30     bool try_lock();
     31     void unlock();
     32 
     33     typedef pthread_mutex_t* native_handle_type;
     34     native_handle_type native_handle();
     35 };
     36 
     37 class recursive_mutex
     38 {
     39 public:
     40      recursive_mutex();
     41      ~recursive_mutex();
     42 
     43     recursive_mutex(const recursive_mutex&) = delete;
     44     recursive_mutex& operator=(const recursive_mutex&) = delete;
     45 
     46     void lock();
     47     bool try_lock() noexcept;
     48     void unlock();
     49 
     50     typedef pthread_mutex_t* native_handle_type;
     51     native_handle_type native_handle();
     52 };
     53 
     54 class timed_mutex
     55 {
     56 public:
     57      timed_mutex();
     58      ~timed_mutex();
     59 
     60     timed_mutex(const timed_mutex&) = delete;
     61     timed_mutex& operator=(const timed_mutex&) = delete;
     62 
     63     void lock();
     64     bool try_lock();
     65     template <class Rep, class Period>
     66         bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
     67     template <class Clock, class Duration>
     68         bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
     69     void unlock();
     70 };
     71 
     72 class recursive_timed_mutex
     73 {
     74 public:
     75      recursive_timed_mutex();
     76      ~recursive_timed_mutex();
     77 
     78     recursive_timed_mutex(const recursive_timed_mutex&) = delete;
     79     recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
     80 
     81     void lock();
     82     bool try_lock() noexcept;
     83     template <class Rep, class Period>
     84         bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
     85     template <class Clock, class Duration>
     86         bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
     87     void unlock();
     88 };
     89 
     90 struct defer_lock_t {};
     91 struct try_to_lock_t {};
     92 struct adopt_lock_t {};
     93 
     94 constexpr defer_lock_t  defer_lock{};
     95 constexpr try_to_lock_t try_to_lock{};
     96 constexpr adopt_lock_t  adopt_lock{};
     97 
     98 template <class Mutex>
     99 class lock_guard
    100 {
    101 public:
    102     typedef Mutex mutex_type;
    103 
    104     explicit lock_guard(mutex_type& m);
    105     lock_guard(mutex_type& m, adopt_lock_t);
    106     ~lock_guard();
    107 
    108     lock_guard(lock_guard const&) = delete;
    109     lock_guard& operator=(lock_guard const&) = delete;
    110 };
    111 
    112 template <class Mutex>
    113 class unique_lock
    114 {
    115 public:
    116     typedef Mutex mutex_type;
    117     unique_lock() noexcept;
    118     explicit unique_lock(mutex_type& m);
    119     unique_lock(mutex_type& m, defer_lock_t) noexcept;
    120     unique_lock(mutex_type& m, try_to_lock_t);
    121     unique_lock(mutex_type& m, adopt_lock_t);
    122     template <class Clock, class Duration>
    123         unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);
    124     template <class Rep, class Period>
    125         unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time);
    126     ~unique_lock();
    127 
    128     unique_lock(unique_lock const&) = delete;
    129     unique_lock& operator=(unique_lock const&) = delete;
    130 
    131     unique_lock(unique_lock&& u) noexcept;
    132     unique_lock& operator=(unique_lock&& u) noexcept;
    133 
    134     void lock();
    135     bool try_lock();
    136 
    137     template <class Rep, class Period>
    138         bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
    139     template <class Clock, class Duration>
    140         bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
    141 
    142     void unlock();
    143 
    144     void swap(unique_lock& u) noexcept;
    145     mutex_type* release() noexcept;
    146 
    147     bool owns_lock() const noexcept;
    148     explicit operator bool () const noexcept;
    149     mutex_type* mutex() const noexcept;
    150 };
    151 
    152 template <class Mutex>
    153   void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept;
    154 
    155 template <class L1, class L2, class... L3>
    156   int try_lock(L1&, L2&, L3&...);
    157 template <class L1, class L2, class... L3>
    158   void lock(L1&, L2&, L3&...);
    159 
    160 struct once_flag
    161 {
    162     constexpr once_flag() noexcept;
    163 
    164     once_flag(const once_flag&) = delete;
    165     once_flag& operator=(const once_flag&) = delete;
    166 };
    167 
    168 template<class Callable, class ...Args>
    169   void call_once(once_flag& flag, Callable&& func, Args&&... args);
    170 
    171 }  // std
    172 
    173 */
    174 
    175 #include <__config>
    176 #include <__mutex_base>
    177 #include <functional>
    178 #ifndef _LIBCPP_HAS_NO_VARIADICS
    179 #include <tuple>
    180 #endif
    181 
    182 #include <__undef_min_max>
    183 
    184 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
    185 #pragma GCC system_header
    186 #endif
    187 
    188 _LIBCPP_BEGIN_NAMESPACE_STD
    189 
    190 class _LIBCPP_VISIBLE recursive_mutex
    191 {
    192     pthread_mutex_t __m_;
    193 
    194 public:
    195      recursive_mutex();
    196      ~recursive_mutex();
    197 
    198 private:
    199     recursive_mutex(const recursive_mutex&); // = delete;
    200     recursive_mutex& operator=(const recursive_mutex&); // = delete;
    201 
    202 public:
    203     void lock();
    204     bool try_lock() _NOEXCEPT;
    205     void unlock()  _NOEXCEPT;
    206 
    207     typedef pthread_mutex_t* native_handle_type;
    208     _LIBCPP_INLINE_VISIBILITY
    209     native_handle_type native_handle() {return &__m_;}
    210 };
    211 
    212 class _LIBCPP_VISIBLE timed_mutex
    213 {
    214     mutex              __m_;
    215     condition_variable __cv_;
    216     bool               __locked_;
    217 public:
    218      timed_mutex();
    219      ~timed_mutex();
    220 
    221 private:
    222     timed_mutex(const timed_mutex&); // = delete;
    223     timed_mutex& operator=(const timed_mutex&); // = delete;
    224 
    225 public:
    226     void lock();
    227     bool try_lock() _NOEXCEPT;
    228     template <class _Rep, class _Period>
    229         _LIBCPP_INLINE_VISIBILITY
    230         bool try_lock_for(const chrono::duration<_Rep, _Period>& __d)
    231             {return try_lock_until(chrono::steady_clock::now() + __d);}
    232     template <class _Clock, class _Duration>
    233         bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
    234     void unlock() _NOEXCEPT;
    235 };
    236 
    237 template <class _Clock, class _Duration>
    238 bool
    239 timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
    240 {
    241     using namespace chrono;
    242     unique_lock<mutex> __lk(__m_);
    243     bool no_timeout = _Clock::now() < __t;
    244     while (no_timeout && __locked_)
    245         no_timeout = __cv_.wait_until(__lk, __t) == cv_status::no_timeout;
    246     if (!__locked_)
    247     {
    248         __locked_ = true;
    249         return true;
    250     }
    251     return false;
    252 }
    253 
    254 class _LIBCPP_VISIBLE recursive_timed_mutex
    255 {
    256     mutex              __m_;
    257     condition_variable __cv_;
    258     size_t             __count_;
    259     pthread_t          __id_;
    260 public:
    261      recursive_timed_mutex();
    262      ~recursive_timed_mutex();
    263 
    264 private:
    265     recursive_timed_mutex(const recursive_timed_mutex&); // = delete;
    266     recursive_timed_mutex& operator=(const recursive_timed_mutex&); // = delete;
    267 
    268 public:
    269     void lock();
    270     bool try_lock() _NOEXCEPT;
    271     template <class _Rep, class _Period>
    272         _LIBCPP_INLINE_VISIBILITY
    273         bool try_lock_for(const chrono::duration<_Rep, _Period>& __d)
    274             {return try_lock_until(chrono::steady_clock::now() + __d);}
    275     template <class _Clock, class _Duration>
    276         bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
    277     void unlock() _NOEXCEPT;
    278 };
    279 
    280 template <class _Clock, class _Duration>
    281 bool
    282 recursive_timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
    283 {
    284     using namespace chrono;
    285     pthread_t __id = pthread_self();
    286     unique_lock<mutex> lk(__m_);
    287     if (pthread_equal(__id, __id_))
    288     {
    289         if (__count_ == numeric_limits<size_t>::max())
    290             return false;
    291         ++__count_;
    292         return true;
    293     }
    294     bool no_timeout = _Clock::now() < __t;
    295     while (no_timeout && __count_ != 0)
    296         no_timeout = __cv_.wait_until(lk, __t) == cv_status::no_timeout;
    297     if (__count_ == 0)
    298     {
    299         __count_ = 1;
    300         __id_ = __id;
    301         return true;
    302     }
    303     return false;
    304 }
    305 
    306 template <class _L0, class _L1>
    307 int
    308 try_lock(_L0& __l0, _L1& __l1)
    309 {
    310     unique_lock<_L0> __u0(__l0, try_to_lock);
    311     if (__u0.owns_lock())
    312     {
    313         if (__l1.try_lock())
    314         {
    315             __u0.release();
    316             return -1;
    317         }
    318         else
    319             return 1;
    320     }
    321     return 0;
    322 }
    323 
    324 #ifndef _LIBCPP_HAS_NO_VARIADICS
    325 
    326 template <class _L0, class _L1, class _L2, class... _L3>
    327 int
    328 try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3)
    329 {
    330     int __r = 0;
    331     unique_lock<_L0> __u0(__l0, try_to_lock);
    332     if (__u0.owns_lock())
    333     {
    334         __r = try_lock(__l1, __l2, __l3...);
    335         if (__r == -1)
    336             __u0.release();
    337         else
    338             ++__r;
    339     }
    340     return __r;
    341 }
    342 
    343 #endif  // _LIBCPP_HAS_NO_VARIADICS
    344 
    345 template <class _L0, class _L1>
    346 void
    347 lock(_L0& __l0, _L1& __l1)
    348 {
    349     while (true)
    350     {
    351         {
    352             unique_lock<_L0> __u0(__l0);
    353             if (__l1.try_lock())
    354             {
    355                 __u0.release();
    356                 break;
    357             }
    358         }
    359         sched_yield();
    360         {
    361             unique_lock<_L1> __u1(__l1);
    362             if (__l0.try_lock())
    363             {
    364                 __u1.release();
    365                 break;
    366             }
    367         }
    368         sched_yield();
    369     }
    370 }
    371 
    372 #ifndef _LIBCPP_HAS_NO_VARIADICS
    373 
    374 template <class _L0, class _L1, class _L2, class ..._L3>
    375 void
    376 __lock_first(int __i, _L0& __l0, _L1& __l1, _L2& __l2, _L3& ...__l3)
    377 {
    378     while (true)
    379     {
    380         switch (__i)
    381         {
    382         case 0:
    383             {
    384                 unique_lock<_L0> __u0(__l0);
    385                 __i = try_lock(__l1, __l2, __l3...);
    386                 if (__i == -1)
    387                 {
    388                     __u0.release();
    389                     return;
    390                 }
    391             }
    392             ++__i;
    393             sched_yield();
    394             break;
    395         case 1:
    396             {
    397                 unique_lock<_L1> __u1(__l1);
    398                 __i = try_lock(__l2, __l3..., __l0);
    399                 if (__i == -1)
    400                 {
    401                     __u1.release();
    402                     return;
    403                 }
    404             }
    405             if (__i == sizeof...(_L3) + 1)
    406                 __i = 0;
    407             else
    408                 __i += 2;
    409             sched_yield();
    410             break;
    411         default:
    412             __lock_first(__i - 2, __l2, __l3..., __l0, __l1);
    413             return;
    414         }
    415     }
    416 }
    417 
    418 template <class _L0, class _L1, class _L2, class ..._L3>
    419 inline _LIBCPP_INLINE_VISIBILITY
    420 void
    421 lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3& ...__l3)
    422 {
    423     __lock_first(0, __l0, __l1, __l2, __l3...);
    424 }
    425 
    426 #endif  // _LIBCPP_HAS_NO_VARIADICS
    427 
    428 struct _LIBCPP_VISIBLE once_flag;
    429 
    430 #ifndef _LIBCPP_HAS_NO_VARIADICS
    431 
    432 template<class _Callable, class... _Args>
    433 _LIBCPP_INLINE_VISIBILITY
    434 void call_once(once_flag&, _Callable&&, _Args&&...);
    435 
    436 #else  // _LIBCPP_HAS_NO_VARIADICS
    437 
    438 template<class _Callable>
    439 _LIBCPP_INLINE_VISIBILITY
    440 void call_once(once_flag&, _Callable);
    441 
    442 #endif  // _LIBCPP_HAS_NO_VARIADICS
    443 
    444 struct _LIBCPP_VISIBLE once_flag
    445 {
    446     _LIBCPP_INLINE_VISIBILITY
    447     _LIBCPP_CONSTEXPR
    448         once_flag() _NOEXCEPT : __state_(0) {}
    449 
    450 private:
    451     once_flag(const once_flag&); // = delete;
    452     once_flag& operator=(const once_flag&); // = delete;
    453 
    454     unsigned long __state_;
    455 
    456 #ifndef _LIBCPP_HAS_NO_VARIADICS
    457     template<class _Callable, class... _Args>
    458     friend
    459     void call_once(once_flag&, _Callable&&, _Args&&...);
    460 #else  // _LIBCPP_HAS_NO_VARIADICS
    461     template<class _Callable>
    462     friend
    463     void call_once(once_flag&, _Callable);
    464 #endif  // _LIBCPP_HAS_NO_VARIADICS
    465 };
    466 
    467 #ifndef _LIBCPP_HAS_NO_VARIADICS
    468 
    469 template <class _Fp>
    470 class __call_once_param
    471 {
    472     _Fp __f_;
    473 public:
    474 #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
    475     _LIBCPP_INLINE_VISIBILITY
    476     explicit __call_once_param(_Fp&& __f) : __f_(_VSTD::move(__f)) {}
    477 #else
    478     _LIBCPP_INLINE_VISIBILITY
    479     explicit __call_once_param(const _Fp& __f) : __f_(__f) {}
    480 #endif
    481 
    482     _LIBCPP_INLINE_VISIBILITY
    483     void operator()()
    484     {
    485         typedef typename __make_tuple_indices<tuple_size<_Fp>::value, 1>::type _Index;
    486         __execute(_Index());
    487     }
    488 
    489 private:
    490     template <size_t ..._Indices>
    491     _LIBCPP_INLINE_VISIBILITY
    492     void __execute(__tuple_indices<_Indices...>)
    493     {
    494         __invoke(_VSTD::move(_VSTD::get<0>(__f_)), _VSTD::move(_VSTD::get<_Indices>(__f_))...);
    495     }
    496 };
    497 
    498 #else
    499 
    500 template <class _Fp>
    501 class __call_once_param
    502 {
    503     _Fp __f_;
    504 public:
    505 #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
    506     _LIBCPP_INLINE_VISIBILITY
    507     explicit __call_once_param(_Fp&& __f) : __f_(_VSTD::move(__f)) {}
    508 #else
    509     _LIBCPP_INLINE_VISIBILITY
    510     explicit __call_once_param(const _Fp& __f) : __f_(__f) {}
    511 #endif
    512 
    513     _LIBCPP_INLINE_VISIBILITY
    514     void operator()()
    515     {
    516         __f_();
    517     }
    518 };
    519 
    520 #endif
    521 
    522 template <class _Fp>
    523 void
    524 __call_once_proxy(void* __vp)
    525 {
    526     __call_once_param<_Fp>* __p = static_cast<__call_once_param<_Fp>*>(__vp);
    527     (*__p)();
    528 }
    529 
    530 void __call_once(volatile unsigned long&, void*, void(*)(void*));
    531 
    532 #ifndef _LIBCPP_HAS_NO_VARIADICS
    533 
    534 template<class _Callable, class... _Args>
    535 inline _LIBCPP_INLINE_VISIBILITY
    536 void
    537 call_once(once_flag& __flag, _Callable&& __func, _Args&&... __args)
    538 {
    539     if (__flag.__state_ != ~0ul)
    540     {
    541         typedef tuple<typename decay<_Callable>::type, typename decay<_Args>::type...> _Gp;
    542         __call_once_param<_Gp> __p(_Gp(__decay_copy(_VSTD::forward<_Callable>(__func)),
    543                                 __decay_copy(_VSTD::forward<_Args>(__args))...));
    544         __call_once(__flag.__state_, &__p, &__call_once_proxy<_Gp>);
    545     }
    546 }
    547 
    548 #else  // _LIBCPP_HAS_NO_VARIADICS
    549 
    550 template<class _Callable>
    551 inline _LIBCPP_INLINE_VISIBILITY
    552 void
    553 call_once(once_flag& __flag, _Callable __func)
    554 {
    555     if (__flag.__state_ != ~0ul)
    556     {
    557         __call_once_param<_Callable> __p(__func);
    558         __call_once(__flag.__state_, &__p, &__call_once_proxy<_Callable>);
    559     }
    560 }
    561 
    562 #endif  // _LIBCPP_HAS_NO_VARIADICS
    563 
    564 _LIBCPP_END_NAMESPACE_STD
    565 
    566 #endif  // _LIBCPP_MUTEX
    567