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 #include <sched.h>
    182 
    183 #include <__undef_min_max>
    184 
    185 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
    186 #pragma GCC system_header
    187 #endif
    188 
    189 _LIBCPP_BEGIN_NAMESPACE_STD
    190 
    191 #ifndef _LIBCPP_HAS_NO_THREADS
    192 
    193 class _LIBCPP_TYPE_VIS recursive_mutex
    194 {
    195     pthread_mutex_t __m_;
    196 
    197 public:
    198      recursive_mutex();
    199      ~recursive_mutex();
    200 
    201 private:
    202     recursive_mutex(const recursive_mutex&); // = delete;
    203     recursive_mutex& operator=(const recursive_mutex&); // = delete;
    204 
    205 public:
    206     void lock();
    207     bool try_lock() _NOEXCEPT;
    208     void unlock()  _NOEXCEPT;
    209 
    210     typedef pthread_mutex_t* native_handle_type;
    211     _LIBCPP_INLINE_VISIBILITY
    212     native_handle_type native_handle() {return &__m_;}
    213 };
    214 
    215 class _LIBCPP_TYPE_VIS timed_mutex
    216 {
    217     mutex              __m_;
    218     condition_variable __cv_;
    219     bool               __locked_;
    220 public:
    221      timed_mutex();
    222      ~timed_mutex();
    223 
    224 private:
    225     timed_mutex(const timed_mutex&); // = delete;
    226     timed_mutex& operator=(const timed_mutex&); // = delete;
    227 
    228 public:
    229     void lock();
    230     bool try_lock() _NOEXCEPT;
    231     template <class _Rep, class _Period>
    232         _LIBCPP_INLINE_VISIBILITY
    233         bool try_lock_for(const chrono::duration<_Rep, _Period>& __d)
    234             {return try_lock_until(chrono::steady_clock::now() + __d);}
    235     template <class _Clock, class _Duration>
    236         bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
    237     void unlock() _NOEXCEPT;
    238 };
    239 
    240 template <class _Clock, class _Duration>
    241 bool
    242 timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
    243 {
    244     using namespace chrono;
    245     unique_lock<mutex> __lk(__m_);
    246     bool no_timeout = _Clock::now() < __t;
    247     while (no_timeout && __locked_)
    248         no_timeout = __cv_.wait_until(__lk, __t) == cv_status::no_timeout;
    249     if (!__locked_)
    250     {
    251         __locked_ = true;
    252         return true;
    253     }
    254     return false;
    255 }
    256 
    257 class _LIBCPP_TYPE_VIS recursive_timed_mutex
    258 {
    259     mutex              __m_;
    260     condition_variable __cv_;
    261     size_t             __count_;
    262     pthread_t          __id_;
    263 public:
    264      recursive_timed_mutex();
    265      ~recursive_timed_mutex();
    266 
    267 private:
    268     recursive_timed_mutex(const recursive_timed_mutex&); // = delete;
    269     recursive_timed_mutex& operator=(const recursive_timed_mutex&); // = delete;
    270 
    271 public:
    272     void lock();
    273     bool try_lock() _NOEXCEPT;
    274     template <class _Rep, class _Period>
    275         _LIBCPP_INLINE_VISIBILITY
    276         bool try_lock_for(const chrono::duration<_Rep, _Period>& __d)
    277             {return try_lock_until(chrono::steady_clock::now() + __d);}
    278     template <class _Clock, class _Duration>
    279         bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
    280     void unlock() _NOEXCEPT;
    281 };
    282 
    283 template <class _Clock, class _Duration>
    284 bool
    285 recursive_timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
    286 {
    287     using namespace chrono;
    288     pthread_t __id = pthread_self();
    289     unique_lock<mutex> lk(__m_);
    290     if (pthread_equal(__id, __id_))
    291     {
    292         if (__count_ == numeric_limits<size_t>::max())
    293             return false;
    294         ++__count_;
    295         return true;
    296     }
    297     bool no_timeout = _Clock::now() < __t;
    298     while (no_timeout && __count_ != 0)
    299         no_timeout = __cv_.wait_until(lk, __t) == cv_status::no_timeout;
    300     if (__count_ == 0)
    301     {
    302         __count_ = 1;
    303         __id_ = __id;
    304         return true;
    305     }
    306     return false;
    307 }
    308 
    309 template <class _L0, class _L1>
    310 int
    311 try_lock(_L0& __l0, _L1& __l1)
    312 {
    313     unique_lock<_L0> __u0(__l0, try_to_lock);
    314     if (__u0.owns_lock())
    315     {
    316         if (__l1.try_lock())
    317         {
    318             __u0.release();
    319             return -1;
    320         }
    321         else
    322             return 1;
    323     }
    324     return 0;
    325 }
    326 
    327 #ifndef _LIBCPP_HAS_NO_VARIADICS
    328 
    329 template <class _L0, class _L1, class _L2, class... _L3>
    330 int
    331 try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3)
    332 {
    333     int __r = 0;
    334     unique_lock<_L0> __u0(__l0, try_to_lock);
    335     if (__u0.owns_lock())
    336     {
    337         __r = try_lock(__l1, __l2, __l3...);
    338         if (__r == -1)
    339             __u0.release();
    340         else
    341             ++__r;
    342     }
    343     return __r;
    344 }
    345 
    346 #endif  // _LIBCPP_HAS_NO_VARIADICS
    347 
    348 template <class _L0, class _L1>
    349 void
    350 lock(_L0& __l0, _L1& __l1)
    351 {
    352     while (true)
    353     {
    354         {
    355             unique_lock<_L0> __u0(__l0);
    356             if (__l1.try_lock())
    357             {
    358                 __u0.release();
    359                 break;
    360             }
    361         }
    362         sched_yield();
    363         {
    364             unique_lock<_L1> __u1(__l1);
    365             if (__l0.try_lock())
    366             {
    367                 __u1.release();
    368                 break;
    369             }
    370         }
    371         sched_yield();
    372     }
    373 }
    374 
    375 #ifndef _LIBCPP_HAS_NO_VARIADICS
    376 
    377 template <class _L0, class _L1, class _L2, class ..._L3>
    378 void
    379 __lock_first(int __i, _L0& __l0, _L1& __l1, _L2& __l2, _L3& ...__l3)
    380 {
    381     while (true)
    382     {
    383         switch (__i)
    384         {
    385         case 0:
    386             {
    387                 unique_lock<_L0> __u0(__l0);
    388                 __i = try_lock(__l1, __l2, __l3...);
    389                 if (__i == -1)
    390                 {
    391                     __u0.release();
    392                     return;
    393                 }
    394             }
    395             ++__i;
    396             sched_yield();
    397             break;
    398         case 1:
    399             {
    400                 unique_lock<_L1> __u1(__l1);
    401                 __i = try_lock(__l2, __l3..., __l0);
    402                 if (__i == -1)
    403                 {
    404                     __u1.release();
    405                     return;
    406                 }
    407             }
    408             if (__i == sizeof...(_L3) + 1)
    409                 __i = 0;
    410             else
    411                 __i += 2;
    412             sched_yield();
    413             break;
    414         default:
    415             __lock_first(__i - 2, __l2, __l3..., __l0, __l1);
    416             return;
    417         }
    418     }
    419 }
    420 
    421 template <class _L0, class _L1, class _L2, class ..._L3>
    422 inline _LIBCPP_INLINE_VISIBILITY
    423 void
    424 lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3& ...__l3)
    425 {
    426     __lock_first(0, __l0, __l1, __l2, __l3...);
    427 }
    428 
    429 #endif  // _LIBCPP_HAS_NO_VARIADICS
    430 
    431 #endif // !_LIBCPP_HAS_NO_THREADS
    432 
    433 struct _LIBCPP_TYPE_VIS_ONLY once_flag;
    434 
    435 #ifndef _LIBCPP_HAS_NO_VARIADICS
    436 
    437 template<class _Callable, class... _Args>
    438 _LIBCPP_INLINE_VISIBILITY
    439 void call_once(once_flag&, _Callable&&, _Args&&...);
    440 
    441 #else  // _LIBCPP_HAS_NO_VARIADICS
    442 
    443 template<class _Callable>
    444 _LIBCPP_INLINE_VISIBILITY
    445 void call_once(once_flag&, _Callable);
    446 
    447 #endif  // _LIBCPP_HAS_NO_VARIADICS
    448 
    449 struct _LIBCPP_TYPE_VIS_ONLY once_flag
    450 {
    451     _LIBCPP_INLINE_VISIBILITY
    452     _LIBCPP_CONSTEXPR
    453         once_flag() _NOEXCEPT : __state_(0) {}
    454 
    455 private:
    456     once_flag(const once_flag&); // = delete;
    457     once_flag& operator=(const once_flag&); // = delete;
    458 
    459     unsigned long __state_;
    460 
    461 #ifndef _LIBCPP_HAS_NO_VARIADICS
    462     template<class _Callable, class... _Args>
    463     friend
    464     void call_once(once_flag&, _Callable&&, _Args&&...);
    465 #else  // _LIBCPP_HAS_NO_VARIADICS
    466     template<class _Callable>
    467     friend
    468     void call_once(once_flag&, _Callable);
    469 #endif  // _LIBCPP_HAS_NO_VARIADICS
    470 };
    471 
    472 #ifndef _LIBCPP_HAS_NO_VARIADICS
    473 
    474 template <class _Fp>
    475 class __call_once_param
    476 {
    477     _Fp __f_;
    478 public:
    479 #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
    480     _LIBCPP_INLINE_VISIBILITY
    481     explicit __call_once_param(_Fp&& __f) : __f_(_VSTD::move(__f)) {}
    482 #else
    483     _LIBCPP_INLINE_VISIBILITY
    484     explicit __call_once_param(const _Fp& __f) : __f_(__f) {}
    485 #endif
    486 
    487     _LIBCPP_INLINE_VISIBILITY
    488     void operator()()
    489     {
    490         typedef typename __make_tuple_indices<tuple_size<_Fp>::value, 1>::type _Index;
    491         __execute(_Index());
    492     }
    493 
    494 private:
    495     template <size_t ..._Indices>
    496     _LIBCPP_INLINE_VISIBILITY
    497     void __execute(__tuple_indices<_Indices...>)
    498     {
    499         __invoke(_VSTD::move(_VSTD::get<0>(__f_)), _VSTD::move(_VSTD::get<_Indices>(__f_))...);
    500     }
    501 };
    502 
    503 #else
    504 
    505 template <class _Fp>
    506 class __call_once_param
    507 {
    508     _Fp __f_;
    509 public:
    510 #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
    511     _LIBCPP_INLINE_VISIBILITY
    512     explicit __call_once_param(_Fp&& __f) : __f_(_VSTD::move(__f)) {}
    513 #else
    514     _LIBCPP_INLINE_VISIBILITY
    515     explicit __call_once_param(const _Fp& __f) : __f_(__f) {}
    516 #endif
    517 
    518     _LIBCPP_INLINE_VISIBILITY
    519     void operator()()
    520     {
    521         __f_();
    522     }
    523 };
    524 
    525 #endif
    526 
    527 template <class _Fp>
    528 void
    529 __call_once_proxy(void* __vp)
    530 {
    531     __call_once_param<_Fp>* __p = static_cast<__call_once_param<_Fp>*>(__vp);
    532     (*__p)();
    533 }
    534 
    535 _LIBCPP_FUNC_VIS void __call_once(volatile unsigned long&, void*, void(*)(void*));
    536 
    537 #ifndef _LIBCPP_HAS_NO_VARIADICS
    538 
    539 template<class _Callable, class... _Args>
    540 inline _LIBCPP_INLINE_VISIBILITY
    541 void
    542 call_once(once_flag& __flag, _Callable&& __func, _Args&&... __args)
    543 {
    544     if (__flag.__state_ != ~0ul)
    545     {
    546         typedef tuple<typename decay<_Callable>::type, typename decay<_Args>::type...> _Gp;
    547         __call_once_param<_Gp> __p(_Gp(__decay_copy(_VSTD::forward<_Callable>(__func)),
    548                                 __decay_copy(_VSTD::forward<_Args>(__args))...));
    549         __call_once(__flag.__state_, &__p, &__call_once_proxy<_Gp>);
    550     }
    551 }
    552 
    553 #else  // _LIBCPP_HAS_NO_VARIADICS
    554 
    555 template<class _Callable>
    556 inline _LIBCPP_INLINE_VISIBILITY
    557 void
    558 call_once(once_flag& __flag, _Callable __func)
    559 {
    560     if (__flag.__state_ != ~0ul)
    561     {
    562         __call_once_param<_Callable> __p(__func);
    563         __call_once(__flag.__state_, &__p, &__call_once_proxy<_Callable>);
    564     }
    565 }
    566 
    567 #endif  // _LIBCPP_HAS_NO_VARIADICS
    568 
    569 _LIBCPP_END_NAMESPACE_STD
    570 
    571 #endif  // _LIBCPP_MUTEX
    572