Home | History | Annotate | Download | only in v1
      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         _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
    224         bool
    225         try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
    226     void unlock();
    227 
    228     // Shared ownership
    229     void lock_shared();
    230     bool try_lock_shared();
    231     template <class _Rep, class _Period>
    232         _LIBCPP_INLINE_VISIBILITY
    233         bool
    234         try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
    235         {
    236             return try_lock_shared_until(chrono::steady_clock::now() + __rel_time);
    237         }
    238     template <class _Clock, class _Duration>
    239         _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
    240         bool
    241         try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
    242     void unlock_shared();
    243 };
    244 
    245 template <class _Clock, class _Duration>
    246 bool
    247 shared_timed_mutex::try_lock_until(
    248                         const chrono::time_point<_Clock, _Duration>& __abs_time)
    249 {
    250     unique_lock<mutex> __lk(__base.__mut_);
    251     if (__base.__state_ & __base.__write_entered_)
    252     {
    253         while (true)
    254         {
    255             cv_status __status = __base.__gate1_.wait_until(__lk, __abs_time);
    256             if ((__base.__state_ & __base.__write_entered_) == 0)
    257                 break;
    258             if (__status == cv_status::timeout)
    259                 return false;
    260         }
    261     }
    262     __base.__state_ |= __base.__write_entered_;
    263     if (__base.__state_ & __base.__n_readers_)
    264     {
    265         while (true)
    266         {
    267             cv_status __status = __base.__gate2_.wait_until(__lk, __abs_time);
    268             if ((__base.__state_ & __base.__n_readers_) == 0)
    269                 break;
    270             if (__status == cv_status::timeout)
    271             {
    272                 __base.__state_ &= ~__base.__write_entered_;
    273                 __base.__gate1_.notify_all();
    274                 return false;
    275             }
    276         }
    277     }
    278     return true;
    279 }
    280 
    281 template <class _Clock, class _Duration>
    282 bool
    283 shared_timed_mutex::try_lock_shared_until(
    284                         const chrono::time_point<_Clock, _Duration>& __abs_time)
    285 {
    286     unique_lock<mutex> __lk(__base.__mut_);
    287     if ((__base.__state_ & __base.__write_entered_) || (__base.__state_ & __base.__n_readers_) == __base.__n_readers_)
    288     {
    289         while (true)
    290         {
    291             cv_status status = __base.__gate1_.wait_until(__lk, __abs_time);
    292             if ((__base.__state_ & __base.__write_entered_) == 0 &&
    293                                        (__base.__state_ & __base.__n_readers_) < __base.__n_readers_)
    294                 break;
    295             if (status == cv_status::timeout)
    296                 return false;
    297         }
    298     }
    299     unsigned __num_readers = (__base.__state_ & __base.__n_readers_) + 1;
    300     __base.__state_ &= ~__base.__n_readers_;
    301     __base.__state_ |= __num_readers;
    302     return true;
    303 }
    304 
    305 template <class _Mutex>
    306 class shared_lock
    307 {
    308 public:
    309     typedef _Mutex mutex_type;
    310 
    311 private:
    312     mutex_type* __m_;
    313     bool __owns_;
    314 
    315 public:
    316     _LIBCPP_INLINE_VISIBILITY
    317     shared_lock() _NOEXCEPT
    318         : __m_(nullptr),
    319           __owns_(false)
    320         {}
    321 
    322     _LIBCPP_INLINE_VISIBILITY
    323     explicit shared_lock(mutex_type& __m)
    324         : __m_(_VSTD::addressof(__m)),
    325           __owns_(true)
    326         {__m_->lock_shared();}
    327 
    328     _LIBCPP_INLINE_VISIBILITY
    329     shared_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
    330         : __m_(_VSTD::addressof(__m)),
    331           __owns_(false)
    332         {}
    333 
    334     _LIBCPP_INLINE_VISIBILITY
    335     shared_lock(mutex_type& __m, try_to_lock_t)
    336         : __m_(_VSTD::addressof(__m)),
    337           __owns_(__m.try_lock_shared())
    338         {}
    339 
    340     _LIBCPP_INLINE_VISIBILITY
    341     shared_lock(mutex_type& __m, adopt_lock_t)
    342         : __m_(_VSTD::addressof(__m)),
    343           __owns_(true)
    344         {}
    345 
    346     template <class _Clock, class _Duration>
    347         _LIBCPP_INLINE_VISIBILITY
    348         shared_lock(mutex_type& __m,
    349                     const chrono::time_point<_Clock, _Duration>& __abs_time)
    350             : __m_(_VSTD::addressof(__m)),
    351               __owns_(__m.try_lock_shared_until(__abs_time))
    352             {}
    353 
    354     template <class _Rep, class _Period>
    355         _LIBCPP_INLINE_VISIBILITY
    356         shared_lock(mutex_type& __m,
    357                     const chrono::duration<_Rep, _Period>& __rel_time)
    358             : __m_(_VSTD::addressof(__m)),
    359               __owns_(__m.try_lock_shared_for(__rel_time))
    360             {}
    361 
    362     _LIBCPP_INLINE_VISIBILITY
    363     ~shared_lock()
    364     {
    365         if (__owns_)
    366             __m_->unlock_shared();
    367     }
    368 
    369     shared_lock(shared_lock const&) = delete;
    370     shared_lock& operator=(shared_lock const&) = delete;
    371 
    372     _LIBCPP_INLINE_VISIBILITY
    373     shared_lock(shared_lock&& __u) _NOEXCEPT
    374         : __m_(__u.__m_),
    375           __owns_(__u.__owns_)
    376         {
    377             __u.__m_ = nullptr;
    378             __u.__owns_ = false;
    379         }
    380 
    381     _LIBCPP_INLINE_VISIBILITY
    382     shared_lock& operator=(shared_lock&& __u) _NOEXCEPT
    383     {
    384         if (__owns_)
    385             __m_->unlock_shared();
    386         __m_ = nullptr;
    387         __owns_ = false;
    388         __m_ = __u.__m_;
    389         __owns_ = __u.__owns_;
    390         __u.__m_ = nullptr;
    391         __u.__owns_ = false;
    392         return *this;
    393     }
    394 
    395     void lock();
    396     bool try_lock();
    397     template <class Rep, class Period>
    398         bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
    399     template <class Clock, class Duration>
    400         bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
    401     void unlock();
    402 
    403     // Setters
    404     _LIBCPP_INLINE_VISIBILITY
    405     void swap(shared_lock& __u) _NOEXCEPT
    406     {
    407         _VSTD::swap(__m_, __u.__m_);
    408         _VSTD::swap(__owns_, __u.__owns_);
    409     }
    410 
    411     _LIBCPP_INLINE_VISIBILITY
    412     mutex_type* release() _NOEXCEPT
    413     {
    414         mutex_type* __m = __m_;
    415         __m_ = nullptr;
    416         __owns_ = false;
    417         return __m;
    418     }
    419 
    420     // Getters
    421     _LIBCPP_INLINE_VISIBILITY
    422     bool owns_lock() const _NOEXCEPT {return __owns_;}
    423 
    424     _LIBCPP_INLINE_VISIBILITY
    425     explicit operator bool () const _NOEXCEPT {return __owns_;}
    426 
    427     _LIBCPP_INLINE_VISIBILITY
    428     mutex_type* mutex() const _NOEXCEPT {return __m_;}
    429 };
    430 
    431 template <class _Mutex>
    432 void
    433 shared_lock<_Mutex>::lock()
    434 {
    435     if (__m_ == nullptr)
    436         __throw_system_error(EPERM, "shared_lock::lock: references null mutex");
    437     if (__owns_)
    438         __throw_system_error(EDEADLK, "shared_lock::lock: already locked");
    439     __m_->lock_shared();
    440     __owns_ = true;
    441 }
    442 
    443 template <class _Mutex>
    444 bool
    445 shared_lock<_Mutex>::try_lock()
    446 {
    447     if (__m_ == nullptr)
    448         __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex");
    449     if (__owns_)
    450         __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked");
    451     __owns_ = __m_->try_lock_shared();
    452     return __owns_;
    453 }
    454 
    455 template <class _Mutex>
    456 template <class _Rep, class _Period>
    457 bool
    458 shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
    459 {
    460     if (__m_ == nullptr)
    461         __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex");
    462     if (__owns_)
    463         __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked");
    464     __owns_ = __m_->try_lock_shared_for(__d);
    465     return __owns_;
    466 }
    467 
    468 template <class _Mutex>
    469 template <class _Clock, class _Duration>
    470 bool
    471 shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
    472 {
    473     if (__m_ == nullptr)
    474         __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex");
    475     if (__owns_)
    476         __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked");
    477     __owns_ = __m_->try_lock_shared_until(__t);
    478     return __owns_;
    479 }
    480 
    481 template <class _Mutex>
    482 void
    483 shared_lock<_Mutex>::unlock()
    484 {
    485     if (!__owns_)
    486         __throw_system_error(EPERM, "shared_lock::unlock: not locked");
    487     __m_->unlock_shared();
    488     __owns_ = false;
    489 }
    490 
    491 template <class _Mutex>
    492 inline _LIBCPP_INLINE_VISIBILITY
    493 void
    494 swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) _NOEXCEPT
    495     {__x.swap(__y);}
    496 
    497 _LIBCPP_END_NAMESPACE_STD
    498 
    499 #endif  // !_LIBCPP_HAS_NO_THREADS
    500 
    501 #endif  // _LIBCPP_STD_VER > 11
    502 
    503 #endif  // _LIBCPP_SHARED_MUTEX
    504