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 
    128 _LIBCPP_PUSH_MACROS
    129 #include <__undef_macros>
    130 
    131 
    132 #if _LIBCPP_STD_VER > 11 || defined(_LIBCPP_BUILDING_SHARED_MUTEX)
    133 
    134 #include <__mutex_base>
    135 
    136 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
    137 #pragma GCC system_header
    138 #endif
    139 
    140 #ifdef _LIBCPP_HAS_NO_THREADS
    141 #error <shared_mutex> is not supported on this single threaded system
    142 #else // !_LIBCPP_HAS_NO_THREADS
    143 
    144 _LIBCPP_BEGIN_NAMESPACE_STD
    145 
    146 struct _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX __shared_mutex_base
    147 {
    148     mutex               __mut_;
    149     condition_variable  __gate1_;
    150     condition_variable  __gate2_;
    151     unsigned            __state_;
    152 
    153     static const unsigned __write_entered_ = 1U << (sizeof(unsigned)*__CHAR_BIT__ - 1);
    154     static const unsigned __n_readers_ = ~__write_entered_;
    155 
    156     __shared_mutex_base();
    157     _LIBCPP_INLINE_VISIBILITY ~__shared_mutex_base() = default;
    158 
    159     __shared_mutex_base(const __shared_mutex_base&) = delete;
    160     __shared_mutex_base& operator=(const __shared_mutex_base&) = delete;
    161 
    162     // Exclusive ownership
    163     void lock(); // blocking
    164     bool try_lock();
    165     void unlock();
    166 
    167     // Shared ownership
    168     void lock_shared(); // blocking
    169     bool try_lock_shared();
    170     void unlock_shared();
    171 
    172 //     typedef implementation-defined native_handle_type; // See 30.2.3
    173 //     native_handle_type native_handle(); // See 30.2.3
    174 };
    175 
    176 
    177 #if _LIBCPP_STD_VER > 14
    178 class _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_mutex
    179 {
    180     __shared_mutex_base __base;
    181 public:
    182     _LIBCPP_INLINE_VISIBILITY shared_mutex() : __base() {}
    183     _LIBCPP_INLINE_VISIBILITY ~shared_mutex() = default;
    184 
    185     shared_mutex(const shared_mutex&) = delete;
    186     shared_mutex& operator=(const shared_mutex&) = delete;
    187 
    188     // Exclusive ownership
    189     _LIBCPP_INLINE_VISIBILITY void lock()     { return __base.lock(); }
    190     _LIBCPP_INLINE_VISIBILITY bool try_lock() { return __base.try_lock(); }
    191     _LIBCPP_INLINE_VISIBILITY void unlock()   { return __base.unlock(); }
    192 
    193     // Shared ownership
    194     _LIBCPP_INLINE_VISIBILITY void lock_shared()     { return __base.lock_shared(); }
    195     _LIBCPP_INLINE_VISIBILITY bool try_lock_shared() { return __base.try_lock_shared(); }
    196     _LIBCPP_INLINE_VISIBILITY void unlock_shared()   { return __base.unlock_shared(); }
    197 
    198 //     typedef __shared_mutex_base::native_handle_type native_handle_type;
    199 //     _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() { return __base::unlock_shared(); }
    200 };
    201 #endif
    202 
    203 
    204 class _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_timed_mutex
    205 {
    206     __shared_mutex_base __base;
    207 public:
    208     shared_timed_mutex();
    209     _LIBCPP_INLINE_VISIBILITY ~shared_timed_mutex() = default;
    210 
    211     shared_timed_mutex(const shared_timed_mutex&) = delete;
    212     shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
    213 
    214     // Exclusive ownership
    215     void lock();
    216     bool try_lock();
    217     template <class _Rep, class _Period>
    218         _LIBCPP_INLINE_VISIBILITY
    219         bool
    220         try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
    221         {
    222             return try_lock_until(chrono::steady_clock::now() + __rel_time);
    223         }
    224     template <class _Clock, class _Duration>
    225         _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
    226         bool
    227         try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
    228     void unlock();
    229 
    230     // Shared ownership
    231     void lock_shared();
    232     bool try_lock_shared();
    233     template <class _Rep, class _Period>
    234         _LIBCPP_INLINE_VISIBILITY
    235         bool
    236         try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
    237         {
    238             return try_lock_shared_until(chrono::steady_clock::now() + __rel_time);
    239         }
    240     template <class _Clock, class _Duration>
    241         _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
    242         bool
    243         try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
    244     void unlock_shared();
    245 };
    246 
    247 template <class _Clock, class _Duration>
    248 bool
    249 shared_timed_mutex::try_lock_until(
    250                         const chrono::time_point<_Clock, _Duration>& __abs_time)
    251 {
    252     unique_lock<mutex> __lk(__base.__mut_);
    253     if (__base.__state_ & __base.__write_entered_)
    254     {
    255         while (true)
    256         {
    257             cv_status __status = __base.__gate1_.wait_until(__lk, __abs_time);
    258             if ((__base.__state_ & __base.__write_entered_) == 0)
    259                 break;
    260             if (__status == cv_status::timeout)
    261                 return false;
    262         }
    263     }
    264     __base.__state_ |= __base.__write_entered_;
    265     if (__base.__state_ & __base.__n_readers_)
    266     {
    267         while (true)
    268         {
    269             cv_status __status = __base.__gate2_.wait_until(__lk, __abs_time);
    270             if ((__base.__state_ & __base.__n_readers_) == 0)
    271                 break;
    272             if (__status == cv_status::timeout)
    273             {
    274                 __base.__state_ &= ~__base.__write_entered_;
    275                 __base.__gate1_.notify_all();
    276                 return false;
    277             }
    278         }
    279     }
    280     return true;
    281 }
    282 
    283 template <class _Clock, class _Duration>
    284 bool
    285 shared_timed_mutex::try_lock_shared_until(
    286                         const chrono::time_point<_Clock, _Duration>& __abs_time)
    287 {
    288     unique_lock<mutex> __lk(__base.__mut_);
    289     if ((__base.__state_ & __base.__write_entered_) || (__base.__state_ & __base.__n_readers_) == __base.__n_readers_)
    290     {
    291         while (true)
    292         {
    293             cv_status status = __base.__gate1_.wait_until(__lk, __abs_time);
    294             if ((__base.__state_ & __base.__write_entered_) == 0 &&
    295                                        (__base.__state_ & __base.__n_readers_) < __base.__n_readers_)
    296                 break;
    297             if (status == cv_status::timeout)
    298                 return false;
    299         }
    300     }
    301     unsigned __num_readers = (__base.__state_ & __base.__n_readers_) + 1;
    302     __base.__state_ &= ~__base.__n_readers_;
    303     __base.__state_ |= __num_readers;
    304     return true;
    305 }
    306 
    307 template <class _Mutex>
    308 class shared_lock
    309 {
    310 public:
    311     typedef _Mutex mutex_type;
    312 
    313 private:
    314     mutex_type* __m_;
    315     bool __owns_;
    316 
    317 public:
    318     _LIBCPP_INLINE_VISIBILITY
    319     shared_lock() _NOEXCEPT
    320         : __m_(nullptr),
    321           __owns_(false)
    322         {}
    323 
    324     _LIBCPP_INLINE_VISIBILITY
    325     explicit shared_lock(mutex_type& __m)
    326         : __m_(_VSTD::addressof(__m)),
    327           __owns_(true)
    328         {__m_->lock_shared();}
    329 
    330     _LIBCPP_INLINE_VISIBILITY
    331     shared_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
    332         : __m_(_VSTD::addressof(__m)),
    333           __owns_(false)
    334         {}
    335 
    336     _LIBCPP_INLINE_VISIBILITY
    337     shared_lock(mutex_type& __m, try_to_lock_t)
    338         : __m_(_VSTD::addressof(__m)),
    339           __owns_(__m.try_lock_shared())
    340         {}
    341 
    342     _LIBCPP_INLINE_VISIBILITY
    343     shared_lock(mutex_type& __m, adopt_lock_t)
    344         : __m_(_VSTD::addressof(__m)),
    345           __owns_(true)
    346         {}
    347 
    348     template <class _Clock, class _Duration>
    349         _LIBCPP_INLINE_VISIBILITY
    350         shared_lock(mutex_type& __m,
    351                     const chrono::time_point<_Clock, _Duration>& __abs_time)
    352             : __m_(_VSTD::addressof(__m)),
    353               __owns_(__m.try_lock_shared_until(__abs_time))
    354             {}
    355 
    356     template <class _Rep, class _Period>
    357         _LIBCPP_INLINE_VISIBILITY
    358         shared_lock(mutex_type& __m,
    359                     const chrono::duration<_Rep, _Period>& __rel_time)
    360             : __m_(_VSTD::addressof(__m)),
    361               __owns_(__m.try_lock_shared_for(__rel_time))
    362             {}
    363 
    364     _LIBCPP_INLINE_VISIBILITY
    365     ~shared_lock()
    366     {
    367         if (__owns_)
    368             __m_->unlock_shared();
    369     }
    370 
    371     shared_lock(shared_lock const&) = delete;
    372     shared_lock& operator=(shared_lock const&) = delete;
    373 
    374     _LIBCPP_INLINE_VISIBILITY
    375     shared_lock(shared_lock&& __u) _NOEXCEPT
    376         : __m_(__u.__m_),
    377           __owns_(__u.__owns_)
    378         {
    379             __u.__m_ = nullptr;
    380             __u.__owns_ = false;
    381         }
    382 
    383     _LIBCPP_INLINE_VISIBILITY
    384     shared_lock& operator=(shared_lock&& __u) _NOEXCEPT
    385     {
    386         if (__owns_)
    387             __m_->unlock_shared();
    388         __m_ = nullptr;
    389         __owns_ = false;
    390         __m_ = __u.__m_;
    391         __owns_ = __u.__owns_;
    392         __u.__m_ = nullptr;
    393         __u.__owns_ = false;
    394         return *this;
    395     }
    396 
    397     void lock();
    398     bool try_lock();
    399     template <class Rep, class Period>
    400         bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
    401     template <class Clock, class Duration>
    402         bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
    403     void unlock();
    404 
    405     // Setters
    406     _LIBCPP_INLINE_VISIBILITY
    407     void swap(shared_lock& __u) _NOEXCEPT
    408     {
    409         _VSTD::swap(__m_, __u.__m_);
    410         _VSTD::swap(__owns_, __u.__owns_);
    411     }
    412 
    413     _LIBCPP_INLINE_VISIBILITY
    414     mutex_type* release() _NOEXCEPT
    415     {
    416         mutex_type* __m = __m_;
    417         __m_ = nullptr;
    418         __owns_ = false;
    419         return __m;
    420     }
    421 
    422     // Getters
    423     _LIBCPP_INLINE_VISIBILITY
    424     bool owns_lock() const _NOEXCEPT {return __owns_;}
    425 
    426     _LIBCPP_INLINE_VISIBILITY
    427     explicit operator bool () const _NOEXCEPT {return __owns_;}
    428 
    429     _LIBCPP_INLINE_VISIBILITY
    430     mutex_type* mutex() const _NOEXCEPT {return __m_;}
    431 };
    432 
    433 template <class _Mutex>
    434 void
    435 shared_lock<_Mutex>::lock()
    436 {
    437     if (__m_ == nullptr)
    438         __throw_system_error(EPERM, "shared_lock::lock: references null mutex");
    439     if (__owns_)
    440         __throw_system_error(EDEADLK, "shared_lock::lock: already locked");
    441     __m_->lock_shared();
    442     __owns_ = true;
    443 }
    444 
    445 template <class _Mutex>
    446 bool
    447 shared_lock<_Mutex>::try_lock()
    448 {
    449     if (__m_ == nullptr)
    450         __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex");
    451     if (__owns_)
    452         __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked");
    453     __owns_ = __m_->try_lock_shared();
    454     return __owns_;
    455 }
    456 
    457 template <class _Mutex>
    458 template <class _Rep, class _Period>
    459 bool
    460 shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
    461 {
    462     if (__m_ == nullptr)
    463         __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex");
    464     if (__owns_)
    465         __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked");
    466     __owns_ = __m_->try_lock_shared_for(__d);
    467     return __owns_;
    468 }
    469 
    470 template <class _Mutex>
    471 template <class _Clock, class _Duration>
    472 bool
    473 shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
    474 {
    475     if (__m_ == nullptr)
    476         __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex");
    477     if (__owns_)
    478         __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked");
    479     __owns_ = __m_->try_lock_shared_until(__t);
    480     return __owns_;
    481 }
    482 
    483 template <class _Mutex>
    484 void
    485 shared_lock<_Mutex>::unlock()
    486 {
    487     if (!__owns_)
    488         __throw_system_error(EPERM, "shared_lock::unlock: not locked");
    489     __m_->unlock_shared();
    490     __owns_ = false;
    491 }
    492 
    493 template <class _Mutex>
    494 inline _LIBCPP_INLINE_VISIBILITY
    495 void
    496 swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) _NOEXCEPT
    497     {__x.swap(__y);}
    498 
    499 _LIBCPP_END_NAMESPACE_STD
    500 
    501 #endif  // !_LIBCPP_HAS_NO_THREADS
    502 
    503 #endif  // _LIBCPP_STD_VER > 11
    504 
    505 _LIBCPP_POP_MACROS
    506 
    507 #endif  // _LIBCPP_SHARED_MUTEX
    508