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