14f7ab58eSDimitry Andric// -*- C++ -*-
24f7ab58eSDimitry Andric//===------------------------ shared_mutex --------------------------------===//
34f7ab58eSDimitry Andric//
44f7ab58eSDimitry Andric//                     The LLVM Compiler Infrastructure
54f7ab58eSDimitry Andric//
64f7ab58eSDimitry Andric// This file is dual licensed under the MIT and the University of Illinois Open
74f7ab58eSDimitry Andric// Source Licenses. See LICENSE.TXT for details.
84f7ab58eSDimitry Andric//
94f7ab58eSDimitry Andric//===----------------------------------------------------------------------===//
104f7ab58eSDimitry Andric
114f7ab58eSDimitry Andric#ifndef _LIBCPP_SHARED_MUTEX
124f7ab58eSDimitry Andric#define _LIBCPP_SHARED_MUTEX
134f7ab58eSDimitry Andric
144f7ab58eSDimitry Andric/*
154f7ab58eSDimitry Andric    shared_mutex synopsis
164f7ab58eSDimitry Andric
174f7ab58eSDimitry Andric// C++1y
184f7ab58eSDimitry Andric
194f7ab58eSDimitry Andricnamespace std
204f7ab58eSDimitry Andric{
214f7ab58eSDimitry Andric
22854fa44bSDimitry Andricclass shared_mutex      // C++17
23854fa44bSDimitry Andric{
24854fa44bSDimitry Andricpublic:
25854fa44bSDimitry Andric    shared_mutex();
26854fa44bSDimitry Andric    ~shared_mutex();
27854fa44bSDimitry Andric
28854fa44bSDimitry Andric    shared_mutex(const shared_mutex&) = delete;
29854fa44bSDimitry Andric    shared_mutex& operator=(const shared_mutex&) = delete;
30854fa44bSDimitry Andric
31854fa44bSDimitry Andric    // Exclusive ownership
32854fa44bSDimitry Andric    void lock(); // blocking
33854fa44bSDimitry Andric    bool try_lock();
34854fa44bSDimitry Andric    void unlock();
35854fa44bSDimitry Andric
36854fa44bSDimitry Andric    // Shared ownership
37854fa44bSDimitry Andric    void lock_shared(); // blocking
38854fa44bSDimitry Andric    bool try_lock_shared();
39854fa44bSDimitry Andric    void unlock_shared();
40854fa44bSDimitry Andric
41854fa44bSDimitry Andric    typedef implementation-defined native_handle_type; // See 30.2.3
42854fa44bSDimitry Andric    native_handle_type native_handle(); // See 30.2.3
43854fa44bSDimitry Andric};
44854fa44bSDimitry Andric
45d72607e9SDimitry Andricclass shared_timed_mutex
464f7ab58eSDimitry Andric{
474f7ab58eSDimitry Andricpublic:
48d72607e9SDimitry Andric    shared_timed_mutex();
49d72607e9SDimitry Andric    ~shared_timed_mutex();
504f7ab58eSDimitry Andric
51d72607e9SDimitry Andric    shared_timed_mutex(const shared_timed_mutex&) = delete;
52d72607e9SDimitry Andric    shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
534f7ab58eSDimitry Andric
544f7ab58eSDimitry Andric    // Exclusive ownership
554f7ab58eSDimitry Andric    void lock(); // blocking
564f7ab58eSDimitry Andric    bool try_lock();
574f7ab58eSDimitry Andric    template <class Rep, class Period>
584f7ab58eSDimitry Andric        bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
594f7ab58eSDimitry Andric    template <class Clock, class Duration>
604f7ab58eSDimitry Andric        bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
614f7ab58eSDimitry Andric    void unlock();
624f7ab58eSDimitry Andric
634f7ab58eSDimitry Andric    // Shared ownership
644f7ab58eSDimitry Andric    void lock_shared(); // blocking
654f7ab58eSDimitry Andric    bool try_lock_shared();
664f7ab58eSDimitry Andric    template <class Rep, class Period>
674f7ab58eSDimitry Andric        bool
684f7ab58eSDimitry Andric        try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time);
694f7ab58eSDimitry Andric    template <class Clock, class Duration>
704f7ab58eSDimitry Andric        bool
714f7ab58eSDimitry Andric        try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time);
724f7ab58eSDimitry Andric    void unlock_shared();
734f7ab58eSDimitry Andric};
744f7ab58eSDimitry Andric
754f7ab58eSDimitry Andrictemplate <class Mutex>
764f7ab58eSDimitry Andricclass shared_lock
774f7ab58eSDimitry Andric{
784f7ab58eSDimitry Andricpublic:
794f7ab58eSDimitry Andric    typedef Mutex mutex_type;
804f7ab58eSDimitry Andric
814f7ab58eSDimitry Andric    // Shared locking
824f7ab58eSDimitry Andric    shared_lock() noexcept;
834f7ab58eSDimitry Andric    explicit shared_lock(mutex_type& m); // blocking
844f7ab58eSDimitry Andric    shared_lock(mutex_type& m, defer_lock_t) noexcept;
854f7ab58eSDimitry Andric    shared_lock(mutex_type& m, try_to_lock_t);
864f7ab58eSDimitry Andric    shared_lock(mutex_type& m, adopt_lock_t);
874f7ab58eSDimitry Andric    template <class Clock, class Duration>
884f7ab58eSDimitry Andric        shared_lock(mutex_type& m,
894f7ab58eSDimitry Andric                    const chrono::time_point<Clock, Duration>& abs_time);
904f7ab58eSDimitry Andric    template <class Rep, class Period>
914f7ab58eSDimitry Andric        shared_lock(mutex_type& m,
924f7ab58eSDimitry Andric                    const chrono::duration<Rep, Period>& rel_time);
934f7ab58eSDimitry Andric    ~shared_lock();
944f7ab58eSDimitry Andric
954f7ab58eSDimitry Andric    shared_lock(shared_lock const&) = delete;
964f7ab58eSDimitry Andric    shared_lock& operator=(shared_lock const&) = delete;
974f7ab58eSDimitry Andric
984f7ab58eSDimitry Andric    shared_lock(shared_lock&& u) noexcept;
994f7ab58eSDimitry Andric    shared_lock& operator=(shared_lock&& u) noexcept;
1004f7ab58eSDimitry Andric
1014f7ab58eSDimitry Andric    void lock(); // blocking
1024f7ab58eSDimitry Andric    bool try_lock();
1034f7ab58eSDimitry Andric    template <class Rep, class Period>
1044f7ab58eSDimitry Andric        bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
1054f7ab58eSDimitry Andric    template <class Clock, class Duration>
1064f7ab58eSDimitry Andric        bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
1074f7ab58eSDimitry Andric    void unlock();
1084f7ab58eSDimitry Andric
1094f7ab58eSDimitry Andric    // Setters
1104f7ab58eSDimitry Andric    void swap(shared_lock& u) noexcept;
1114f7ab58eSDimitry Andric    mutex_type* release() noexcept;
1124f7ab58eSDimitry Andric
1134f7ab58eSDimitry Andric    // Getters
1144f7ab58eSDimitry Andric    bool owns_lock() const noexcept;
1154f7ab58eSDimitry Andric    explicit operator bool () const noexcept;
1164f7ab58eSDimitry Andric    mutex_type* mutex() const noexcept;
1174f7ab58eSDimitry Andric};
1184f7ab58eSDimitry Andric
1194f7ab58eSDimitry Andrictemplate <class Mutex>
1204f7ab58eSDimitry Andric    void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
1214f7ab58eSDimitry Andric
1224f7ab58eSDimitry Andric}  // std
1234f7ab58eSDimitry Andric
1244f7ab58eSDimitry Andric*/
1254f7ab58eSDimitry Andric
1264f7ab58eSDimitry Andric#include <__config>
127*b5893f02SDimitry Andric#include <version>
1284f7ab58eSDimitry Andric
129f9448bf3SDimitry Andric_LIBCPP_PUSH_MACROS
130f9448bf3SDimitry Andric#include <__undef_macros>
131f9448bf3SDimitry Andric
132f9448bf3SDimitry Andric
1334ba319b5SDimitry Andric#if _LIBCPP_STD_VER > 11 || defined(_LIBCPP_BUILDING_LIBRARY)
1344f7ab58eSDimitry Andric
1354f7ab58eSDimitry Andric#include <__mutex_base>
1364f7ab58eSDimitry Andric
1374f7ab58eSDimitry Andric#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
1384f7ab58eSDimitry Andric#pragma GCC system_header
1394f7ab58eSDimitry Andric#endif
1404f7ab58eSDimitry Andric
141d72607e9SDimitry Andric#ifdef _LIBCPP_HAS_NO_THREADS
142d72607e9SDimitry Andric#error <shared_mutex> is not supported on this single threaded system
143d72607e9SDimitry Andric#else // !_LIBCPP_HAS_NO_THREADS
144d72607e9SDimitry Andric
1454f7ab58eSDimitry Andric_LIBCPP_BEGIN_NAMESPACE_STD
1464f7ab58eSDimitry Andric
147*b5893f02SDimitry Andricstruct _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("shared_mutex"))
148*b5893f02SDimitry Andric__shared_mutex_base
1494f7ab58eSDimitry Andric{
1504f7ab58eSDimitry Andric    mutex               __mut_;
1514f7ab58eSDimitry Andric    condition_variable  __gate1_;
1524f7ab58eSDimitry Andric    condition_variable  __gate2_;
1534f7ab58eSDimitry Andric    unsigned            __state_;
1544f7ab58eSDimitry Andric
1554f7ab58eSDimitry Andric    static const unsigned __write_entered_ = 1U << (sizeof(unsigned)*__CHAR_BIT__ - 1);
1564f7ab58eSDimitry Andric    static const unsigned __n_readers_ = ~__write_entered_;
157854fa44bSDimitry Andric
158854fa44bSDimitry Andric    __shared_mutex_base();
159854fa44bSDimitry Andric    _LIBCPP_INLINE_VISIBILITY ~__shared_mutex_base() = default;
160854fa44bSDimitry Andric
161854fa44bSDimitry Andric    __shared_mutex_base(const __shared_mutex_base&) = delete;
162854fa44bSDimitry Andric    __shared_mutex_base& operator=(const __shared_mutex_base&) = delete;
163854fa44bSDimitry Andric
164854fa44bSDimitry Andric    // Exclusive ownership
165*b5893f02SDimitry Andric    void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability()); // blocking
166*b5893f02SDimitry Andric    bool try_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_capability(true));
167*b5893f02SDimitry Andric    void unlock() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability());
168854fa44bSDimitry Andric
169854fa44bSDimitry Andric    // Shared ownership
170*b5893f02SDimitry Andric    void lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_shared_capability()); // blocking
171*b5893f02SDimitry Andric    bool try_lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_shared_capability(true));
172*b5893f02SDimitry Andric    void unlock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_shared_capability());
173854fa44bSDimitry Andric
174854fa44bSDimitry Andric//     typedef implementation-defined native_handle_type; // See 30.2.3
175854fa44bSDimitry Andric//     native_handle_type native_handle(); // See 30.2.3
176854fa44bSDimitry Andric};
177854fa44bSDimitry Andric
178854fa44bSDimitry Andric
179854fa44bSDimitry Andric#if _LIBCPP_STD_VER > 14
1800f5676f4SDimitry Andricclass _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_mutex
181854fa44bSDimitry Andric{
182854fa44bSDimitry Andric    __shared_mutex_base __base;
183854fa44bSDimitry Andricpublic:
1840f5676f4SDimitry Andric    _LIBCPP_INLINE_VISIBILITY shared_mutex() : __base() {}
185854fa44bSDimitry Andric    _LIBCPP_INLINE_VISIBILITY ~shared_mutex() = default;
186854fa44bSDimitry Andric
187854fa44bSDimitry Andric    shared_mutex(const shared_mutex&) = delete;
188854fa44bSDimitry Andric    shared_mutex& operator=(const shared_mutex&) = delete;
189854fa44bSDimitry Andric
190854fa44bSDimitry Andric    // Exclusive ownership
191854fa44bSDimitry Andric    _LIBCPP_INLINE_VISIBILITY void lock()     { return __base.lock(); }
192854fa44bSDimitry Andric    _LIBCPP_INLINE_VISIBILITY bool try_lock() { return __base.try_lock(); }
193854fa44bSDimitry Andric    _LIBCPP_INLINE_VISIBILITY void unlock()   { return __base.unlock(); }
194854fa44bSDimitry Andric
195854fa44bSDimitry Andric    // Shared ownership
196854fa44bSDimitry Andric    _LIBCPP_INLINE_VISIBILITY void lock_shared()     { return __base.lock_shared(); }
197854fa44bSDimitry Andric    _LIBCPP_INLINE_VISIBILITY bool try_lock_shared() { return __base.try_lock_shared(); }
198854fa44bSDimitry Andric    _LIBCPP_INLINE_VISIBILITY void unlock_shared()   { return __base.unlock_shared(); }
199854fa44bSDimitry Andric
200854fa44bSDimitry Andric//     typedef __shared_mutex_base::native_handle_type native_handle_type;
201854fa44bSDimitry Andric//     _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() { return __base::unlock_shared(); }
202854fa44bSDimitry Andric};
203854fa44bSDimitry Andric#endif
204854fa44bSDimitry Andric
205854fa44bSDimitry Andric
2060f5676f4SDimitry Andricclass _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_timed_mutex
207854fa44bSDimitry Andric{
208854fa44bSDimitry Andric    __shared_mutex_base __base;
2094f7ab58eSDimitry Andricpublic:
210d72607e9SDimitry Andric    shared_timed_mutex();
211d72607e9SDimitry Andric    _LIBCPP_INLINE_VISIBILITY ~shared_timed_mutex() = default;
2124f7ab58eSDimitry Andric
213d72607e9SDimitry Andric    shared_timed_mutex(const shared_timed_mutex&) = delete;
214d72607e9SDimitry Andric    shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
2154f7ab58eSDimitry Andric
2164f7ab58eSDimitry Andric    // Exclusive ownership
2174f7ab58eSDimitry Andric    void lock();
2184f7ab58eSDimitry Andric    bool try_lock();
2194f7ab58eSDimitry Andric    template <class _Rep, class _Period>
2204f7ab58eSDimitry Andric        _LIBCPP_INLINE_VISIBILITY
2214f7ab58eSDimitry Andric        bool
2224f7ab58eSDimitry Andric        try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
2234f7ab58eSDimitry Andric        {
2244f7ab58eSDimitry Andric            return try_lock_until(chrono::steady_clock::now() + __rel_time);
2254f7ab58eSDimitry Andric        }
2264f7ab58eSDimitry Andric    template <class _Clock, class _Duration>
227540d2a8bSDimitry Andric        _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
2284f7ab58eSDimitry Andric        bool
2294f7ab58eSDimitry Andric        try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
2304f7ab58eSDimitry Andric    void unlock();
2314f7ab58eSDimitry Andric
2324f7ab58eSDimitry Andric    // Shared ownership
2334f7ab58eSDimitry Andric    void lock_shared();
2344f7ab58eSDimitry Andric    bool try_lock_shared();
2354f7ab58eSDimitry Andric    template <class _Rep, class _Period>
2364f7ab58eSDimitry Andric        _LIBCPP_INLINE_VISIBILITY
2374f7ab58eSDimitry Andric        bool
2384f7ab58eSDimitry Andric        try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
2394f7ab58eSDimitry Andric        {
2404f7ab58eSDimitry Andric            return try_lock_shared_until(chrono::steady_clock::now() + __rel_time);
2414f7ab58eSDimitry Andric        }
2424f7ab58eSDimitry Andric    template <class _Clock, class _Duration>
243540d2a8bSDimitry Andric        _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
2444f7ab58eSDimitry Andric        bool
2454f7ab58eSDimitry Andric        try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
2464f7ab58eSDimitry Andric    void unlock_shared();
2474f7ab58eSDimitry Andric};
2484f7ab58eSDimitry Andric
2494f7ab58eSDimitry Andrictemplate <class _Clock, class _Duration>
2504f7ab58eSDimitry Andricbool
251d72607e9SDimitry Andricshared_timed_mutex::try_lock_until(
2524f7ab58eSDimitry Andric                        const chrono::time_point<_Clock, _Duration>& __abs_time)
2534f7ab58eSDimitry Andric{
254854fa44bSDimitry Andric    unique_lock<mutex> __lk(__base.__mut_);
255854fa44bSDimitry Andric    if (__base.__state_ & __base.__write_entered_)
2564f7ab58eSDimitry Andric    {
2574f7ab58eSDimitry Andric        while (true)
2584f7ab58eSDimitry Andric        {
259854fa44bSDimitry Andric            cv_status __status = __base.__gate1_.wait_until(__lk, __abs_time);
260854fa44bSDimitry Andric            if ((__base.__state_ & __base.__write_entered_) == 0)
2614f7ab58eSDimitry Andric                break;
2624f7ab58eSDimitry Andric            if (__status == cv_status::timeout)
2634f7ab58eSDimitry Andric                return false;
2644f7ab58eSDimitry Andric        }
2654f7ab58eSDimitry Andric    }
266854fa44bSDimitry Andric    __base.__state_ |= __base.__write_entered_;
267854fa44bSDimitry Andric    if (__base.__state_ & __base.__n_readers_)
2684f7ab58eSDimitry Andric    {
2694f7ab58eSDimitry Andric        while (true)
2704f7ab58eSDimitry Andric        {
271854fa44bSDimitry Andric            cv_status __status = __base.__gate2_.wait_until(__lk, __abs_time);
272854fa44bSDimitry Andric            if ((__base.__state_ & __base.__n_readers_) == 0)
2734f7ab58eSDimitry Andric                break;
2744f7ab58eSDimitry Andric            if (__status == cv_status::timeout)
2754f7ab58eSDimitry Andric            {
276854fa44bSDimitry Andric                __base.__state_ &= ~__base.__write_entered_;
277854fa44bSDimitry Andric                __base.__gate1_.notify_all();
2784f7ab58eSDimitry Andric                return false;
2794f7ab58eSDimitry Andric            }
2804f7ab58eSDimitry Andric        }
2814f7ab58eSDimitry Andric    }
2824f7ab58eSDimitry Andric    return true;
2834f7ab58eSDimitry Andric}
2844f7ab58eSDimitry Andric
2854f7ab58eSDimitry Andrictemplate <class _Clock, class _Duration>
2864f7ab58eSDimitry Andricbool
287d72607e9SDimitry Andricshared_timed_mutex::try_lock_shared_until(
2884f7ab58eSDimitry Andric                        const chrono::time_point<_Clock, _Duration>& __abs_time)
2894f7ab58eSDimitry Andric{
290854fa44bSDimitry Andric    unique_lock<mutex> __lk(__base.__mut_);
291854fa44bSDimitry Andric    if ((__base.__state_ & __base.__write_entered_) || (__base.__state_ & __base.__n_readers_) == __base.__n_readers_)
2924f7ab58eSDimitry Andric    {
2934f7ab58eSDimitry Andric        while (true)
2944f7ab58eSDimitry Andric        {
295854fa44bSDimitry Andric            cv_status status = __base.__gate1_.wait_until(__lk, __abs_time);
296854fa44bSDimitry Andric            if ((__base.__state_ & __base.__write_entered_) == 0 &&
297854fa44bSDimitry Andric                                       (__base.__state_ & __base.__n_readers_) < __base.__n_readers_)
2984f7ab58eSDimitry Andric                break;
2994f7ab58eSDimitry Andric            if (status == cv_status::timeout)
3004f7ab58eSDimitry Andric                return false;
3014f7ab58eSDimitry Andric        }
3024f7ab58eSDimitry Andric    }
303854fa44bSDimitry Andric    unsigned __num_readers = (__base.__state_ & __base.__n_readers_) + 1;
304854fa44bSDimitry Andric    __base.__state_ &= ~__base.__n_readers_;
305854fa44bSDimitry Andric    __base.__state_ |= __num_readers;
3064f7ab58eSDimitry Andric    return true;
3074f7ab58eSDimitry Andric}
3084f7ab58eSDimitry Andric
3094f7ab58eSDimitry Andrictemplate <class _Mutex>
3104f7ab58eSDimitry Andricclass shared_lock
3114f7ab58eSDimitry Andric{
3124f7ab58eSDimitry Andricpublic:
3134f7ab58eSDimitry Andric    typedef _Mutex mutex_type;
3144f7ab58eSDimitry Andric
3154f7ab58eSDimitry Andricprivate:
3164f7ab58eSDimitry Andric    mutex_type* __m_;
3174f7ab58eSDimitry Andric    bool __owns_;
3184f7ab58eSDimitry Andric
3194f7ab58eSDimitry Andricpublic:
3204f7ab58eSDimitry Andric    _LIBCPP_INLINE_VISIBILITY
321d72607e9SDimitry Andric    shared_lock() _NOEXCEPT
3224f7ab58eSDimitry Andric        : __m_(nullptr),
3234f7ab58eSDimitry Andric          __owns_(false)
3244f7ab58eSDimitry Andric        {}
3254f7ab58eSDimitry Andric
3264f7ab58eSDimitry Andric    _LIBCPP_INLINE_VISIBILITY
3274f7ab58eSDimitry Andric    explicit shared_lock(mutex_type& __m)
3287c82a1ecSDimitry Andric        : __m_(_VSTD::addressof(__m)),
3294f7ab58eSDimitry Andric          __owns_(true)
3304f7ab58eSDimitry Andric        {__m_->lock_shared();}
3314f7ab58eSDimitry Andric
3324f7ab58eSDimitry Andric    _LIBCPP_INLINE_VISIBILITY
333d72607e9SDimitry Andric    shared_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
3347c82a1ecSDimitry Andric        : __m_(_VSTD::addressof(__m)),
3354f7ab58eSDimitry Andric          __owns_(false)
3364f7ab58eSDimitry Andric        {}
3374f7ab58eSDimitry Andric
3384f7ab58eSDimitry Andric    _LIBCPP_INLINE_VISIBILITY
3394f7ab58eSDimitry Andric    shared_lock(mutex_type& __m, try_to_lock_t)
3407c82a1ecSDimitry Andric        : __m_(_VSTD::addressof(__m)),
3414f7ab58eSDimitry Andric          __owns_(__m.try_lock_shared())
3424f7ab58eSDimitry Andric        {}
3434f7ab58eSDimitry Andric
3444f7ab58eSDimitry Andric    _LIBCPP_INLINE_VISIBILITY
3454f7ab58eSDimitry Andric    shared_lock(mutex_type& __m, adopt_lock_t)
3467c82a1ecSDimitry Andric        : __m_(_VSTD::addressof(__m)),
3474f7ab58eSDimitry Andric          __owns_(true)
3484f7ab58eSDimitry Andric        {}
3494f7ab58eSDimitry Andric
3504f7ab58eSDimitry Andric    template <class _Clock, class _Duration>
3514f7ab58eSDimitry Andric        _LIBCPP_INLINE_VISIBILITY
3524f7ab58eSDimitry Andric        shared_lock(mutex_type& __m,
3534f7ab58eSDimitry Andric                    const chrono::time_point<_Clock, _Duration>& __abs_time)
3547c82a1ecSDimitry Andric            : __m_(_VSTD::addressof(__m)),
3554f7ab58eSDimitry Andric              __owns_(__m.try_lock_shared_until(__abs_time))
3564f7ab58eSDimitry Andric            {}
3574f7ab58eSDimitry Andric
3584f7ab58eSDimitry Andric    template <class _Rep, class _Period>
3594f7ab58eSDimitry Andric        _LIBCPP_INLINE_VISIBILITY
3604f7ab58eSDimitry Andric        shared_lock(mutex_type& __m,
3614f7ab58eSDimitry Andric                    const chrono::duration<_Rep, _Period>& __rel_time)
3627c82a1ecSDimitry Andric            : __m_(_VSTD::addressof(__m)),
3634f7ab58eSDimitry Andric              __owns_(__m.try_lock_shared_for(__rel_time))
3644f7ab58eSDimitry Andric            {}
3654f7ab58eSDimitry Andric
3664f7ab58eSDimitry Andric    _LIBCPP_INLINE_VISIBILITY
3674f7ab58eSDimitry Andric    ~shared_lock()
3684f7ab58eSDimitry Andric    {
3694f7ab58eSDimitry Andric        if (__owns_)
3704f7ab58eSDimitry Andric            __m_->unlock_shared();
3714f7ab58eSDimitry Andric    }
3724f7ab58eSDimitry Andric
3734f7ab58eSDimitry Andric    shared_lock(shared_lock const&) = delete;
3744f7ab58eSDimitry Andric    shared_lock& operator=(shared_lock const&) = delete;
3754f7ab58eSDimitry Andric
3764f7ab58eSDimitry Andric    _LIBCPP_INLINE_VISIBILITY
377d72607e9SDimitry Andric    shared_lock(shared_lock&& __u) _NOEXCEPT
3784f7ab58eSDimitry Andric        : __m_(__u.__m_),
3794f7ab58eSDimitry Andric          __owns_(__u.__owns_)
3804f7ab58eSDimitry Andric        {
3814f7ab58eSDimitry Andric            __u.__m_ = nullptr;
3824f7ab58eSDimitry Andric            __u.__owns_ = false;
3834f7ab58eSDimitry Andric        }
3844f7ab58eSDimitry Andric
3854f7ab58eSDimitry Andric    _LIBCPP_INLINE_VISIBILITY
386d72607e9SDimitry Andric    shared_lock& operator=(shared_lock&& __u) _NOEXCEPT
3874f7ab58eSDimitry Andric    {
3884f7ab58eSDimitry Andric        if (__owns_)
3894f7ab58eSDimitry Andric            __m_->unlock_shared();
3904f7ab58eSDimitry Andric        __m_ = nullptr;
3914f7ab58eSDimitry Andric        __owns_ = false;
3924f7ab58eSDimitry Andric        __m_ = __u.__m_;
3934f7ab58eSDimitry Andric        __owns_ = __u.__owns_;
3944f7ab58eSDimitry Andric        __u.__m_ = nullptr;
3954f7ab58eSDimitry Andric        __u.__owns_ = false;
3964f7ab58eSDimitry Andric        return *this;
3974f7ab58eSDimitry Andric    }
3984f7ab58eSDimitry Andric
3994f7ab58eSDimitry Andric    void lock();
4004f7ab58eSDimitry Andric    bool try_lock();
4014f7ab58eSDimitry Andric    template <class Rep, class Period>
4024f7ab58eSDimitry Andric        bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
4034f7ab58eSDimitry Andric    template <class Clock, class Duration>
4044f7ab58eSDimitry Andric        bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
4054f7ab58eSDimitry Andric    void unlock();
4064f7ab58eSDimitry Andric
4074f7ab58eSDimitry Andric    // Setters
4084f7ab58eSDimitry Andric    _LIBCPP_INLINE_VISIBILITY
409d72607e9SDimitry Andric    void swap(shared_lock& __u) _NOEXCEPT
4104f7ab58eSDimitry Andric    {
4114f7ab58eSDimitry Andric        _VSTD::swap(__m_, __u.__m_);
4124f7ab58eSDimitry Andric        _VSTD::swap(__owns_, __u.__owns_);
4134f7ab58eSDimitry Andric    }
4144f7ab58eSDimitry Andric
4154f7ab58eSDimitry Andric    _LIBCPP_INLINE_VISIBILITY
416d72607e9SDimitry Andric    mutex_type* release() _NOEXCEPT
4174f7ab58eSDimitry Andric    {
4184f7ab58eSDimitry Andric        mutex_type* __m = __m_;
4194f7ab58eSDimitry Andric        __m_ = nullptr;
4204f7ab58eSDimitry Andric        __owns_ = false;
4214f7ab58eSDimitry Andric        return __m;
4224f7ab58eSDimitry Andric    }
4234f7ab58eSDimitry Andric
4244f7ab58eSDimitry Andric    // Getters
4254f7ab58eSDimitry Andric    _LIBCPP_INLINE_VISIBILITY
426d72607e9SDimitry Andric    bool owns_lock() const _NOEXCEPT {return __owns_;}
4274f7ab58eSDimitry Andric
4284f7ab58eSDimitry Andric    _LIBCPP_INLINE_VISIBILITY
429d72607e9SDimitry Andric    explicit operator bool () const _NOEXCEPT {return __owns_;}
4304f7ab58eSDimitry Andric
4314f7ab58eSDimitry Andric    _LIBCPP_INLINE_VISIBILITY
432d72607e9SDimitry Andric    mutex_type* mutex() const _NOEXCEPT {return __m_;}
4334f7ab58eSDimitry Andric};
4344f7ab58eSDimitry Andric
4354f7ab58eSDimitry Andrictemplate <class _Mutex>
4364f7ab58eSDimitry Andricvoid
4374f7ab58eSDimitry Andricshared_lock<_Mutex>::lock()
4384f7ab58eSDimitry Andric{
4394f7ab58eSDimitry Andric    if (__m_ == nullptr)
4404f7ab58eSDimitry Andric        __throw_system_error(EPERM, "shared_lock::lock: references null mutex");
4414f7ab58eSDimitry Andric    if (__owns_)
4424f7ab58eSDimitry Andric        __throw_system_error(EDEADLK, "shared_lock::lock: already locked");
4434f7ab58eSDimitry Andric    __m_->lock_shared();
4444f7ab58eSDimitry Andric    __owns_ = true;
4454f7ab58eSDimitry Andric}
4464f7ab58eSDimitry Andric
4474f7ab58eSDimitry Andrictemplate <class _Mutex>
4484f7ab58eSDimitry Andricbool
4494f7ab58eSDimitry Andricshared_lock<_Mutex>::try_lock()
4504f7ab58eSDimitry Andric{
4514f7ab58eSDimitry Andric    if (__m_ == nullptr)
4524f7ab58eSDimitry Andric        __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex");
4534f7ab58eSDimitry Andric    if (__owns_)
4544f7ab58eSDimitry Andric        __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked");
4554f7ab58eSDimitry Andric    __owns_ = __m_->try_lock_shared();
4564f7ab58eSDimitry Andric    return __owns_;
4574f7ab58eSDimitry Andric}
4584f7ab58eSDimitry Andric
4594f7ab58eSDimitry Andrictemplate <class _Mutex>
4604f7ab58eSDimitry Andrictemplate <class _Rep, class _Period>
4614f7ab58eSDimitry Andricbool
4624f7ab58eSDimitry Andricshared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
4634f7ab58eSDimitry Andric{
4644f7ab58eSDimitry Andric    if (__m_ == nullptr)
4654f7ab58eSDimitry Andric        __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex");
4664f7ab58eSDimitry Andric    if (__owns_)
4674f7ab58eSDimitry Andric        __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked");
4684f7ab58eSDimitry Andric    __owns_ = __m_->try_lock_shared_for(__d);
4694f7ab58eSDimitry Andric    return __owns_;
4704f7ab58eSDimitry Andric}
4714f7ab58eSDimitry Andric
4724f7ab58eSDimitry Andrictemplate <class _Mutex>
4734f7ab58eSDimitry Andrictemplate <class _Clock, class _Duration>
4744f7ab58eSDimitry Andricbool
4754f7ab58eSDimitry Andricshared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
4764f7ab58eSDimitry Andric{
4774f7ab58eSDimitry Andric    if (__m_ == nullptr)
4784f7ab58eSDimitry Andric        __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex");
4794f7ab58eSDimitry Andric    if (__owns_)
4804f7ab58eSDimitry Andric        __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked");
4814f7ab58eSDimitry Andric    __owns_ = __m_->try_lock_shared_until(__t);
4824f7ab58eSDimitry Andric    return __owns_;
4834f7ab58eSDimitry Andric}
4844f7ab58eSDimitry Andric
4854f7ab58eSDimitry Andrictemplate <class _Mutex>
4864f7ab58eSDimitry Andricvoid
4874f7ab58eSDimitry Andricshared_lock<_Mutex>::unlock()
4884f7ab58eSDimitry Andric{
4894f7ab58eSDimitry Andric    if (!__owns_)
4904f7ab58eSDimitry Andric        __throw_system_error(EPERM, "shared_lock::unlock: not locked");
4914f7ab58eSDimitry Andric    __m_->unlock_shared();
4924f7ab58eSDimitry Andric    __owns_ = false;
4934f7ab58eSDimitry Andric}
4944f7ab58eSDimitry Andric
4954f7ab58eSDimitry Andrictemplate <class _Mutex>
4964f7ab58eSDimitry Andricinline _LIBCPP_INLINE_VISIBILITY
4974f7ab58eSDimitry Andricvoid
498d72607e9SDimitry Andricswap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) _NOEXCEPT
4994f7ab58eSDimitry Andric    {__x.swap(__y);}
5004f7ab58eSDimitry Andric
5014f7ab58eSDimitry Andric_LIBCPP_END_NAMESPACE_STD
5024f7ab58eSDimitry Andric
503d72607e9SDimitry Andric#endif  // !_LIBCPP_HAS_NO_THREADS
504d72607e9SDimitry Andric
5054f7ab58eSDimitry Andric#endif  // _LIBCPP_STD_VER > 11
5064f7ab58eSDimitry Andric
507f9448bf3SDimitry Andric_LIBCPP_POP_MACROS
508f9448bf3SDimitry Andric
5094f7ab58eSDimitry Andric#endif  // _LIBCPP_SHARED_MUTEX
510