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