xref: /llvm-project/libcxx/include/__cxx03/shared_mutex (revision ce7771902dc50d900de639d499a60486b83f70e0)
1e78f53d1SNikolas Klauser// -*- C++ -*-
2e78f53d1SNikolas Klauser//===----------------------------------------------------------------------===//
3e78f53d1SNikolas Klauser//
4e78f53d1SNikolas Klauser// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5e78f53d1SNikolas Klauser// See https://llvm.org/LICENSE.txt for license information.
6e78f53d1SNikolas Klauser// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7e78f53d1SNikolas Klauser//
8e78f53d1SNikolas Klauser//===----------------------------------------------------------------------===//
9e78f53d1SNikolas Klauser
10*ce777190SNikolas Klauser#ifndef _LIBCPP___CXX03_SHARED_MUTEX
11*ce777190SNikolas Klauser#define _LIBCPP___CXX03_SHARED_MUTEX
12e78f53d1SNikolas Klauser
13e78f53d1SNikolas Klauser/*
14e78f53d1SNikolas Klauser    shared_mutex synopsis
15e78f53d1SNikolas Klauser
16e78f53d1SNikolas Klauser// C++1y
17e78f53d1SNikolas Klauser
18e78f53d1SNikolas Klausernamespace std
19e78f53d1SNikolas Klauser{
20e78f53d1SNikolas Klauser
21e78f53d1SNikolas Klauserclass shared_mutex      // C++17
22e78f53d1SNikolas Klauser{
23e78f53d1SNikolas Klauserpublic:
24e78f53d1SNikolas Klauser    shared_mutex();
25e78f53d1SNikolas Klauser    ~shared_mutex();
26e78f53d1SNikolas Klauser
27e78f53d1SNikolas Klauser    shared_mutex(const shared_mutex&) = delete;
28e78f53d1SNikolas Klauser    shared_mutex& operator=(const shared_mutex&) = delete;
29e78f53d1SNikolas Klauser
30e78f53d1SNikolas Klauser    // Exclusive ownership
31e78f53d1SNikolas Klauser    void lock(); // blocking
32e78f53d1SNikolas Klauser    bool try_lock();
33e78f53d1SNikolas Klauser    void unlock();
34e78f53d1SNikolas Klauser
35e78f53d1SNikolas Klauser    // Shared ownership
36e78f53d1SNikolas Klauser    void lock_shared(); // blocking
37e78f53d1SNikolas Klauser    bool try_lock_shared();
38e78f53d1SNikolas Klauser    void unlock_shared();
39e78f53d1SNikolas Klauser
40e78f53d1SNikolas Klauser    typedef implementation-defined native_handle_type; // See 30.2.3
41e78f53d1SNikolas Klauser    native_handle_type native_handle(); // See 30.2.3
42e78f53d1SNikolas Klauser};
43e78f53d1SNikolas Klauser
44e78f53d1SNikolas Klauserclass shared_timed_mutex
45e78f53d1SNikolas Klauser{
46e78f53d1SNikolas Klauserpublic:
47e78f53d1SNikolas Klauser    shared_timed_mutex();
48e78f53d1SNikolas Klauser    ~shared_timed_mutex();
49e78f53d1SNikolas Klauser
50e78f53d1SNikolas Klauser    shared_timed_mutex(const shared_timed_mutex&) = delete;
51e78f53d1SNikolas Klauser    shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
52e78f53d1SNikolas Klauser
53e78f53d1SNikolas Klauser    // Exclusive ownership
54e78f53d1SNikolas Klauser    void lock(); // blocking
55e78f53d1SNikolas Klauser    bool try_lock();
56e78f53d1SNikolas Klauser    template <class Rep, class Period>
57e78f53d1SNikolas Klauser        bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
58e78f53d1SNikolas Klauser    template <class Clock, class Duration>
59e78f53d1SNikolas Klauser        bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
60e78f53d1SNikolas Klauser    void unlock();
61e78f53d1SNikolas Klauser
62e78f53d1SNikolas Klauser    // Shared ownership
63e78f53d1SNikolas Klauser    void lock_shared(); // blocking
64e78f53d1SNikolas Klauser    bool try_lock_shared();
65e78f53d1SNikolas Klauser    template <class Rep, class Period>
66e78f53d1SNikolas Klauser        bool
67e78f53d1SNikolas Klauser        try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time);
68e78f53d1SNikolas Klauser    template <class Clock, class Duration>
69e78f53d1SNikolas Klauser        bool
70e78f53d1SNikolas Klauser        try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time);
71e78f53d1SNikolas Klauser    void unlock_shared();
72e78f53d1SNikolas Klauser};
73e78f53d1SNikolas Klauser
74e78f53d1SNikolas Klausertemplate <class Mutex>
75e78f53d1SNikolas Klauserclass shared_lock
76e78f53d1SNikolas Klauser{
77e78f53d1SNikolas Klauserpublic:
78e78f53d1SNikolas Klauser    typedef Mutex mutex_type;
79e78f53d1SNikolas Klauser
80e78f53d1SNikolas Klauser    // Shared locking
81e78f53d1SNikolas Klauser    shared_lock() noexcept;
82e78f53d1SNikolas Klauser    explicit shared_lock(mutex_type& m); // blocking
83e78f53d1SNikolas Klauser    shared_lock(mutex_type& m, defer_lock_t) noexcept;
84e78f53d1SNikolas Klauser    shared_lock(mutex_type& m, try_to_lock_t);
85e78f53d1SNikolas Klauser    shared_lock(mutex_type& m, adopt_lock_t);
86e78f53d1SNikolas Klauser    template <class Clock, class Duration>
87e78f53d1SNikolas Klauser        shared_lock(mutex_type& m,
88e78f53d1SNikolas Klauser                    const chrono::time_point<Clock, Duration>& abs_time);
89e78f53d1SNikolas Klauser    template <class Rep, class Period>
90e78f53d1SNikolas Klauser        shared_lock(mutex_type& m,
91e78f53d1SNikolas Klauser                    const chrono::duration<Rep, Period>& rel_time);
92e78f53d1SNikolas Klauser    ~shared_lock();
93e78f53d1SNikolas Klauser
94e78f53d1SNikolas Klauser    shared_lock(shared_lock const&) = delete;
95e78f53d1SNikolas Klauser    shared_lock& operator=(shared_lock const&) = delete;
96e78f53d1SNikolas Klauser
97e78f53d1SNikolas Klauser    shared_lock(shared_lock&& u) noexcept;
98e78f53d1SNikolas Klauser    shared_lock& operator=(shared_lock&& u) noexcept;
99e78f53d1SNikolas Klauser
100e78f53d1SNikolas Klauser    void lock(); // blocking
101e78f53d1SNikolas Klauser    bool try_lock();
102e78f53d1SNikolas Klauser    template <class Rep, class Period>
103e78f53d1SNikolas Klauser        bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
104e78f53d1SNikolas Klauser    template <class Clock, class Duration>
105e78f53d1SNikolas Klauser        bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
106e78f53d1SNikolas Klauser    void unlock();
107e78f53d1SNikolas Klauser
108e78f53d1SNikolas Klauser    // Setters
109e78f53d1SNikolas Klauser    void swap(shared_lock& u) noexcept;
110e78f53d1SNikolas Klauser    mutex_type* release() noexcept;
111e78f53d1SNikolas Klauser
112e78f53d1SNikolas Klauser    // Getters
113e78f53d1SNikolas Klauser    bool owns_lock() const noexcept;
114e78f53d1SNikolas Klauser    explicit operator bool () const noexcept;
115e78f53d1SNikolas Klauser    mutex_type* mutex() const noexcept;
116e78f53d1SNikolas Klauser};
117e78f53d1SNikolas Klauser
118e78f53d1SNikolas Klausertemplate <class Mutex>
119e78f53d1SNikolas Klauser    void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
120e78f53d1SNikolas Klauser
121e78f53d1SNikolas Klauser}  // std
122e78f53d1SNikolas Klauser
123e78f53d1SNikolas Klauser*/
124e78f53d1SNikolas Klauser
12573fbae83SNikolas Klauser#include <__cxx03/__config>
126e78f53d1SNikolas Klauser
127e78f53d1SNikolas Klauser#if !defined(_LIBCPP_HAS_NO_THREADS)
128e78f53d1SNikolas Klauser
12973fbae83SNikolas Klauser#  include <__cxx03/__chrono/duration.h>
13073fbae83SNikolas Klauser#  include <__cxx03/__chrono/steady_clock.h>
13173fbae83SNikolas Klauser#  include <__cxx03/__chrono/time_point.h>
13273fbae83SNikolas Klauser#  include <__cxx03/__condition_variable/condition_variable.h>
13373fbae83SNikolas Klauser#  include <__cxx03/__memory/addressof.h>
13473fbae83SNikolas Klauser#  include <__cxx03/__mutex/mutex.h>
13573fbae83SNikolas Klauser#  include <__cxx03/__mutex/tag_types.h>
13673fbae83SNikolas Klauser#  include <__cxx03/__mutex/unique_lock.h>
13773fbae83SNikolas Klauser#  include <__cxx03/__system_error/system_error.h>
13873fbae83SNikolas Klauser#  include <__cxx03/__utility/swap.h>
13973fbae83SNikolas Klauser#  include <__cxx03/cerrno>
14073fbae83SNikolas Klauser#  include <__cxx03/version>
141e78f53d1SNikolas Klauser
142e78f53d1SNikolas Klauser_LIBCPP_PUSH_MACROS
14373fbae83SNikolas Klauser#  include <__cxx03/__undef_macros>
144e78f53d1SNikolas Klauser
145e78f53d1SNikolas Klauser#  if _LIBCPP_STD_VER >= 14
146e78f53d1SNikolas Klauser
147e78f53d1SNikolas Klauser#    if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
148e78f53d1SNikolas Klauser#      pragma GCC system_header
149e78f53d1SNikolas Klauser#    endif
150e78f53d1SNikolas Klauser
151e78f53d1SNikolas Klauser_LIBCPP_BEGIN_NAMESPACE_STD
152e78f53d1SNikolas Klauser
153e78f53d1SNikolas Klauserstruct _LIBCPP_EXPORTED_FROM_ABI __shared_mutex_base {
154e78f53d1SNikolas Klauser  mutex __mut_;
155e78f53d1SNikolas Klauser  condition_variable __gate1_;
156e78f53d1SNikolas Klauser  condition_variable __gate2_;
157e78f53d1SNikolas Klauser  unsigned __state_;
158e78f53d1SNikolas Klauser
159e78f53d1SNikolas Klauser  static const unsigned __write_entered_ = 1U << (sizeof(unsigned) * __CHAR_BIT__ - 1);
160e78f53d1SNikolas Klauser  static const unsigned __n_readers_     = ~__write_entered_;
161e78f53d1SNikolas Klauser
162e78f53d1SNikolas Klauser  __shared_mutex_base();
163e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI ~__shared_mutex_base() = default;
164e78f53d1SNikolas Klauser
165e78f53d1SNikolas Klauser  __shared_mutex_base(const __shared_mutex_base&)            = delete;
166e78f53d1SNikolas Klauser  __shared_mutex_base& operator=(const __shared_mutex_base&) = delete;
167e78f53d1SNikolas Klauser
168e78f53d1SNikolas Klauser  // Exclusive ownership
169e78f53d1SNikolas Klauser  void lock(); // blocking
170e78f53d1SNikolas Klauser  bool try_lock();
171e78f53d1SNikolas Klauser  void unlock();
172e78f53d1SNikolas Klauser
173e78f53d1SNikolas Klauser  // Shared ownership
174e78f53d1SNikolas Klauser  void lock_shared(); // blocking
175e78f53d1SNikolas Klauser  bool try_lock_shared();
176e78f53d1SNikolas Klauser  void unlock_shared();
177e78f53d1SNikolas Klauser
178e78f53d1SNikolas Klauser  //     typedef implementation-defined native_handle_type; // See 30.2.3
179e78f53d1SNikolas Klauser  //     native_handle_type native_handle(); // See 30.2.3
180e78f53d1SNikolas Klauser};
181e78f53d1SNikolas Klauser
182e78f53d1SNikolas Klauser#    if _LIBCPP_STD_VER >= 17
183e78f53d1SNikolas Klauserclass _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_THREAD_SAFETY_ANNOTATION(__capability__("shared_mutex")) shared_mutex {
184e78f53d1SNikolas Klauser  __shared_mutex_base __base_;
185e78f53d1SNikolas Klauser
186e78f53d1SNikolas Klauserpublic:
187e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI shared_mutex() : __base_() {}
188e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI ~shared_mutex() = default;
189e78f53d1SNikolas Klauser
190e78f53d1SNikolas Klauser  shared_mutex(const shared_mutex&)            = delete;
191e78f53d1SNikolas Klauser  shared_mutex& operator=(const shared_mutex&) = delete;
192e78f53d1SNikolas Klauser
193e78f53d1SNikolas Klauser  // Exclusive ownership
194e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__acquire_capability__()) {
195e78f53d1SNikolas Klauser    return __base_.lock();
196e78f53d1SNikolas Klauser  }
197e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI bool try_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_capability__(true)) {
198e78f53d1SNikolas Klauser    return __base_.try_lock();
199e78f53d1SNikolas Klauser  }
200e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI void unlock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__release_capability__()) {
201e78f53d1SNikolas Klauser    return __base_.unlock();
202e78f53d1SNikolas Klauser  }
203e78f53d1SNikolas Klauser
204e78f53d1SNikolas Klauser  // Shared ownership
205e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI void lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__acquire_shared_capability__()) {
206e78f53d1SNikolas Klauser    return __base_.lock_shared();
207e78f53d1SNikolas Klauser  }
208e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI bool try_lock_shared()
209e78f53d1SNikolas Klauser      _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_shared_capability__(true)) {
210e78f53d1SNikolas Klauser    return __base_.try_lock_shared();
211e78f53d1SNikolas Klauser  }
212e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI void unlock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__release_shared_capability__()) {
213e78f53d1SNikolas Klauser    return __base_.unlock_shared();
214e78f53d1SNikolas Klauser  }
215e78f53d1SNikolas Klauser
216e78f53d1SNikolas Klauser  //     typedef __shared_mutex_base::native_handle_type native_handle_type;
217e78f53d1SNikolas Klauser  //     _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return __base::unlock_shared(); }
218e78f53d1SNikolas Klauser};
219e78f53d1SNikolas Klauser#    endif
220e78f53d1SNikolas Klauser
221e78f53d1SNikolas Klauserclass _LIBCPP_EXPORTED_FROM_ABI
222e78f53d1SNikolas Klauser_LIBCPP_THREAD_SAFETY_ANNOTATION(__capability__("shared_timed_mutex")) shared_timed_mutex {
223e78f53d1SNikolas Klauser  __shared_mutex_base __base_;
224e78f53d1SNikolas Klauser
225e78f53d1SNikolas Klauserpublic:
226e78f53d1SNikolas Klauser  shared_timed_mutex();
227e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI ~shared_timed_mutex() = default;
228e78f53d1SNikolas Klauser
229e78f53d1SNikolas Klauser  shared_timed_mutex(const shared_timed_mutex&)            = delete;
230e78f53d1SNikolas Klauser  shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
231e78f53d1SNikolas Klauser
232e78f53d1SNikolas Klauser  // Exclusive ownership
233e78f53d1SNikolas Klauser  void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__acquire_capability__());
234e78f53d1SNikolas Klauser  bool try_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_capability__(true));
235e78f53d1SNikolas Klauser  template <class _Rep, class _Period>
236e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
237e78f53d1SNikolas Klauser      _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_capability__(true)) {
238e78f53d1SNikolas Klauser    return try_lock_until(chrono::steady_clock::now() + __rel_time);
239e78f53d1SNikolas Klauser  }
240e78f53d1SNikolas Klauser  template <class _Clock, class _Duration>
241e78f53d1SNikolas Klauser  _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool
242e78f53d1SNikolas Klauser  try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time)
243e78f53d1SNikolas Klauser      _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_capability__(true));
244e78f53d1SNikolas Klauser  void unlock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__release_capability__());
245e78f53d1SNikolas Klauser
246e78f53d1SNikolas Klauser  // Shared ownership
247e78f53d1SNikolas Klauser  void lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__acquire_shared_capability__());
248e78f53d1SNikolas Klauser  bool try_lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_shared_capability__(true));
249e78f53d1SNikolas Klauser  template <class _Rep, class _Period>
250e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI bool try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
251e78f53d1SNikolas Klauser      _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_shared_capability__(true)) {
252e78f53d1SNikolas Klauser    return try_lock_shared_until(chrono::steady_clock::now() + __rel_time);
253e78f53d1SNikolas Klauser  }
254e78f53d1SNikolas Klauser  template <class _Clock, class _Duration>
255e78f53d1SNikolas Klauser  _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool
256e78f53d1SNikolas Klauser  try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time)
257e78f53d1SNikolas Klauser      _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_shared_capability__(true));
258e78f53d1SNikolas Klauser  void unlock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__release_shared_capability__());
259e78f53d1SNikolas Klauser};
260e78f53d1SNikolas Klauser
261e78f53d1SNikolas Klausertemplate <class _Clock, class _Duration>
262e78f53d1SNikolas Klauserbool shared_timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time) {
263e78f53d1SNikolas Klauser  unique_lock<mutex> __lk(__base_.__mut_);
264e78f53d1SNikolas Klauser  if (__base_.__state_ & __base_.__write_entered_) {
265e78f53d1SNikolas Klauser    while (true) {
266e78f53d1SNikolas Klauser      cv_status __status = __base_.__gate1_.wait_until(__lk, __abs_time);
267e78f53d1SNikolas Klauser      if ((__base_.__state_ & __base_.__write_entered_) == 0)
268e78f53d1SNikolas Klauser        break;
269e78f53d1SNikolas Klauser      if (__status == cv_status::timeout)
270e78f53d1SNikolas Klauser        return false;
271e78f53d1SNikolas Klauser    }
272e78f53d1SNikolas Klauser  }
273e78f53d1SNikolas Klauser  __base_.__state_ |= __base_.__write_entered_;
274e78f53d1SNikolas Klauser  if (__base_.__state_ & __base_.__n_readers_) {
275e78f53d1SNikolas Klauser    while (true) {
276e78f53d1SNikolas Klauser      cv_status __status = __base_.__gate2_.wait_until(__lk, __abs_time);
277e78f53d1SNikolas Klauser      if ((__base_.__state_ & __base_.__n_readers_) == 0)
278e78f53d1SNikolas Klauser        break;
279e78f53d1SNikolas Klauser      if (__status == cv_status::timeout) {
280e78f53d1SNikolas Klauser        __base_.__state_ &= ~__base_.__write_entered_;
281e78f53d1SNikolas Klauser        __base_.__gate1_.notify_all();
282e78f53d1SNikolas Klauser        return false;
283e78f53d1SNikolas Klauser      }
284e78f53d1SNikolas Klauser    }
285e78f53d1SNikolas Klauser  }
286e78f53d1SNikolas Klauser  return true;
287e78f53d1SNikolas Klauser}
288e78f53d1SNikolas Klauser
289e78f53d1SNikolas Klausertemplate <class _Clock, class _Duration>
290e78f53d1SNikolas Klauserbool shared_timed_mutex::try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time) {
291e78f53d1SNikolas Klauser  unique_lock<mutex> __lk(__base_.__mut_);
292e78f53d1SNikolas Klauser  if ((__base_.__state_ & __base_.__write_entered_) ||
293e78f53d1SNikolas Klauser      (__base_.__state_ & __base_.__n_readers_) == __base_.__n_readers_) {
294e78f53d1SNikolas Klauser    while (true) {
295e78f53d1SNikolas Klauser      cv_status __status = __base_.__gate1_.wait_until(__lk, __abs_time);
296e78f53d1SNikolas Klauser      if ((__base_.__state_ & __base_.__write_entered_) == 0 &&
297e78f53d1SNikolas Klauser          (__base_.__state_ & __base_.__n_readers_) < __base_.__n_readers_)
298e78f53d1SNikolas Klauser        break;
299e78f53d1SNikolas Klauser      if (__status == cv_status::timeout)
300e78f53d1SNikolas Klauser        return false;
301e78f53d1SNikolas Klauser    }
302e78f53d1SNikolas Klauser  }
303e78f53d1SNikolas Klauser  unsigned __num_readers = (__base_.__state_ & __base_.__n_readers_) + 1;
304e78f53d1SNikolas Klauser  __base_.__state_ &= ~__base_.__n_readers_;
305e78f53d1SNikolas Klauser  __base_.__state_ |= __num_readers;
306e78f53d1SNikolas Klauser  return true;
307e78f53d1SNikolas Klauser}
308e78f53d1SNikolas Klauser
309e78f53d1SNikolas Klausertemplate <class _Mutex>
310e78f53d1SNikolas Klauserclass shared_lock {
311e78f53d1SNikolas Klauserpublic:
312e78f53d1SNikolas Klauser  typedef _Mutex mutex_type;
313e78f53d1SNikolas Klauser
314e78f53d1SNikolas Klauserprivate:
315e78f53d1SNikolas Klauser  mutex_type* __m_;
316e78f53d1SNikolas Klauser  bool __owns_;
317e78f53d1SNikolas Klauser
318e78f53d1SNikolas Klauserpublic:
319e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI shared_lock() _NOEXCEPT : __m_(nullptr), __owns_(false) {}
320e78f53d1SNikolas Klauser
321e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI explicit shared_lock(mutex_type& __m) : __m_(std::addressof(__m)), __owns_(true) {
322e78f53d1SNikolas Klauser    __m_->lock_shared();
323e78f53d1SNikolas Klauser  }
324e78f53d1SNikolas Klauser
325e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI shared_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
326e78f53d1SNikolas Klauser      : __m_(std::addressof(__m)),
327e78f53d1SNikolas Klauser        __owns_(false) {}
328e78f53d1SNikolas Klauser
329e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI shared_lock(mutex_type& __m, try_to_lock_t)
330e78f53d1SNikolas Klauser      : __m_(std::addressof(__m)), __owns_(__m.try_lock_shared()) {}
331e78f53d1SNikolas Klauser
332e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI shared_lock(mutex_type& __m, adopt_lock_t) : __m_(std::addressof(__m)), __owns_(true) {}
333e78f53d1SNikolas Klauser
334e78f53d1SNikolas Klauser  template <class _Clock, class _Duration>
335e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI shared_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __abs_time)
336e78f53d1SNikolas Klauser      : __m_(std::addressof(__m)), __owns_(__m.try_lock_shared_until(__abs_time)) {}
337e78f53d1SNikolas Klauser
338e78f53d1SNikolas Klauser  template <class _Rep, class _Period>
339e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI shared_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __rel_time)
340e78f53d1SNikolas Klauser      : __m_(std::addressof(__m)), __owns_(__m.try_lock_shared_for(__rel_time)) {}
341e78f53d1SNikolas Klauser
342e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI ~shared_lock() {
343e78f53d1SNikolas Klauser    if (__owns_)
344e78f53d1SNikolas Klauser      __m_->unlock_shared();
345e78f53d1SNikolas Klauser  }
346e78f53d1SNikolas Klauser
347e78f53d1SNikolas Klauser  shared_lock(shared_lock const&)            = delete;
348e78f53d1SNikolas Klauser  shared_lock& operator=(shared_lock const&) = delete;
349e78f53d1SNikolas Klauser
350e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI shared_lock(shared_lock&& __u) _NOEXCEPT : __m_(__u.__m_), __owns_(__u.__owns_) {
351e78f53d1SNikolas Klauser    __u.__m_    = nullptr;
352e78f53d1SNikolas Klauser    __u.__owns_ = false;
353e78f53d1SNikolas Klauser  }
354e78f53d1SNikolas Klauser
355e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI shared_lock& operator=(shared_lock&& __u) _NOEXCEPT {
356e78f53d1SNikolas Klauser    if (__owns_)
357e78f53d1SNikolas Klauser      __m_->unlock_shared();
358e78f53d1SNikolas Klauser    __m_        = nullptr;
359e78f53d1SNikolas Klauser    __owns_     = false;
360e78f53d1SNikolas Klauser    __m_        = __u.__m_;
361e78f53d1SNikolas Klauser    __owns_     = __u.__owns_;
362e78f53d1SNikolas Klauser    __u.__m_    = nullptr;
363e78f53d1SNikolas Klauser    __u.__owns_ = false;
364e78f53d1SNikolas Klauser    return *this;
365e78f53d1SNikolas Klauser  }
366e78f53d1SNikolas Klauser
367e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI void lock();
368e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI bool try_lock();
369e78f53d1SNikolas Klauser  template <class _Rep, class _Period>
370e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time);
371e78f53d1SNikolas Klauser  template <class _Clock, class _Duration>
372e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
373e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI void unlock();
374e78f53d1SNikolas Klauser
375e78f53d1SNikolas Klauser  // Setters
376e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI void swap(shared_lock& __u) _NOEXCEPT {
377e78f53d1SNikolas Klauser    std::swap(__m_, __u.__m_);
378e78f53d1SNikolas Klauser    std::swap(__owns_, __u.__owns_);
379e78f53d1SNikolas Klauser  }
380e78f53d1SNikolas Klauser
381e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI mutex_type* release() _NOEXCEPT {
382e78f53d1SNikolas Klauser    mutex_type* __m = __m_;
383e78f53d1SNikolas Klauser    __m_            = nullptr;
384e78f53d1SNikolas Klauser    __owns_         = false;
385e78f53d1SNikolas Klauser    return __m;
386e78f53d1SNikolas Klauser  }
387e78f53d1SNikolas Klauser
388e78f53d1SNikolas Klauser  // Getters
389e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI bool owns_lock() const _NOEXCEPT { return __owns_; }
390e78f53d1SNikolas Klauser
391e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI explicit operator bool() const _NOEXCEPT { return __owns_; }
392e78f53d1SNikolas Klauser
393e78f53d1SNikolas Klauser  _LIBCPP_HIDE_FROM_ABI mutex_type* mutex() const _NOEXCEPT { return __m_; }
394e78f53d1SNikolas Klauser};
395e78f53d1SNikolas Klauser_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(shared_lock);
396e78f53d1SNikolas Klauser
397e78f53d1SNikolas Klausertemplate <class _Mutex>
398e78f53d1SNikolas Klauservoid shared_lock<_Mutex>::lock() {
399e78f53d1SNikolas Klauser  if (__m_ == nullptr)
400e78f53d1SNikolas Klauser    __throw_system_error(EPERM, "shared_lock::lock: references null mutex");
401e78f53d1SNikolas Klauser  if (__owns_)
402e78f53d1SNikolas Klauser    __throw_system_error(EDEADLK, "shared_lock::lock: already locked");
403e78f53d1SNikolas Klauser  __m_->lock_shared();
404e78f53d1SNikolas Klauser  __owns_ = true;
405e78f53d1SNikolas Klauser}
406e78f53d1SNikolas Klauser
407e78f53d1SNikolas Klausertemplate <class _Mutex>
408e78f53d1SNikolas Klauserbool shared_lock<_Mutex>::try_lock() {
409e78f53d1SNikolas Klauser  if (__m_ == nullptr)
410e78f53d1SNikolas Klauser    __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex");
411e78f53d1SNikolas Klauser  if (__owns_)
412e78f53d1SNikolas Klauser    __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked");
413e78f53d1SNikolas Klauser  __owns_ = __m_->try_lock_shared();
414e78f53d1SNikolas Klauser  return __owns_;
415e78f53d1SNikolas Klauser}
416e78f53d1SNikolas Klauser
417e78f53d1SNikolas Klausertemplate <class _Mutex>
418e78f53d1SNikolas Klausertemplate <class _Rep, class _Period>
419e78f53d1SNikolas Klauserbool shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d) {
420e78f53d1SNikolas Klauser  if (__m_ == nullptr)
421e78f53d1SNikolas Klauser    __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex");
422e78f53d1SNikolas Klauser  if (__owns_)
423e78f53d1SNikolas Klauser    __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked");
424e78f53d1SNikolas Klauser  __owns_ = __m_->try_lock_shared_for(__d);
425e78f53d1SNikolas Klauser  return __owns_;
426e78f53d1SNikolas Klauser}
427e78f53d1SNikolas Klauser
428e78f53d1SNikolas Klausertemplate <class _Mutex>
429e78f53d1SNikolas Klausertemplate <class _Clock, class _Duration>
430e78f53d1SNikolas Klauserbool shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) {
431e78f53d1SNikolas Klauser  if (__m_ == nullptr)
432e78f53d1SNikolas Klauser    __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex");
433e78f53d1SNikolas Klauser  if (__owns_)
434e78f53d1SNikolas Klauser    __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked");
435e78f53d1SNikolas Klauser  __owns_ = __m_->try_lock_shared_until(__t);
436e78f53d1SNikolas Klauser  return __owns_;
437e78f53d1SNikolas Klauser}
438e78f53d1SNikolas Klauser
439e78f53d1SNikolas Klausertemplate <class _Mutex>
440e78f53d1SNikolas Klauservoid shared_lock<_Mutex>::unlock() {
441e78f53d1SNikolas Klauser  if (!__owns_)
442e78f53d1SNikolas Klauser    __throw_system_error(EPERM, "shared_lock::unlock: not locked");
443e78f53d1SNikolas Klauser  __m_->unlock_shared();
444e78f53d1SNikolas Klauser  __owns_ = false;
445e78f53d1SNikolas Klauser}
446e78f53d1SNikolas Klauser
447e78f53d1SNikolas Klausertemplate <class _Mutex>
448e78f53d1SNikolas Klauserinline _LIBCPP_HIDE_FROM_ABI void swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) _NOEXCEPT {
449e78f53d1SNikolas Klauser  __x.swap(__y);
450e78f53d1SNikolas Klauser}
451e78f53d1SNikolas Klauser
452e78f53d1SNikolas Klauser_LIBCPP_END_NAMESPACE_STD
453e78f53d1SNikolas Klauser
454e78f53d1SNikolas Klauser#  endif // _LIBCPP_STD_VER >= 14
455e78f53d1SNikolas Klauser
456e78f53d1SNikolas Klauser_LIBCPP_POP_MACROS
457e78f53d1SNikolas Klauser
458e78f53d1SNikolas Klauser#endif // !defined(_LIBCPP_HAS_NO_THREADS)
459e78f53d1SNikolas Klauser
460e78f53d1SNikolas Klauser#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
46173fbae83SNikolas Klauser#  include <__cxx03/system_error>
462e78f53d1SNikolas Klauser#endif
463e78f53d1SNikolas Klauser
464*ce777190SNikolas Klauser#endif // _LIBCPP___CXX03_SHARED_MUTEX
465