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