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