xref: /freebsd/contrib/llvm-project/libcxx/include/shared_mutex (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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
1257a6dacacSDimitry Andric#include <__config>
1267a6dacacSDimitry Andric
127*0fca6ea1SDimitry Andric#if !defined(_LIBCPP_HAS_NO_THREADS)
1287a6dacacSDimitry Andric
12906c3fb27SDimitry Andric#  include <__chrono/duration.h>
13006c3fb27SDimitry Andric#  include <__chrono/steady_clock.h>
13106c3fb27SDimitry Andric#  include <__chrono/time_point.h>
13206c3fb27SDimitry Andric#  include <__condition_variable/condition_variable.h>
13306c3fb27SDimitry Andric#  include <__memory/addressof.h>
13406c3fb27SDimitry Andric#  include <__mutex/mutex.h>
13506c3fb27SDimitry Andric#  include <__mutex/tag_types.h>
13606c3fb27SDimitry Andric#  include <__mutex/unique_lock.h>
13706c3fb27SDimitry Andric#  include <__system_error/system_error.h>
13806c3fb27SDimitry Andric#  include <__utility/swap.h>
13906c3fb27SDimitry Andric#  include <cerrno>
1400b57cec5SDimitry Andric#  include <version>
1410b57cec5SDimitry Andric
1420b57cec5SDimitry Andric_LIBCPP_PUSH_MACROS
1430b57cec5SDimitry Andric#  include <__undef_macros>
1440b57cec5SDimitry Andric
14506c3fb27SDimitry Andric#  if _LIBCPP_STD_VER >= 14
1460b57cec5SDimitry Andric
1470b57cec5SDimitry Andric#    if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
1480b57cec5SDimitry Andric#      pragma GCC system_header
1490b57cec5SDimitry Andric#    endif
1500b57cec5SDimitry Andric
1510b57cec5SDimitry Andric_LIBCPP_BEGIN_NAMESPACE_STD
1520b57cec5SDimitry Andric
1535f757f3fSDimitry Andricstruct _LIBCPP_EXPORTED_FROM_ABI __shared_mutex_base {
1540b57cec5SDimitry Andric  mutex __mut_;
1550b57cec5SDimitry Andric  condition_variable __gate1_;
1560b57cec5SDimitry Andric  condition_variable __gate2_;
1570b57cec5SDimitry Andric  unsigned __state_;
1580b57cec5SDimitry Andric
1590b57cec5SDimitry Andric  static const unsigned __write_entered_ = 1U << (sizeof(unsigned) * __CHAR_BIT__ - 1);
1600b57cec5SDimitry Andric  static const unsigned __n_readers_     = ~__write_entered_;
1610b57cec5SDimitry Andric
1620b57cec5SDimitry Andric  __shared_mutex_base();
16306c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI ~__shared_mutex_base() = default;
1640b57cec5SDimitry Andric
1650b57cec5SDimitry Andric  __shared_mutex_base(const __shared_mutex_base&)            = delete;
1660b57cec5SDimitry Andric  __shared_mutex_base& operator=(const __shared_mutex_base&) = delete;
1670b57cec5SDimitry Andric
1680b57cec5SDimitry Andric  // Exclusive ownership
16906c3fb27SDimitry Andric  void lock(); // blocking
17006c3fb27SDimitry Andric  bool try_lock();
17106c3fb27SDimitry Andric  void unlock();
1720b57cec5SDimitry Andric
1730b57cec5SDimitry Andric  // Shared ownership
17406c3fb27SDimitry Andric  void lock_shared(); // blocking
17506c3fb27SDimitry Andric  bool try_lock_shared();
17606c3fb27SDimitry Andric  void unlock_shared();
1770b57cec5SDimitry Andric
1780b57cec5SDimitry Andric  //     typedef implementation-defined native_handle_type; // See 30.2.3
1790b57cec5SDimitry Andric  //     native_handle_type native_handle(); // See 30.2.3
1800b57cec5SDimitry Andric};
1810b57cec5SDimitry Andric
18206c3fb27SDimitry Andric#    if _LIBCPP_STD_VER >= 17
1835f757f3fSDimitry Andricclass _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_THREAD_SAFETY_ANNOTATION(__capability__("shared_mutex")) shared_mutex {
184bdd1243dSDimitry Andric  __shared_mutex_base __base_;
18506c3fb27SDimitry Andric
1860b57cec5SDimitry Andricpublic:
18706c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI shared_mutex() : __base_() {}
18806c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI ~shared_mutex() = default;
1890b57cec5SDimitry Andric
1900b57cec5SDimitry Andric  shared_mutex(const shared_mutex&)            = delete;
1910b57cec5SDimitry Andric  shared_mutex& operator=(const shared_mutex&) = delete;
1920b57cec5SDimitry Andric
1930b57cec5SDimitry Andric  // Exclusive ownership
19406c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__acquire_capability__()) {
19506c3fb27SDimitry Andric    return __base_.lock();
19606c3fb27SDimitry Andric  }
19706c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI bool try_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_capability__(true)) {
19806c3fb27SDimitry Andric    return __base_.try_lock();
19906c3fb27SDimitry Andric  }
20006c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI void unlock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__release_capability__()) {
20106c3fb27SDimitry Andric    return __base_.unlock();
20206c3fb27SDimitry Andric  }
2030b57cec5SDimitry Andric
2040b57cec5SDimitry Andric  // Shared ownership
20506c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI void lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__acquire_shared_capability__()) {
20606c3fb27SDimitry Andric    return __base_.lock_shared();
20706c3fb27SDimitry Andric  }
20806c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI bool try_lock_shared()
20906c3fb27SDimitry Andric      _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_shared_capability__(true)) {
21006c3fb27SDimitry Andric    return __base_.try_lock_shared();
21106c3fb27SDimitry Andric  }
21206c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI void unlock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__release_shared_capability__()) {
21306c3fb27SDimitry Andric    return __base_.unlock_shared();
21406c3fb27SDimitry Andric  }
2150b57cec5SDimitry Andric
2160b57cec5SDimitry Andric  //     typedef __shared_mutex_base::native_handle_type native_handle_type;
21706c3fb27SDimitry Andric  //     _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return __base::unlock_shared(); }
2180b57cec5SDimitry Andric};
2190b57cec5SDimitry Andric#    endif
2200b57cec5SDimitry Andric
221*0fca6ea1SDimitry Andricclass _LIBCPP_EXPORTED_FROM_ABI
222*0fca6ea1SDimitry Andric_LIBCPP_THREAD_SAFETY_ANNOTATION(__capability__("shared_timed_mutex")) shared_timed_mutex {
223bdd1243dSDimitry Andric  __shared_mutex_base __base_;
22406c3fb27SDimitry Andric
2250b57cec5SDimitry Andricpublic:
2260b57cec5SDimitry Andric  shared_timed_mutex();
22706c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI ~shared_timed_mutex() = default;
2280b57cec5SDimitry Andric
2290b57cec5SDimitry Andric  shared_timed_mutex(const shared_timed_mutex&)            = delete;
2300b57cec5SDimitry Andric  shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
2310b57cec5SDimitry Andric
2320b57cec5SDimitry Andric  // Exclusive ownership
23306c3fb27SDimitry Andric  void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__acquire_capability__());
23406c3fb27SDimitry Andric  bool try_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_capability__(true));
2350b57cec5SDimitry Andric  template <class _Rep, class _Period>
23606c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
23706c3fb27SDimitry Andric      _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_capability__(true)) {
2380b57cec5SDimitry Andric    return try_lock_until(chrono::steady_clock::now() + __rel_time);
2390b57cec5SDimitry Andric  }
2400b57cec5SDimitry Andric  template <class _Clock, class _Duration>
24106c3fb27SDimitry Andric  _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool
24206c3fb27SDimitry Andric  try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time)
24306c3fb27SDimitry Andric      _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_capability__(true));
24406c3fb27SDimitry Andric  void unlock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__release_capability__());
2450b57cec5SDimitry Andric
2460b57cec5SDimitry Andric  // Shared ownership
24706c3fb27SDimitry Andric  void lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__acquire_shared_capability__());
24806c3fb27SDimitry Andric  bool try_lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_shared_capability__(true));
2490b57cec5SDimitry Andric  template <class _Rep, class _Period>
25006c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI bool try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
25106c3fb27SDimitry Andric      _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_shared_capability__(true)) {
2520b57cec5SDimitry Andric    return try_lock_shared_until(chrono::steady_clock::now() + __rel_time);
2530b57cec5SDimitry Andric  }
2540b57cec5SDimitry Andric  template <class _Clock, class _Duration>
25506c3fb27SDimitry Andric  _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool
25606c3fb27SDimitry Andric  try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time)
25706c3fb27SDimitry Andric      _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_shared_capability__(true));
25806c3fb27SDimitry Andric  void unlock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__release_shared_capability__());
2590b57cec5SDimitry Andric};
2600b57cec5SDimitry Andric
2610b57cec5SDimitry Andrictemplate <class _Clock, class _Duration>
26206c3fb27SDimitry Andricbool shared_timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time) {
263bdd1243dSDimitry Andric  unique_lock<mutex> __lk(__base_.__mut_);
26406c3fb27SDimitry Andric  if (__base_.__state_ & __base_.__write_entered_) {
26506c3fb27SDimitry Andric    while (true) {
266bdd1243dSDimitry Andric      cv_status __status = __base_.__gate1_.wait_until(__lk, __abs_time);
267bdd1243dSDimitry Andric      if ((__base_.__state_ & __base_.__write_entered_) == 0)
2680b57cec5SDimitry Andric        break;
2690b57cec5SDimitry Andric      if (__status == cv_status::timeout)
2700b57cec5SDimitry Andric        return false;
2710b57cec5SDimitry Andric    }
2720b57cec5SDimitry Andric  }
273bdd1243dSDimitry Andric  __base_.__state_ |= __base_.__write_entered_;
27406c3fb27SDimitry Andric  if (__base_.__state_ & __base_.__n_readers_) {
27506c3fb27SDimitry Andric    while (true) {
276bdd1243dSDimitry Andric      cv_status __status = __base_.__gate2_.wait_until(__lk, __abs_time);
277bdd1243dSDimitry Andric      if ((__base_.__state_ & __base_.__n_readers_) == 0)
2780b57cec5SDimitry Andric        break;
27906c3fb27SDimitry Andric      if (__status == cv_status::timeout) {
280bdd1243dSDimitry Andric        __base_.__state_ &= ~__base_.__write_entered_;
281bdd1243dSDimitry Andric        __base_.__gate1_.notify_all();
2820b57cec5SDimitry Andric        return false;
2830b57cec5SDimitry Andric      }
2840b57cec5SDimitry Andric    }
2850b57cec5SDimitry Andric  }
2860b57cec5SDimitry Andric  return true;
2870b57cec5SDimitry Andric}
2880b57cec5SDimitry Andric
2890b57cec5SDimitry Andrictemplate <class _Clock, class _Duration>
29006c3fb27SDimitry Andricbool shared_timed_mutex::try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time) {
291bdd1243dSDimitry Andric  unique_lock<mutex> __lk(__base_.__mut_);
29206c3fb27SDimitry Andric  if ((__base_.__state_ & __base_.__write_entered_) ||
29306c3fb27SDimitry Andric      (__base_.__state_ & __base_.__n_readers_) == __base_.__n_readers_) {
29406c3fb27SDimitry Andric    while (true) {
29506c3fb27SDimitry Andric      cv_status __status = __base_.__gate1_.wait_until(__lk, __abs_time);
296bdd1243dSDimitry Andric      if ((__base_.__state_ & __base_.__write_entered_) == 0 &&
297bdd1243dSDimitry Andric          (__base_.__state_ & __base_.__n_readers_) < __base_.__n_readers_)
2980b57cec5SDimitry Andric        break;
29906c3fb27SDimitry Andric      if (__status == cv_status::timeout)
3000b57cec5SDimitry Andric        return false;
3010b57cec5SDimitry Andric    }
3020b57cec5SDimitry Andric  }
303bdd1243dSDimitry Andric  unsigned __num_readers = (__base_.__state_ & __base_.__n_readers_) + 1;
304bdd1243dSDimitry Andric  __base_.__state_ &= ~__base_.__n_readers_;
305bdd1243dSDimitry Andric  __base_.__state_ |= __num_readers;
3060b57cec5SDimitry Andric  return true;
3070b57cec5SDimitry Andric}
3080b57cec5SDimitry Andric
3090b57cec5SDimitry Andrictemplate <class _Mutex>
31006c3fb27SDimitry Andricclass shared_lock {
3110b57cec5SDimitry Andricpublic:
3120b57cec5SDimitry Andric  typedef _Mutex mutex_type;
3130b57cec5SDimitry Andric
3140b57cec5SDimitry Andricprivate:
3150b57cec5SDimitry Andric  mutex_type* __m_;
3160b57cec5SDimitry Andric  bool __owns_;
3170b57cec5SDimitry Andric
3180b57cec5SDimitry Andricpublic:
31906c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI shared_lock() _NOEXCEPT : __m_(nullptr), __owns_(false) {}
3200b57cec5SDimitry Andric
3215f757f3fSDimitry Andric  _LIBCPP_HIDE_FROM_ABI explicit shared_lock(mutex_type& __m) : __m_(std::addressof(__m)), __owns_(true) {
32206c3fb27SDimitry Andric    __m_->lock_shared();
32306c3fb27SDimitry Andric  }
3240b57cec5SDimitry Andric
32506c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI shared_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
3265f757f3fSDimitry Andric      : __m_(std::addressof(__m)),
32706c3fb27SDimitry Andric        __owns_(false) {}
3280b57cec5SDimitry Andric
32906c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI shared_lock(mutex_type& __m, try_to_lock_t)
3305f757f3fSDimitry Andric      : __m_(std::addressof(__m)), __owns_(__m.try_lock_shared()) {}
3310b57cec5SDimitry Andric
3325f757f3fSDimitry Andric  _LIBCPP_HIDE_FROM_ABI shared_lock(mutex_type& __m, adopt_lock_t) : __m_(std::addressof(__m)), __owns_(true) {}
3330b57cec5SDimitry Andric
3340b57cec5SDimitry Andric  template <class _Clock, class _Duration>
33506c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI shared_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __abs_time)
3365f757f3fSDimitry Andric      : __m_(std::addressof(__m)), __owns_(__m.try_lock_shared_until(__abs_time)) {}
3370b57cec5SDimitry Andric
3380b57cec5SDimitry Andric  template <class _Rep, class _Period>
33906c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI shared_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __rel_time)
3405f757f3fSDimitry Andric      : __m_(std::addressof(__m)), __owns_(__m.try_lock_shared_for(__rel_time)) {}
3410b57cec5SDimitry Andric
34206c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI ~shared_lock() {
3430b57cec5SDimitry Andric    if (__owns_)
3440b57cec5SDimitry Andric      __m_->unlock_shared();
3450b57cec5SDimitry Andric  }
3460b57cec5SDimitry Andric
3470b57cec5SDimitry Andric  shared_lock(shared_lock const&)            = delete;
3480b57cec5SDimitry Andric  shared_lock& operator=(shared_lock const&) = delete;
3490b57cec5SDimitry Andric
35006c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI shared_lock(shared_lock&& __u) _NOEXCEPT : __m_(__u.__m_), __owns_(__u.__owns_) {
3510b57cec5SDimitry Andric    __u.__m_    = nullptr;
3520b57cec5SDimitry Andric    __u.__owns_ = false;
3530b57cec5SDimitry Andric  }
3540b57cec5SDimitry Andric
35506c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI shared_lock& operator=(shared_lock&& __u) _NOEXCEPT {
3560b57cec5SDimitry Andric    if (__owns_)
3570b57cec5SDimitry Andric      __m_->unlock_shared();
3580b57cec5SDimitry Andric    __m_        = nullptr;
3590b57cec5SDimitry Andric    __owns_     = false;
3600b57cec5SDimitry Andric    __m_        = __u.__m_;
3610b57cec5SDimitry Andric    __owns_     = __u.__owns_;
3620b57cec5SDimitry Andric    __u.__m_    = nullptr;
3630b57cec5SDimitry Andric    __u.__owns_ = false;
3640b57cec5SDimitry Andric    return *this;
3650b57cec5SDimitry Andric  }
3660b57cec5SDimitry Andric
36706c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI void lock();
36806c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI bool try_lock();
36906c3fb27SDimitry Andric  template <class _Rep, class _Period>
37006c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time);
37106c3fb27SDimitry Andric  template <class _Clock, class _Duration>
37206c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
37306c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI void unlock();
3740b57cec5SDimitry Andric
3750b57cec5SDimitry Andric  // Setters
37606c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI void swap(shared_lock& __u) _NOEXCEPT {
3775f757f3fSDimitry Andric    std::swap(__m_, __u.__m_);
3785f757f3fSDimitry Andric    std::swap(__owns_, __u.__owns_);
3790b57cec5SDimitry Andric  }
3800b57cec5SDimitry Andric
38106c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI mutex_type* release() _NOEXCEPT {
3820b57cec5SDimitry Andric    mutex_type* __m = __m_;
3830b57cec5SDimitry Andric    __m_            = nullptr;
3840b57cec5SDimitry Andric    __owns_         = false;
3850b57cec5SDimitry Andric    return __m;
3860b57cec5SDimitry Andric  }
3870b57cec5SDimitry Andric
3880b57cec5SDimitry Andric  // Getters
38906c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI bool owns_lock() const _NOEXCEPT { return __owns_; }
3900b57cec5SDimitry Andric
39106c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI explicit operator bool() const _NOEXCEPT { return __owns_; }
3920b57cec5SDimitry Andric
39306c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI mutex_type* mutex() const _NOEXCEPT { return __m_; }
3940b57cec5SDimitry Andric};
395bdd1243dSDimitry Andric_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(shared_lock);
3960b57cec5SDimitry Andric
3970b57cec5SDimitry Andrictemplate <class _Mutex>
39806c3fb27SDimitry Andricvoid shared_lock<_Mutex>::lock() {
3990b57cec5SDimitry Andric  if (__m_ == nullptr)
4000b57cec5SDimitry Andric    __throw_system_error(EPERM, "shared_lock::lock: references null mutex");
4010b57cec5SDimitry Andric  if (__owns_)
4020b57cec5SDimitry Andric    __throw_system_error(EDEADLK, "shared_lock::lock: already locked");
4030b57cec5SDimitry Andric  __m_->lock_shared();
4040b57cec5SDimitry Andric  __owns_ = true;
4050b57cec5SDimitry Andric}
4060b57cec5SDimitry Andric
4070b57cec5SDimitry Andrictemplate <class _Mutex>
40806c3fb27SDimitry Andricbool shared_lock<_Mutex>::try_lock() {
4090b57cec5SDimitry Andric  if (__m_ == nullptr)
4100b57cec5SDimitry Andric    __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex");
4110b57cec5SDimitry Andric  if (__owns_)
4120b57cec5SDimitry Andric    __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked");
4130b57cec5SDimitry Andric  __owns_ = __m_->try_lock_shared();
4140b57cec5SDimitry Andric  return __owns_;
4150b57cec5SDimitry Andric}
4160b57cec5SDimitry Andric
4170b57cec5SDimitry Andrictemplate <class _Mutex>
4180b57cec5SDimitry Andrictemplate <class _Rep, class _Period>
41906c3fb27SDimitry Andricbool shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d) {
4200b57cec5SDimitry Andric  if (__m_ == nullptr)
4210b57cec5SDimitry Andric    __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex");
4220b57cec5SDimitry Andric  if (__owns_)
4230b57cec5SDimitry Andric    __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked");
4240b57cec5SDimitry Andric  __owns_ = __m_->try_lock_shared_for(__d);
4250b57cec5SDimitry Andric  return __owns_;
4260b57cec5SDimitry Andric}
4270b57cec5SDimitry Andric
4280b57cec5SDimitry Andrictemplate <class _Mutex>
4290b57cec5SDimitry Andrictemplate <class _Clock, class _Duration>
43006c3fb27SDimitry Andricbool shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) {
4310b57cec5SDimitry Andric  if (__m_ == nullptr)
4320b57cec5SDimitry Andric    __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex");
4330b57cec5SDimitry Andric  if (__owns_)
4340b57cec5SDimitry Andric    __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked");
4350b57cec5SDimitry Andric  __owns_ = __m_->try_lock_shared_until(__t);
4360b57cec5SDimitry Andric  return __owns_;
4370b57cec5SDimitry Andric}
4380b57cec5SDimitry Andric
4390b57cec5SDimitry Andrictemplate <class _Mutex>
44006c3fb27SDimitry Andricvoid shared_lock<_Mutex>::unlock() {
4410b57cec5SDimitry Andric  if (!__owns_)
4420b57cec5SDimitry Andric    __throw_system_error(EPERM, "shared_lock::unlock: not locked");
4430b57cec5SDimitry Andric  __m_->unlock_shared();
4440b57cec5SDimitry Andric  __owns_ = false;
4450b57cec5SDimitry Andric}
4460b57cec5SDimitry Andric
4470b57cec5SDimitry Andrictemplate <class _Mutex>
44806c3fb27SDimitry Andricinline _LIBCPP_HIDE_FROM_ABI void swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) _NOEXCEPT {
44906c3fb27SDimitry Andric  __x.swap(__y);
45006c3fb27SDimitry Andric}
4510b57cec5SDimitry Andric
4520b57cec5SDimitry Andric_LIBCPP_END_NAMESPACE_STD
4530b57cec5SDimitry Andric
45406c3fb27SDimitry Andric#  endif // _LIBCPP_STD_VER >= 14
4550b57cec5SDimitry Andric
4560b57cec5SDimitry Andric_LIBCPP_POP_MACROS
4570b57cec5SDimitry Andric
458*0fca6ea1SDimitry Andric#endif // !defined(_LIBCPP_HAS_NO_THREADS)
459*0fca6ea1SDimitry Andric
46006c3fb27SDimitry Andric#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
46106c3fb27SDimitry Andric#  include <system_error>
46206c3fb27SDimitry Andric#endif
46306c3fb27SDimitry Andric
4640b57cec5SDimitry Andric#endif // _LIBCPP_SHARED_MUTEX
465