xref: /freebsd/contrib/llvm-project/libcxx/include/shared_mutex (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
10b57cec5SDimitry Andric// -*- C++ -*-
2349cc55cSDimitry Andric//===----------------------------------------------------------------------===//
30b57cec5SDimitry Andric//
40b57cec5SDimitry Andric// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
50b57cec5SDimitry Andric// See https://llvm.org/LICENSE.txt for license information.
60b57cec5SDimitry Andric// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
70b57cec5SDimitry Andric//
80b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
90b57cec5SDimitry Andric
100b57cec5SDimitry Andric#ifndef _LIBCPP_SHARED_MUTEX
110b57cec5SDimitry Andric#define _LIBCPP_SHARED_MUTEX
120b57cec5SDimitry Andric
130b57cec5SDimitry Andric/*
140b57cec5SDimitry Andric    shared_mutex synopsis
150b57cec5SDimitry Andric
160b57cec5SDimitry Andric// C++1y
170b57cec5SDimitry Andric
180b57cec5SDimitry Andricnamespace std
190b57cec5SDimitry Andric{
200b57cec5SDimitry Andric
210b57cec5SDimitry Andricclass shared_mutex      // C++17
220b57cec5SDimitry Andric{
230b57cec5SDimitry Andricpublic:
240b57cec5SDimitry Andric    shared_mutex();
250b57cec5SDimitry Andric    ~shared_mutex();
260b57cec5SDimitry Andric
270b57cec5SDimitry Andric    shared_mutex(const shared_mutex&) = delete;
280b57cec5SDimitry Andric    shared_mutex& operator=(const shared_mutex&) = delete;
290b57cec5SDimitry Andric
300b57cec5SDimitry Andric    // Exclusive ownership
310b57cec5SDimitry Andric    void lock(); // blocking
320b57cec5SDimitry Andric    bool try_lock();
330b57cec5SDimitry Andric    void unlock();
340b57cec5SDimitry Andric
350b57cec5SDimitry Andric    // Shared ownership
360b57cec5SDimitry Andric    void lock_shared(); // blocking
370b57cec5SDimitry Andric    bool try_lock_shared();
380b57cec5SDimitry Andric    void unlock_shared();
390b57cec5SDimitry Andric
400b57cec5SDimitry Andric    typedef implementation-defined native_handle_type; // See 30.2.3
410b57cec5SDimitry Andric    native_handle_type native_handle(); // See 30.2.3
420b57cec5SDimitry Andric};
430b57cec5SDimitry Andric
440b57cec5SDimitry Andricclass shared_timed_mutex
450b57cec5SDimitry Andric{
460b57cec5SDimitry Andricpublic:
470b57cec5SDimitry Andric    shared_timed_mutex();
480b57cec5SDimitry Andric    ~shared_timed_mutex();
490b57cec5SDimitry Andric
500b57cec5SDimitry Andric    shared_timed_mutex(const shared_timed_mutex&) = delete;
510b57cec5SDimitry Andric    shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
520b57cec5SDimitry Andric
530b57cec5SDimitry Andric    // Exclusive ownership
540b57cec5SDimitry Andric    void lock(); // blocking
550b57cec5SDimitry Andric    bool try_lock();
560b57cec5SDimitry Andric    template <class Rep, class Period>
570b57cec5SDimitry Andric        bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
580b57cec5SDimitry Andric    template <class Clock, class Duration>
590b57cec5SDimitry Andric        bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
600b57cec5SDimitry Andric    void unlock();
610b57cec5SDimitry Andric
620b57cec5SDimitry Andric    // Shared ownership
630b57cec5SDimitry Andric    void lock_shared(); // blocking
640b57cec5SDimitry Andric    bool try_lock_shared();
650b57cec5SDimitry Andric    template <class Rep, class Period>
660b57cec5SDimitry Andric        bool
670b57cec5SDimitry Andric        try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time);
680b57cec5SDimitry Andric    template <class Clock, class Duration>
690b57cec5SDimitry Andric        bool
700b57cec5SDimitry Andric        try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time);
710b57cec5SDimitry Andric    void unlock_shared();
720b57cec5SDimitry Andric};
730b57cec5SDimitry Andric
740b57cec5SDimitry Andrictemplate <class Mutex>
750b57cec5SDimitry Andricclass shared_lock
760b57cec5SDimitry Andric{
770b57cec5SDimitry Andricpublic:
780b57cec5SDimitry Andric    typedef Mutex mutex_type;
790b57cec5SDimitry Andric
800b57cec5SDimitry Andric    // Shared locking
810b57cec5SDimitry Andric    shared_lock() noexcept;
820b57cec5SDimitry Andric    explicit shared_lock(mutex_type& m); // blocking
830b57cec5SDimitry Andric    shared_lock(mutex_type& m, defer_lock_t) noexcept;
840b57cec5SDimitry Andric    shared_lock(mutex_type& m, try_to_lock_t);
850b57cec5SDimitry Andric    shared_lock(mutex_type& m, adopt_lock_t);
860b57cec5SDimitry Andric    template <class Clock, class Duration>
870b57cec5SDimitry Andric        shared_lock(mutex_type& m,
880b57cec5SDimitry Andric                    const chrono::time_point<Clock, Duration>& abs_time);
890b57cec5SDimitry Andric    template <class Rep, class Period>
900b57cec5SDimitry Andric        shared_lock(mutex_type& m,
910b57cec5SDimitry Andric                    const chrono::duration<Rep, Period>& rel_time);
920b57cec5SDimitry Andric    ~shared_lock();
930b57cec5SDimitry Andric
940b57cec5SDimitry Andric    shared_lock(shared_lock const&) = delete;
950b57cec5SDimitry Andric    shared_lock& operator=(shared_lock const&) = delete;
960b57cec5SDimitry Andric
970b57cec5SDimitry Andric    shared_lock(shared_lock&& u) noexcept;
980b57cec5SDimitry Andric    shared_lock& operator=(shared_lock&& u) noexcept;
990b57cec5SDimitry Andric
1000b57cec5SDimitry Andric    void lock(); // blocking
1010b57cec5SDimitry Andric    bool try_lock();
1020b57cec5SDimitry Andric    template <class Rep, class Period>
1030b57cec5SDimitry Andric        bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
1040b57cec5SDimitry Andric    template <class Clock, class Duration>
1050b57cec5SDimitry Andric        bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
1060b57cec5SDimitry Andric    void unlock();
1070b57cec5SDimitry Andric
1080b57cec5SDimitry Andric    // Setters
1090b57cec5SDimitry Andric    void swap(shared_lock& u) noexcept;
1100b57cec5SDimitry Andric    mutex_type* release() noexcept;
1110b57cec5SDimitry Andric
1120b57cec5SDimitry Andric    // Getters
1130b57cec5SDimitry Andric    bool owns_lock() const noexcept;
1140b57cec5SDimitry Andric    explicit operator bool () const noexcept;
1150b57cec5SDimitry Andric    mutex_type* mutex() const noexcept;
1160b57cec5SDimitry Andric};
1170b57cec5SDimitry Andric
1180b57cec5SDimitry Andrictemplate <class Mutex>
1190b57cec5SDimitry Andric    void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
1200b57cec5SDimitry Andric
1210b57cec5SDimitry Andric}  // std
1220b57cec5SDimitry Andric
1230b57cec5SDimitry Andric*/
1240b57cec5SDimitry Andric
12581ad6265SDimitry Andric#include <__assert> // all public C++ headers provide the assertion handler
126e8d8bef9SDimitry Andric#include <__availability>
127*06c3fb27SDimitry Andric#include <__chrono/duration.h>
128*06c3fb27SDimitry Andric#include <__chrono/steady_clock.h>
129*06c3fb27SDimitry Andric#include <__chrono/time_point.h>
130*06c3fb27SDimitry Andric#include <__condition_variable/condition_variable.h>
131fe6060f1SDimitry Andric#include <__config>
132*06c3fb27SDimitry Andric#include <__memory/addressof.h>
133*06c3fb27SDimitry Andric#include <__mutex/mutex.h>
134*06c3fb27SDimitry Andric#include <__mutex/tag_types.h>
135*06c3fb27SDimitry Andric#include <__mutex/unique_lock.h>
136*06c3fb27SDimitry Andric#include <__system_error/system_error.h>
137*06c3fb27SDimitry Andric#include <__utility/swap.h>
138*06c3fb27SDimitry Andric#include <cerrno>
1390b57cec5SDimitry Andric#include <version>
1400b57cec5SDimitry Andric
1410b57cec5SDimitry Andric_LIBCPP_PUSH_MACROS
1420b57cec5SDimitry Andric#include <__undef_macros>
1430b57cec5SDimitry Andric
144*06c3fb27SDimitry Andric#if _LIBCPP_STD_VER >= 14
1450b57cec5SDimitry Andric
1460b57cec5SDimitry Andric#  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
1470b57cec5SDimitry Andric#    pragma GCC system_header
1480b57cec5SDimitry Andric#  endif
1490b57cec5SDimitry Andric
1500b57cec5SDimitry Andric#  ifdef _LIBCPP_HAS_NO_THREADS
15181ad6265SDimitry Andric#    error "<shared_mutex> is not supported since libc++ has been configured without support for threads."
15281ad6265SDimitry Andric#  endif
1530b57cec5SDimitry Andric
1540b57cec5SDimitry Andric_LIBCPP_BEGIN_NAMESPACE_STD
1550b57cec5SDimitry Andric
156*06c3fb27SDimitry Andricstruct _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_AVAILABILITY_SHARED_MUTEX __shared_mutex_base {
1570b57cec5SDimitry Andric  mutex __mut_;
1580b57cec5SDimitry Andric  condition_variable __gate1_;
1590b57cec5SDimitry Andric  condition_variable __gate2_;
1600b57cec5SDimitry Andric  unsigned __state_;
1610b57cec5SDimitry Andric
1620b57cec5SDimitry Andric  static const unsigned __write_entered_ = 1U << (sizeof(unsigned) * __CHAR_BIT__ - 1);
1630b57cec5SDimitry Andric  static const unsigned __n_readers_     = ~__write_entered_;
1640b57cec5SDimitry Andric
1650b57cec5SDimitry Andric  __shared_mutex_base();
166*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI ~__shared_mutex_base() = default;
1670b57cec5SDimitry Andric
1680b57cec5SDimitry Andric  __shared_mutex_base(const __shared_mutex_base&)            = delete;
1690b57cec5SDimitry Andric  __shared_mutex_base& operator=(const __shared_mutex_base&) = delete;
1700b57cec5SDimitry Andric
1710b57cec5SDimitry Andric  // Exclusive ownership
172*06c3fb27SDimitry Andric  void lock(); // blocking
173*06c3fb27SDimitry Andric  bool try_lock();
174*06c3fb27SDimitry Andric  void unlock();
1750b57cec5SDimitry Andric
1760b57cec5SDimitry Andric  // Shared ownership
177*06c3fb27SDimitry Andric  void lock_shared(); // blocking
178*06c3fb27SDimitry Andric  bool try_lock_shared();
179*06c3fb27SDimitry Andric  void unlock_shared();
1800b57cec5SDimitry Andric
1810b57cec5SDimitry Andric  //     typedef implementation-defined native_handle_type; // See 30.2.3
1820b57cec5SDimitry Andric  //     native_handle_type native_handle(); // See 30.2.3
1830b57cec5SDimitry Andric};
1840b57cec5SDimitry Andric
185*06c3fb27SDimitry Andric#  if _LIBCPP_STD_VER >= 17
186*06c3fb27SDimitry Andricclass _LIBCPP_EXPORTED_FROM_ABI
187*06c3fb27SDimitry Andric    _LIBCPP_AVAILABILITY_SHARED_MUTEX _LIBCPP_THREAD_SAFETY_ANNOTATION(__capability__("shared_mutex")) shared_mutex {
188bdd1243dSDimitry Andric  __shared_mutex_base __base_;
189*06c3fb27SDimitry Andric
1900b57cec5SDimitry Andricpublic:
191*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI shared_mutex() : __base_() {}
192*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI ~shared_mutex() = default;
1930b57cec5SDimitry Andric
1940b57cec5SDimitry Andric  shared_mutex(const shared_mutex&)            = delete;
1950b57cec5SDimitry Andric  shared_mutex& operator=(const shared_mutex&) = delete;
1960b57cec5SDimitry Andric
1970b57cec5SDimitry Andric  // Exclusive ownership
198*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__acquire_capability__()) {
199*06c3fb27SDimitry Andric    return __base_.lock();
200*06c3fb27SDimitry Andric  }
201*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI bool try_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_capability__(true)) {
202*06c3fb27SDimitry Andric    return __base_.try_lock();
203*06c3fb27SDimitry Andric  }
204*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI void unlock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__release_capability__()) {
205*06c3fb27SDimitry Andric    return __base_.unlock();
206*06c3fb27SDimitry Andric  }
2070b57cec5SDimitry Andric
2080b57cec5SDimitry Andric  // Shared ownership
209*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI void lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__acquire_shared_capability__()) {
210*06c3fb27SDimitry Andric    return __base_.lock_shared();
211*06c3fb27SDimitry Andric  }
212*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI bool try_lock_shared()
213*06c3fb27SDimitry Andric      _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_shared_capability__(true)) {
214*06c3fb27SDimitry Andric    return __base_.try_lock_shared();
215*06c3fb27SDimitry Andric  }
216*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI void unlock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__release_shared_capability__()) {
217*06c3fb27SDimitry Andric    return __base_.unlock_shared();
218*06c3fb27SDimitry Andric  }
2190b57cec5SDimitry Andric
2200b57cec5SDimitry Andric  //     typedef __shared_mutex_base::native_handle_type native_handle_type;
221*06c3fb27SDimitry Andric  //     _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return __base::unlock_shared(); }
2220b57cec5SDimitry Andric};
2230b57cec5SDimitry Andric#  endif
2240b57cec5SDimitry Andric
225*06c3fb27SDimitry Andricclass _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_AVAILABILITY_SHARED_MUTEX _LIBCPP_THREAD_SAFETY_ANNOTATION(
226*06c3fb27SDimitry Andric    __capability__("shared_timed_mutex")) shared_timed_mutex {
227bdd1243dSDimitry Andric  __shared_mutex_base __base_;
228*06c3fb27SDimitry Andric
2290b57cec5SDimitry Andricpublic:
2300b57cec5SDimitry Andric  shared_timed_mutex();
231*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI ~shared_timed_mutex() = default;
2320b57cec5SDimitry Andric
2330b57cec5SDimitry Andric  shared_timed_mutex(const shared_timed_mutex&)            = delete;
2340b57cec5SDimitry Andric  shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
2350b57cec5SDimitry Andric
2360b57cec5SDimitry Andric  // Exclusive ownership
237*06c3fb27SDimitry Andric  void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__acquire_capability__());
238*06c3fb27SDimitry Andric  bool try_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_capability__(true));
2390b57cec5SDimitry Andric  template <class _Rep, class _Period>
240*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
241*06c3fb27SDimitry Andric      _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_capability__(true)) {
2420b57cec5SDimitry Andric    return try_lock_until(chrono::steady_clock::now() + __rel_time);
2430b57cec5SDimitry Andric  }
2440b57cec5SDimitry Andric  template <class _Clock, class _Duration>
245*06c3fb27SDimitry Andric  _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool
246*06c3fb27SDimitry Andric  try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time)
247*06c3fb27SDimitry Andric      _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_capability__(true));
248*06c3fb27SDimitry Andric  void unlock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__release_capability__());
2490b57cec5SDimitry Andric
2500b57cec5SDimitry Andric  // Shared ownership
251*06c3fb27SDimitry Andric  void lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__acquire_shared_capability__());
252*06c3fb27SDimitry Andric  bool try_lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_shared_capability__(true));
2530b57cec5SDimitry Andric  template <class _Rep, class _Period>
254*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI bool try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
255*06c3fb27SDimitry Andric      _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_shared_capability__(true)) {
2560b57cec5SDimitry Andric    return try_lock_shared_until(chrono::steady_clock::now() + __rel_time);
2570b57cec5SDimitry Andric  }
2580b57cec5SDimitry Andric  template <class _Clock, class _Duration>
259*06c3fb27SDimitry Andric  _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool
260*06c3fb27SDimitry Andric  try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time)
261*06c3fb27SDimitry Andric      _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_shared_capability__(true));
262*06c3fb27SDimitry Andric  void unlock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__release_shared_capability__());
2630b57cec5SDimitry Andric};
2640b57cec5SDimitry Andric
2650b57cec5SDimitry Andrictemplate <class _Clock, class _Duration>
266*06c3fb27SDimitry Andricbool shared_timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time) {
267bdd1243dSDimitry Andric  unique_lock<mutex> __lk(__base_.__mut_);
268*06c3fb27SDimitry Andric  if (__base_.__state_ & __base_.__write_entered_) {
269*06c3fb27SDimitry Andric    while (true) {
270bdd1243dSDimitry Andric      cv_status __status = __base_.__gate1_.wait_until(__lk, __abs_time);
271bdd1243dSDimitry Andric      if ((__base_.__state_ & __base_.__write_entered_) == 0)
2720b57cec5SDimitry Andric        break;
2730b57cec5SDimitry Andric      if (__status == cv_status::timeout)
2740b57cec5SDimitry Andric        return false;
2750b57cec5SDimitry Andric    }
2760b57cec5SDimitry Andric  }
277bdd1243dSDimitry Andric  __base_.__state_ |= __base_.__write_entered_;
278*06c3fb27SDimitry Andric  if (__base_.__state_ & __base_.__n_readers_) {
279*06c3fb27SDimitry Andric    while (true) {
280bdd1243dSDimitry Andric      cv_status __status = __base_.__gate2_.wait_until(__lk, __abs_time);
281bdd1243dSDimitry Andric      if ((__base_.__state_ & __base_.__n_readers_) == 0)
2820b57cec5SDimitry Andric        break;
283*06c3fb27SDimitry Andric      if (__status == cv_status::timeout) {
284bdd1243dSDimitry Andric        __base_.__state_ &= ~__base_.__write_entered_;
285bdd1243dSDimitry Andric        __base_.__gate1_.notify_all();
2860b57cec5SDimitry Andric        return false;
2870b57cec5SDimitry Andric      }
2880b57cec5SDimitry Andric    }
2890b57cec5SDimitry Andric  }
2900b57cec5SDimitry Andric  return true;
2910b57cec5SDimitry Andric}
2920b57cec5SDimitry Andric
2930b57cec5SDimitry Andrictemplate <class _Clock, class _Duration>
294*06c3fb27SDimitry Andricbool shared_timed_mutex::try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time) {
295bdd1243dSDimitry Andric  unique_lock<mutex> __lk(__base_.__mut_);
296*06c3fb27SDimitry Andric  if ((__base_.__state_ & __base_.__write_entered_) ||
297*06c3fb27SDimitry Andric      (__base_.__state_ & __base_.__n_readers_) == __base_.__n_readers_) {
298*06c3fb27SDimitry Andric    while (true) {
299*06c3fb27SDimitry Andric      cv_status __status = __base_.__gate1_.wait_until(__lk, __abs_time);
300bdd1243dSDimitry Andric      if ((__base_.__state_ & __base_.__write_entered_) == 0 &&
301bdd1243dSDimitry Andric          (__base_.__state_ & __base_.__n_readers_) < __base_.__n_readers_)
3020b57cec5SDimitry Andric        break;
303*06c3fb27SDimitry Andric      if (__status == cv_status::timeout)
3040b57cec5SDimitry Andric        return false;
3050b57cec5SDimitry Andric    }
3060b57cec5SDimitry Andric  }
307bdd1243dSDimitry Andric  unsigned __num_readers = (__base_.__state_ & __base_.__n_readers_) + 1;
308bdd1243dSDimitry Andric  __base_.__state_ &= ~__base_.__n_readers_;
309bdd1243dSDimitry Andric  __base_.__state_ |= __num_readers;
3100b57cec5SDimitry Andric  return true;
3110b57cec5SDimitry Andric}
3120b57cec5SDimitry Andric
3130b57cec5SDimitry Andrictemplate <class _Mutex>
314*06c3fb27SDimitry Andricclass shared_lock {
3150b57cec5SDimitry Andricpublic:
3160b57cec5SDimitry Andric  typedef _Mutex mutex_type;
3170b57cec5SDimitry Andric
3180b57cec5SDimitry Andricprivate:
3190b57cec5SDimitry Andric  mutex_type* __m_;
3200b57cec5SDimitry Andric  bool __owns_;
3210b57cec5SDimitry Andric
3220b57cec5SDimitry Andricpublic:
323*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI shared_lock() _NOEXCEPT : __m_(nullptr), __owns_(false) {}
3240b57cec5SDimitry Andric
325*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI explicit shared_lock(mutex_type& __m) : __m_(_VSTD::addressof(__m)), __owns_(true) {
326*06c3fb27SDimitry Andric    __m_->lock_shared();
327*06c3fb27SDimitry Andric  }
3280b57cec5SDimitry Andric
329*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI shared_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
3300b57cec5SDimitry Andric      : __m_(_VSTD::addressof(__m)),
331*06c3fb27SDimitry Andric        __owns_(false) {}
3320b57cec5SDimitry Andric
333*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI shared_lock(mutex_type& __m, try_to_lock_t)
334*06c3fb27SDimitry Andric      : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock_shared()) {}
3350b57cec5SDimitry Andric
336*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI shared_lock(mutex_type& __m, adopt_lock_t) : __m_(_VSTD::addressof(__m)), __owns_(true) {}
3370b57cec5SDimitry Andric
3380b57cec5SDimitry Andric  template <class _Clock, class _Duration>
339*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI shared_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __abs_time)
340*06c3fb27SDimitry Andric      : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock_shared_until(__abs_time)) {}
3410b57cec5SDimitry Andric
3420b57cec5SDimitry Andric  template <class _Rep, class _Period>
343*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI shared_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __rel_time)
344*06c3fb27SDimitry Andric      : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock_shared_for(__rel_time)) {}
3450b57cec5SDimitry Andric
346*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI ~shared_lock() {
3470b57cec5SDimitry Andric    if (__owns_)
3480b57cec5SDimitry Andric      __m_->unlock_shared();
3490b57cec5SDimitry Andric  }
3500b57cec5SDimitry Andric
3510b57cec5SDimitry Andric  shared_lock(shared_lock const&)            = delete;
3520b57cec5SDimitry Andric  shared_lock& operator=(shared_lock const&) = delete;
3530b57cec5SDimitry Andric
354*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI shared_lock(shared_lock&& __u) _NOEXCEPT : __m_(__u.__m_), __owns_(__u.__owns_) {
3550b57cec5SDimitry Andric    __u.__m_    = nullptr;
3560b57cec5SDimitry Andric    __u.__owns_ = false;
3570b57cec5SDimitry Andric  }
3580b57cec5SDimitry Andric
359*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI shared_lock& operator=(shared_lock&& __u) _NOEXCEPT {
3600b57cec5SDimitry Andric    if (__owns_)
3610b57cec5SDimitry Andric      __m_->unlock_shared();
3620b57cec5SDimitry Andric    __m_        = nullptr;
3630b57cec5SDimitry Andric    __owns_     = false;
3640b57cec5SDimitry Andric    __m_        = __u.__m_;
3650b57cec5SDimitry Andric    __owns_     = __u.__owns_;
3660b57cec5SDimitry Andric    __u.__m_    = nullptr;
3670b57cec5SDimitry Andric    __u.__owns_ = false;
3680b57cec5SDimitry Andric    return *this;
3690b57cec5SDimitry Andric  }
3700b57cec5SDimitry Andric
371*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI void lock();
372*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI bool try_lock();
373*06c3fb27SDimitry Andric  template <class _Rep, class _Period>
374*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time);
375*06c3fb27SDimitry Andric  template <class _Clock, class _Duration>
376*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
377*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI void unlock();
3780b57cec5SDimitry Andric
3790b57cec5SDimitry Andric  // Setters
380*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI void swap(shared_lock& __u) _NOEXCEPT {
3810b57cec5SDimitry Andric    _VSTD::swap(__m_, __u.__m_);
3820b57cec5SDimitry Andric    _VSTD::swap(__owns_, __u.__owns_);
3830b57cec5SDimitry Andric  }
3840b57cec5SDimitry Andric
385*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI mutex_type* release() _NOEXCEPT {
3860b57cec5SDimitry Andric    mutex_type* __m = __m_;
3870b57cec5SDimitry Andric    __m_            = nullptr;
3880b57cec5SDimitry Andric    __owns_         = false;
3890b57cec5SDimitry Andric    return __m;
3900b57cec5SDimitry Andric  }
3910b57cec5SDimitry Andric
3920b57cec5SDimitry Andric  // Getters
393*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI bool owns_lock() const _NOEXCEPT { return __owns_; }
3940b57cec5SDimitry Andric
395*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI explicit operator bool() const _NOEXCEPT { return __owns_; }
3960b57cec5SDimitry Andric
397*06c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI mutex_type* mutex() const _NOEXCEPT { return __m_; }
3980b57cec5SDimitry Andric};
399bdd1243dSDimitry Andric_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(shared_lock);
4000b57cec5SDimitry Andric
4010b57cec5SDimitry Andrictemplate <class _Mutex>
402*06c3fb27SDimitry Andricvoid shared_lock<_Mutex>::lock() {
4030b57cec5SDimitry Andric  if (__m_ == nullptr)
4040b57cec5SDimitry Andric    __throw_system_error(EPERM, "shared_lock::lock: references null mutex");
4050b57cec5SDimitry Andric  if (__owns_)
4060b57cec5SDimitry Andric    __throw_system_error(EDEADLK, "shared_lock::lock: already locked");
4070b57cec5SDimitry Andric  __m_->lock_shared();
4080b57cec5SDimitry Andric  __owns_ = true;
4090b57cec5SDimitry Andric}
4100b57cec5SDimitry Andric
4110b57cec5SDimitry Andrictemplate <class _Mutex>
412*06c3fb27SDimitry Andricbool shared_lock<_Mutex>::try_lock() {
4130b57cec5SDimitry Andric  if (__m_ == nullptr)
4140b57cec5SDimitry Andric    __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex");
4150b57cec5SDimitry Andric  if (__owns_)
4160b57cec5SDimitry Andric    __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked");
4170b57cec5SDimitry Andric  __owns_ = __m_->try_lock_shared();
4180b57cec5SDimitry Andric  return __owns_;
4190b57cec5SDimitry Andric}
4200b57cec5SDimitry Andric
4210b57cec5SDimitry Andrictemplate <class _Mutex>
4220b57cec5SDimitry Andrictemplate <class _Rep, class _Period>
423*06c3fb27SDimitry Andricbool shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d) {
4240b57cec5SDimitry Andric  if (__m_ == nullptr)
4250b57cec5SDimitry Andric    __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex");
4260b57cec5SDimitry Andric  if (__owns_)
4270b57cec5SDimitry Andric    __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked");
4280b57cec5SDimitry Andric  __owns_ = __m_->try_lock_shared_for(__d);
4290b57cec5SDimitry Andric  return __owns_;
4300b57cec5SDimitry Andric}
4310b57cec5SDimitry Andric
4320b57cec5SDimitry Andrictemplate <class _Mutex>
4330b57cec5SDimitry Andrictemplate <class _Clock, class _Duration>
434*06c3fb27SDimitry Andricbool shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) {
4350b57cec5SDimitry Andric  if (__m_ == nullptr)
4360b57cec5SDimitry Andric    __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex");
4370b57cec5SDimitry Andric  if (__owns_)
4380b57cec5SDimitry Andric    __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked");
4390b57cec5SDimitry Andric  __owns_ = __m_->try_lock_shared_until(__t);
4400b57cec5SDimitry Andric  return __owns_;
4410b57cec5SDimitry Andric}
4420b57cec5SDimitry Andric
4430b57cec5SDimitry Andrictemplate <class _Mutex>
444*06c3fb27SDimitry Andricvoid shared_lock<_Mutex>::unlock() {
4450b57cec5SDimitry Andric  if (!__owns_)
4460b57cec5SDimitry Andric    __throw_system_error(EPERM, "shared_lock::unlock: not locked");
4470b57cec5SDimitry Andric  __m_->unlock_shared();
4480b57cec5SDimitry Andric  __owns_ = false;
4490b57cec5SDimitry Andric}
4500b57cec5SDimitry Andric
4510b57cec5SDimitry Andrictemplate <class _Mutex>
452*06c3fb27SDimitry Andricinline _LIBCPP_HIDE_FROM_ABI void swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) _NOEXCEPT {
453*06c3fb27SDimitry Andric  __x.swap(__y);
454*06c3fb27SDimitry Andric}
4550b57cec5SDimitry Andric
4560b57cec5SDimitry Andric_LIBCPP_END_NAMESPACE_STD
4570b57cec5SDimitry Andric
458*06c3fb27SDimitry Andric#endif // _LIBCPP_STD_VER >= 14
4590b57cec5SDimitry Andric
4600b57cec5SDimitry Andric_LIBCPP_POP_MACROS
4610b57cec5SDimitry Andric
462*06c3fb27SDimitry Andric#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
463*06c3fb27SDimitry Andric#  include <system_error>
464*06c3fb27SDimitry Andric#endif
465*06c3fb27SDimitry Andric
4660b57cec5SDimitry Andric#endif // _LIBCPP_SHARED_MUTEX
467