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_timed_mutex
     23 {
     24 public:
     25     shared_timed_mutex();
     26     ~shared_timed_mutex();
     27 
     28     shared_timed_mutex(const shared_timed_mutex&) = delete;
     29     shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
     30 
     31     // Exclusive ownership
     32     void lock(); // blocking
     33     bool try_lock();
     34     template <class Rep, class Period>
     35         bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
     36     template <class Clock, class Duration>
     37         bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
     38     void unlock();
     39 
     40     // Shared ownership
     41     void lock_shared(); // blocking
     42     bool try_lock_shared();
     43     template <class Rep, class Period>
     44         bool
     45         try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time);
     46     template <class Clock, class Duration>
     47         bool
     48         try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time);
     49     void unlock_shared();
     50 };
     51 
     52 template <class Mutex>
     53 class shared_lock
     54 {
     55 public:
     56     typedef Mutex mutex_type;
     57 
     58     // Shared locking
     59     shared_lock() noexcept;
     60     explicit shared_lock(mutex_type& m); // blocking
     61     shared_lock(mutex_type& m, defer_lock_t) noexcept;
     62     shared_lock(mutex_type& m, try_to_lock_t);
     63     shared_lock(mutex_type& m, adopt_lock_t);
     64     template <class Clock, class Duration>
     65         shared_lock(mutex_type& m,
     66                     const chrono::time_point<Clock, Duration>& abs_time);
     67     template <class Rep, class Period>
     68         shared_lock(mutex_type& m,
     69                     const chrono::duration<Rep, Period>& rel_time);
     70     ~shared_lock();
     71 
     72     shared_lock(shared_lock const&) = delete;
     73     shared_lock& operator=(shared_lock const&) = delete;
     74 
     75     shared_lock(shared_lock&& u) noexcept;
     76     shared_lock& operator=(shared_lock&& u) noexcept;
     77 
     78     void lock(); // blocking
     79     bool try_lock();
     80     template <class Rep, class Period>
     81         bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
     82     template <class Clock, class Duration>
     83         bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
     84     void unlock();
     85 
     86     // Setters
     87     void swap(shared_lock& u) noexcept;
     88     mutex_type* release() noexcept;
     89 
     90     // Getters
     91     bool owns_lock() const noexcept;
     92     explicit operator bool () const noexcept;
     93     mutex_type* mutex() const noexcept;
     94 };
     95 
     96 template <class Mutex>
     97     void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
     98 
     99 }  // std
    100 
    101 */
    102 
    103 #include <__config>
    104 
    105 #if _LIBCPP_STD_VER > 11 || defined(_LIBCPP_BUILDING_SHARED_MUTEX)
    106 
    107 #include <__mutex_base>
    108 
    109 #include <__undef_min_max>
    110 
    111 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
    112 #pragma GCC system_header
    113 #endif
    114 
    115 _LIBCPP_BEGIN_NAMESPACE_STD
    116 
    117 class _LIBCPP_TYPE_VIS shared_timed_mutex
    118 {
    119     mutex               __mut_;
    120     condition_variable  __gate1_;
    121     condition_variable  __gate2_;
    122     unsigned            __state_;
    123 
    124     static const unsigned __write_entered_ = 1U << (sizeof(unsigned)*__CHAR_BIT__ - 1);
    125     static const unsigned __n_readers_ = ~__write_entered_;
    126 public:
    127     shared_timed_mutex();
    128     _LIBCPP_INLINE_VISIBILITY ~shared_timed_mutex() = default;
    129 
    130     shared_timed_mutex(const shared_timed_mutex&) = delete;
    131     shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
    132 
    133     // Exclusive ownership
    134     void lock();
    135     bool try_lock();
    136     template <class _Rep, class _Period>
    137         _LIBCPP_INLINE_VISIBILITY
    138         bool
    139         try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
    140         {
    141             return try_lock_until(chrono::steady_clock::now() + __rel_time);
    142         }
    143     template <class _Clock, class _Duration>
    144         bool
    145         try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
    146     void unlock();
    147 
    148     // Shared ownership
    149     void lock_shared();
    150     bool try_lock_shared();
    151     template <class _Rep, class _Period>
    152         _LIBCPP_INLINE_VISIBILITY
    153         bool
    154         try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
    155         {
    156             return try_lock_shared_until(chrono::steady_clock::now() + __rel_time);
    157         }
    158     template <class _Clock, class _Duration>
    159         bool
    160         try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
    161     void unlock_shared();
    162 };
    163 
    164 template <class _Clock, class _Duration>
    165 bool
    166 shared_timed_mutex::try_lock_until(
    167                         const chrono::time_point<_Clock, _Duration>& __abs_time)
    168 {
    169     unique_lock<mutex> __lk(__mut_);
    170     if (__state_ & __write_entered_)
    171     {
    172         while (true)
    173         {
    174             cv_status __status = __gate1_.wait_until(__lk, __abs_time);
    175             if ((__state_ & __write_entered_) == 0)
    176                 break;
    177             if (__status == cv_status::timeout)
    178                 return false;
    179         }
    180     }
    181     __state_ |= __write_entered_;
    182     if (__state_ & __n_readers_)
    183     {
    184         while (true)
    185         {
    186             cv_status __status = __gate2_.wait_until(__lk, __abs_time);
    187             if ((__state_ & __n_readers_) == 0)
    188                 break;
    189             if (__status == cv_status::timeout)
    190             {
    191                 __state_ &= ~__write_entered_;
    192                 return false;
    193             }
    194         }
    195     }
    196     return true;
    197 }
    198 
    199 template <class _Clock, class _Duration>
    200 bool
    201 shared_timed_mutex::try_lock_shared_until(
    202                         const chrono::time_point<_Clock, _Duration>& __abs_time)
    203 {
    204     unique_lock<mutex> __lk(__mut_);
    205     if ((__state_ & __write_entered_) || (__state_ & __n_readers_) == __n_readers_)
    206     {
    207         while (true)
    208         {
    209             cv_status status = __gate1_.wait_until(__lk, __abs_time);
    210             if ((__state_ & __write_entered_) == 0 &&
    211                                        (__state_ & __n_readers_) < __n_readers_)
    212                 break;
    213             if (status == cv_status::timeout)
    214                 return false;
    215         }
    216     }
    217     unsigned __num_readers = (__state_ & __n_readers_) + 1;
    218     __state_ &= ~__n_readers_;
    219     __state_ |= __num_readers;
    220     return true;
    221 }
    222 
    223 template <class _Mutex>
    224 class shared_lock
    225 {
    226 public:
    227     typedef _Mutex mutex_type;
    228 
    229 private:
    230     mutex_type* __m_;
    231     bool __owns_;
    232 
    233 public:
    234     _LIBCPP_INLINE_VISIBILITY
    235     shared_lock() noexcept
    236         : __m_(nullptr),
    237           __owns_(false)
    238         {}
    239 
    240     _LIBCPP_INLINE_VISIBILITY
    241     explicit shared_lock(mutex_type& __m)
    242         : __m_(&__m),
    243           __owns_(true)
    244         {__m_->lock_shared();}
    245 
    246     _LIBCPP_INLINE_VISIBILITY
    247     shared_lock(mutex_type& __m, defer_lock_t) noexcept
    248         : __m_(&__m),
    249           __owns_(false)
    250         {}
    251 
    252     _LIBCPP_INLINE_VISIBILITY
    253     shared_lock(mutex_type& __m, try_to_lock_t)
    254         : __m_(&__m),
    255           __owns_(__m.try_lock_shared())
    256         {}
    257 
    258     _LIBCPP_INLINE_VISIBILITY
    259     shared_lock(mutex_type& __m, adopt_lock_t)
    260         : __m_(&__m),
    261           __owns_(true)
    262         {}
    263 
    264     template <class _Clock, class _Duration>
    265         _LIBCPP_INLINE_VISIBILITY
    266         shared_lock(mutex_type& __m,
    267                     const chrono::time_point<_Clock, _Duration>& __abs_time)
    268             : __m_(&__m),
    269               __owns_(__m.try_lock_shared_until(__abs_time))
    270             {}
    271 
    272     template <class _Rep, class _Period>
    273         _LIBCPP_INLINE_VISIBILITY
    274         shared_lock(mutex_type& __m,
    275                     const chrono::duration<_Rep, _Period>& __rel_time)
    276             : __m_(&__m),
    277               __owns_(__m.try_lock_shared_for(__rel_time))
    278             {}
    279 
    280     _LIBCPP_INLINE_VISIBILITY
    281     ~shared_lock()
    282     {
    283         if (__owns_)
    284             __m_->unlock_shared();
    285     }
    286 
    287     shared_lock(shared_lock const&) = delete;
    288     shared_lock& operator=(shared_lock const&) = delete;
    289 
    290     _LIBCPP_INLINE_VISIBILITY
    291     shared_lock(shared_lock&& __u) noexcept
    292         : __m_(__u.__m_),
    293           __owns_(__u.__owns_)
    294         {
    295             __u.__m_ = nullptr;
    296             __u.__owns_ = false;
    297         }
    298 
    299     _LIBCPP_INLINE_VISIBILITY
    300     shared_lock& operator=(shared_lock&& __u) noexcept
    301     {
    302         if (__owns_)
    303             __m_->unlock_shared();
    304         __m_ = nullptr;
    305         __owns_ = false;
    306         __m_ = __u.__m_;
    307         __owns_ = __u.__owns_;
    308         __u.__m_ = nullptr;
    309         __u.__owns_ = false;
    310         return *this;
    311     }
    312 
    313     void lock();
    314     bool try_lock();
    315     template <class Rep, class Period>
    316         bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
    317     template <class Clock, class Duration>
    318         bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
    319     void unlock();
    320 
    321     // Setters
    322     _LIBCPP_INLINE_VISIBILITY
    323     void swap(shared_lock& __u) noexcept
    324     {
    325         _VSTD::swap(__m_, __u.__m_);
    326         _VSTD::swap(__owns_, __u.__owns_);
    327     }
    328 
    329     _LIBCPP_INLINE_VISIBILITY
    330     mutex_type* release() noexcept
    331     {
    332         mutex_type* __m = __m_;
    333         __m_ = nullptr;
    334         __owns_ = false;
    335         return __m;
    336     }
    337 
    338     // Getters
    339     _LIBCPP_INLINE_VISIBILITY
    340     bool owns_lock() const noexcept {return __owns_;}
    341 
    342     _LIBCPP_INLINE_VISIBILITY
    343     explicit operator bool () const noexcept {return __owns_;}
    344 
    345     _LIBCPP_INLINE_VISIBILITY
    346     mutex_type* mutex() const noexcept {return __m_;}
    347 };
    348 
    349 template <class _Mutex>
    350 void
    351 shared_lock<_Mutex>::lock()
    352 {
    353     if (__m_ == nullptr)
    354         __throw_system_error(EPERM, "shared_lock::lock: references null mutex");
    355     if (__owns_)
    356         __throw_system_error(EDEADLK, "shared_lock::lock: already locked");
    357     __m_->lock_shared();
    358     __owns_ = true;
    359 }
    360 
    361 template <class _Mutex>
    362 bool
    363 shared_lock<_Mutex>::try_lock()
    364 {
    365     if (__m_ == nullptr)
    366         __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex");
    367     if (__owns_)
    368         __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked");
    369     __owns_ = __m_->try_lock_shared();
    370     return __owns_;
    371 }
    372 
    373 template <class _Mutex>
    374 template <class _Rep, class _Period>
    375 bool
    376 shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
    377 {
    378     if (__m_ == nullptr)
    379         __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex");
    380     if (__owns_)
    381         __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked");
    382     __owns_ = __m_->try_lock_shared_for(__d);
    383     return __owns_;
    384 }
    385 
    386 template <class _Mutex>
    387 template <class _Clock, class _Duration>
    388 bool
    389 shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
    390 {
    391     if (__m_ == nullptr)
    392         __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex");
    393     if (__owns_)
    394         __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked");
    395     __owns_ = __m_->try_lock_shared_until(__t);
    396     return __owns_;
    397 }
    398 
    399 template <class _Mutex>
    400 void
    401 shared_lock<_Mutex>::unlock()
    402 {
    403     if (!__owns_)
    404         __throw_system_error(EPERM, "shared_lock::unlock: not locked");
    405     __m_->unlock_shared();
    406     __owns_ = false;
    407 }
    408 
    409 template <class _Mutex>
    410 inline _LIBCPP_INLINE_VISIBILITY
    411 void
    412 swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) noexcept
    413     {__x.swap(__y);}
    414 
    415 _LIBCPP_END_NAMESPACE_STD
    416 
    417 #endif  // _LIBCPP_STD_VER > 11
    418 
    419 #endif  // _LIBCPP_SHARED_MUTEX
    420