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