Home | History | Annotate | Download | only in include
      1 // -*- C++ -*-
      2 //===------------------------ shared_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_SHARED_MUTEX
     12 #define _LIBCPP_SHARED_MUTEX
     13 
     14 /*
     15     shared_mutex synopsis
     16 
     17 // C++1y
     18 
     19 namespace std
     20 {
     21 
     22 class shared_mutex      // C++17
     23 {
     24 public:
     25     shared_mutex();
     26     ~shared_mutex();
     27 
     28     shared_mutex(const shared_mutex&) = delete;
     29     shared_mutex& operator=(const shared_mutex&) = delete;
     30 
     31     // Exclusive ownership
     32     void lock(); // blocking
     33     bool try_lock();
     34     void unlock();
     35 
     36     // Shared ownership
     37     void lock_shared(); // blocking
     38     bool try_lock_shared();
     39     void unlock_shared();
     40 
     41     typedef implementation-defined native_handle_type; // See 30.2.3
     42     native_handle_type native_handle(); // See 30.2.3
     43 };
     44 
     45 class shared_timed_mutex
     46 {
     47 public:
     48     shared_timed_mutex();
     49     ~shared_timed_mutex();
     50 
     51     shared_timed_mutex(const shared_timed_mutex&) = delete;
     52     shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
     53 
     54     // Exclusive ownership
     55     void lock(); // blocking
     56     bool try_lock();
     57     template <class Rep, class Period>
     58         bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
     59     template <class Clock, class Duration>
     60         bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
     61     void unlock();
     62 
     63     // Shared ownership
     64     void lock_shared(); // blocking
     65     bool try_lock_shared();
     66     template <class Rep, class Period>
     67         bool
     68         try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time);
     69     template <class Clock, class Duration>
     70         bool
     71         try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time);
     72     void unlock_shared();
     73 };
     74 
     75 template <class Mutex>
     76 class shared_lock
     77 {
     78 public:
     79     typedef Mutex mutex_type;
     80 
     81     // Shared locking
     82     shared_lock() noexcept;
     83     explicit shared_lock(mutex_type& m); // blocking
     84     shared_lock(mutex_type& m, defer_lock_t) noexcept;
     85     shared_lock(mutex_type& m, try_to_lock_t);
     86     shared_lock(mutex_type& m, adopt_lock_t);
     87     template <class Clock, class Duration>
     88         shared_lock(mutex_type& m,
     89                     const chrono::time_point<Clock, Duration>& abs_time);
     90     template <class Rep, class Period>
     91         shared_lock(mutex_type& m,
     92                     const chrono::duration<Rep, Period>& rel_time);
     93     ~shared_lock();
     94 
     95     shared_lock(shared_lock const&) = delete;
     96     shared_lock& operator=(shared_lock const&) = delete;
     97 
     98     shared_lock(shared_lock&& u) noexcept;
     99     shared_lock& operator=(shared_lock&& u) noexcept;
    100 
    101     void lock(); // blocking
    102     bool try_lock();
    103     template <class Rep, class Period>
    104         bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
    105     template <class Clock, class Duration>
    106         bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
    107     void unlock();
    108 
    109     // Setters
    110     void swap(shared_lock& u) noexcept;
    111     mutex_type* release() noexcept;
    112 
    113     // Getters
    114     bool owns_lock() const noexcept;
    115     explicit operator bool () const noexcept;
    116     mutex_type* mutex() const noexcept;
    117 };
    118 
    119 template <class Mutex>
    120     void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
    121 
    122 }  // std
    123 
    124 */
    125 
    126 #include <__config>
    127 #include <version>
    128 
    129 _LIBCPP_PUSH_MACROS
    130 #include <__undef_macros>
    131 
    132 
    133 #if _LIBCPP_STD_VER > 11 || defined(_LIBCPP_BUILDING_LIBRARY)
    134 
    135 #include <__mutex_base>
    136 
    137 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
    138 #pragma GCC system_header
    139 #endif
    140 
    141 #ifdef _LIBCPP_HAS_NO_THREADS
    142 #error <shared_mutex> is not supported on this single threaded system
    143 #else // !_LIBCPP_HAS_NO_THREADS
    144 
    145 _LIBCPP_BEGIN_NAMESPACE_STD
    146 
    147 struct _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("shared_mutex"))
    148 __shared_mutex_base
    149 {
    150     mutex               __mut_;
    151     condition_variable  __gate1_;
    152     condition_variable  __gate2_;
    153     unsigned            __state_;
    154 
    155     static const unsigned __write_entered_ = 1U << (sizeof(unsigned)*__CHAR_BIT__ - 1);
    156     static const unsigned __n_readers_ = ~__write_entered_;
    157 
    158     __shared_mutex_base();
    159     _LIBCPP_INLINE_VISIBILITY ~__shared_mutex_base() = default;
    160 
    161     __shared_mutex_base(const __shared_mutex_base&) = delete;
    162     __shared_mutex_base& operator=(const __shared_mutex_base&) = delete;
    163 
    164     // Exclusive ownership
    165     void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability()); // blocking
    166     bool try_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_capability(true));
    167     void unlock() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability());
    168 
    169     // Shared ownership
    170     void lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_shared_capability()); // blocking
    171     bool try_lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_shared_capability(true));
    172     void unlock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_shared_capability());
    173 
    174 //     typedef implementation-defined native_handle_type; // See 30.2.3
    175 //     native_handle_type native_handle(); // See 30.2.3
    176 };
    177 
    178 
    179 #if _LIBCPP_STD_VER > 14
    180 class _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_mutex
    181 {
    182     __shared_mutex_base __base;
    183 public:
    184     _LIBCPP_INLINE_VISIBILITY shared_mutex() : __base() {}
    185     _LIBCPP_INLINE_VISIBILITY ~shared_mutex() = default;
    186 
    187     shared_mutex(const shared_mutex&) = delete;
    188     shared_mutex& operator=(const shared_mutex&) = delete;
    189 
    190     // Exclusive ownership
    191     _LIBCPP_INLINE_VISIBILITY void lock()     { return __base.lock(); }
    192     _LIBCPP_INLINE_VISIBILITY bool try_lock() { return __base.try_lock(); }
    193     _LIBCPP_INLINE_VISIBILITY void unlock()   { return __base.unlock(); }
    194 
    195     // Shared ownership
    196     _LIBCPP_INLINE_VISIBILITY void lock_shared()     { return __base.lock_shared(); }
    197     _LIBCPP_INLINE_VISIBILITY bool try_lock_shared() { return __base.try_lock_shared(); }
    198     _LIBCPP_INLINE_VISIBILITY void unlock_shared()   { return __base.unlock_shared(); }
    199 
    200 //     typedef __shared_mutex_base::native_handle_type native_handle_type;
    201 //     _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() { return __base::unlock_shared(); }
    202 };
    203 #endif
    204 
    205 
    206 class _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_timed_mutex
    207 {
    208     __shared_mutex_base __base;
    209 public:
    210     shared_timed_mutex();
    211     _LIBCPP_INLINE_VISIBILITY ~shared_timed_mutex() = default;
    212 
    213     shared_timed_mutex(const shared_timed_mutex&) = delete;
    214     shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
    215 
    216     // Exclusive ownership
    217     void lock();
    218     bool try_lock();
    219     template <class _Rep, class _Period>
    220         _LIBCPP_INLINE_VISIBILITY
    221         bool
    222         try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
    223         {
    224             return try_lock_until(chrono::steady_clock::now() + __rel_time);
    225         }
    226     template <class _Clock, class _Duration>
    227         _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
    228         bool
    229         try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
    230     void unlock();
    231 
    232     // Shared ownership
    233     void lock_shared();
    234     bool try_lock_shared();
    235     template <class _Rep, class _Period>
    236         _LIBCPP_INLINE_VISIBILITY
    237         bool
    238         try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
    239         {
    240             return try_lock_shared_until(chrono::steady_clock::now() + __rel_time);
    241         }
    242     template <class _Clock, class _Duration>
    243         _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
    244         bool
    245         try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
    246     void unlock_shared();
    247 };
    248 
    249 template <class _Clock, class _Duration>
    250 bool
    251 shared_timed_mutex::try_lock_until(
    252                         const chrono::time_point<_Clock, _Duration>& __abs_time)
    253 {
    254     unique_lock<mutex> __lk(__base.__mut_);
    255     if (__base.__state_ & __base.__write_entered_)
    256     {
    257         while (true)
    258         {
    259             cv_status __status = __base.__gate1_.wait_until(__lk, __abs_time);
    260             if ((__base.__state_ & __base.__write_entered_) == 0)
    261                 break;
    262             if (__status == cv_status::timeout)
    263                 return false;
    264         }
    265     }
    266     __base.__state_ |= __base.__write_entered_;
    267     if (__base.__state_ & __base.__n_readers_)
    268     {
    269         while (true)
    270         {
    271             cv_status __status = __base.__gate2_.wait_until(__lk, __abs_time);
    272             if ((__base.__state_ & __base.__n_readers_) == 0)
    273                 break;
    274             if (__status == cv_status::timeout)
    275             {
    276                 __base.__state_ &= ~__base.__write_entered_;
    277                 __base.__gate1_.notify_all();
    278                 return false;
    279             }
    280         }
    281     }
    282     return true;
    283 }
    284 
    285 template <class _Clock, class _Duration>
    286 bool
    287 shared_timed_mutex::try_lock_shared_until(
    288                         const chrono::time_point<_Clock, _Duration>& __abs_time)
    289 {
    290     unique_lock<mutex> __lk(__base.__mut_);
    291     if ((__base.__state_ & __base.__write_entered_) || (__base.__state_ & __base.__n_readers_) == __base.__n_readers_)
    292     {
    293         while (true)
    294         {
    295             cv_status status = __base.__gate1_.wait_until(__lk, __abs_time);
    296             if ((__base.__state_ & __base.__write_entered_) == 0 &&
    297                                        (__base.__state_ & __base.__n_readers_) < __base.__n_readers_)
    298                 break;
    299             if (status == cv_status::timeout)
    300                 return false;
    301         }
    302     }
    303     unsigned __num_readers = (__base.__state_ & __base.__n_readers_) + 1;
    304     __base.__state_ &= ~__base.__n_readers_;
    305     __base.__state_ |= __num_readers;
    306     return true;
    307 }
    308 
    309 template <class _Mutex>
    310 class shared_lock
    311 {
    312 public:
    313     typedef _Mutex mutex_type;
    314 
    315 private:
    316     mutex_type* __m_;
    317     bool __owns_;
    318 
    319 public:
    320     _LIBCPP_INLINE_VISIBILITY
    321     shared_lock() _NOEXCEPT
    322         : __m_(nullptr),
    323           __owns_(false)
    324         {}
    325 
    326     _LIBCPP_INLINE_VISIBILITY
    327     explicit shared_lock(mutex_type& __m)
    328         : __m_(_VSTD::addressof(__m)),
    329           __owns_(true)
    330         {__m_->lock_shared();}
    331 
    332     _LIBCPP_INLINE_VISIBILITY
    333     shared_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
    334         : __m_(_VSTD::addressof(__m)),
    335           __owns_(false)
    336         {}
    337 
    338     _LIBCPP_INLINE_VISIBILITY
    339     shared_lock(mutex_type& __m, try_to_lock_t)
    340         : __m_(_VSTD::addressof(__m)),
    341           __owns_(__m.try_lock_shared())
    342         {}
    343 
    344     _LIBCPP_INLINE_VISIBILITY
    345     shared_lock(mutex_type& __m, adopt_lock_t)
    346         : __m_(_VSTD::addressof(__m)),
    347           __owns_(true)
    348         {}
    349 
    350     template <class _Clock, class _Duration>
    351         _LIBCPP_INLINE_VISIBILITY
    352         shared_lock(mutex_type& __m,
    353                     const chrono::time_point<_Clock, _Duration>& __abs_time)
    354             : __m_(_VSTD::addressof(__m)),
    355               __owns_(__m.try_lock_shared_until(__abs_time))
    356             {}
    357 
    358     template <class _Rep, class _Period>
    359         _LIBCPP_INLINE_VISIBILITY
    360         shared_lock(mutex_type& __m,
    361                     const chrono::duration<_Rep, _Period>& __rel_time)
    362             : __m_(_VSTD::addressof(__m)),
    363               __owns_(__m.try_lock_shared_for(__rel_time))
    364             {}
    365 
    366     _LIBCPP_INLINE_VISIBILITY
    367     ~shared_lock()
    368     {
    369         if (__owns_)
    370             __m_->unlock_shared();
    371     }
    372 
    373     shared_lock(shared_lock const&) = delete;
    374     shared_lock& operator=(shared_lock const&) = delete;
    375 
    376     _LIBCPP_INLINE_VISIBILITY
    377     shared_lock(shared_lock&& __u) _NOEXCEPT
    378         : __m_(__u.__m_),
    379           __owns_(__u.__owns_)
    380         {
    381             __u.__m_ = nullptr;
    382             __u.__owns_ = false;
    383         }
    384 
    385     _LIBCPP_INLINE_VISIBILITY
    386     shared_lock& operator=(shared_lock&& __u) _NOEXCEPT
    387     {
    388         if (__owns_)
    389             __m_->unlock_shared();
    390         __m_ = nullptr;
    391         __owns_ = false;
    392         __m_ = __u.__m_;
    393         __owns_ = __u.__owns_;
    394         __u.__m_ = nullptr;
    395         __u.__owns_ = false;
    396         return *this;
    397     }
    398 
    399     void lock();
    400     bool try_lock();
    401     template <class Rep, class Period>
    402         bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
    403     template <class Clock, class Duration>
    404         bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
    405     void unlock();
    406 
    407     // Setters
    408     _LIBCPP_INLINE_VISIBILITY
    409     void swap(shared_lock& __u) _NOEXCEPT
    410     {
    411         _VSTD::swap(__m_, __u.__m_);
    412         _VSTD::swap(__owns_, __u.__owns_);
    413     }
    414 
    415     _LIBCPP_INLINE_VISIBILITY
    416     mutex_type* release() _NOEXCEPT
    417     {
    418         mutex_type* __m = __m_;
    419         __m_ = nullptr;
    420         __owns_ = false;
    421         return __m;
    422     }
    423 
    424     // Getters
    425     _LIBCPP_INLINE_VISIBILITY
    426     bool owns_lock() const _NOEXCEPT {return __owns_;}
    427 
    428     _LIBCPP_INLINE_VISIBILITY
    429     explicit operator bool () const _NOEXCEPT {return __owns_;}
    430 
    431     _LIBCPP_INLINE_VISIBILITY
    432     mutex_type* mutex() const _NOEXCEPT {return __m_;}
    433 };
    434 
    435 template <class _Mutex>
    436 void
    437 shared_lock<_Mutex>::lock()
    438 {
    439     if (__m_ == nullptr)
    440         __throw_system_error(EPERM, "shared_lock::lock: references null mutex");
    441     if (__owns_)
    442         __throw_system_error(EDEADLK, "shared_lock::lock: already locked");
    443     __m_->lock_shared();
    444     __owns_ = true;
    445 }
    446 
    447 template <class _Mutex>
    448 bool
    449 shared_lock<_Mutex>::try_lock()
    450 {
    451     if (__m_ == nullptr)
    452         __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex");
    453     if (__owns_)
    454         __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked");
    455     __owns_ = __m_->try_lock_shared();
    456     return __owns_;
    457 }
    458 
    459 template <class _Mutex>
    460 template <class _Rep, class _Period>
    461 bool
    462 shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
    463 {
    464     if (__m_ == nullptr)
    465         __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex");
    466     if (__owns_)
    467         __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked");
    468     __owns_ = __m_->try_lock_shared_for(__d);
    469     return __owns_;
    470 }
    471 
    472 template <class _Mutex>
    473 template <class _Clock, class _Duration>
    474 bool
    475 shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
    476 {
    477     if (__m_ == nullptr)
    478         __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex");
    479     if (__owns_)
    480         __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked");
    481     __owns_ = __m_->try_lock_shared_until(__t);
    482     return __owns_;
    483 }
    484 
    485 template <class _Mutex>
    486 void
    487 shared_lock<_Mutex>::unlock()
    488 {
    489     if (!__owns_)
    490         __throw_system_error(EPERM, "shared_lock::unlock: not locked");
    491     __m_->unlock_shared();
    492     __owns_ = false;
    493 }
    494 
    495 template <class _Mutex>
    496 inline _LIBCPP_INLINE_VISIBILITY
    497 void
    498 swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) _NOEXCEPT
    499     {__x.swap(__y);}
    500 
    501 _LIBCPP_END_NAMESPACE_STD
    502 
    503 #endif  // !_LIBCPP_HAS_NO_THREADS
    504 
    505 #endif  // _LIBCPP_STD_VER > 11
    506 
    507 _LIBCPP_POP_MACROS
    508 
    509 #endif  // _LIBCPP_SHARED_MUTEX
    510