xref: /freebsd/contrib/llvm-project/libcxx/include/shared_mutex (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
10b57cec5SDimitry Andric// -*- C++ -*-
2*349cc55cSDimitry 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
125e8d8bef9SDimitry Andric#include <__availability>
126fe6060f1SDimitry Andric#include <__config>
1270b57cec5SDimitry Andric#include <version>
1280b57cec5SDimitry Andric
1290b57cec5SDimitry Andric_LIBCPP_PUSH_MACROS
1300b57cec5SDimitry Andric#include <__undef_macros>
1310b57cec5SDimitry Andric
1320b57cec5SDimitry Andric
1330b57cec5SDimitry Andric#if _LIBCPP_STD_VER > 11 || defined(_LIBCPP_BUILDING_LIBRARY)
1340b57cec5SDimitry Andric
1350b57cec5SDimitry Andric#include <__mutex_base>
1360b57cec5SDimitry Andric
1370b57cec5SDimitry Andric#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
1380b57cec5SDimitry Andric#pragma GCC system_header
1390b57cec5SDimitry Andric#endif
1400b57cec5SDimitry Andric
1410b57cec5SDimitry Andric#ifdef _LIBCPP_HAS_NO_THREADS
1420b57cec5SDimitry Andric#error <shared_mutex> is not supported on this single threaded system
1430b57cec5SDimitry Andric#else // !_LIBCPP_HAS_NO_THREADS
1440b57cec5SDimitry Andric
1450b57cec5SDimitry Andric_LIBCPP_BEGIN_NAMESPACE_STD
1460b57cec5SDimitry Andric
1470b57cec5SDimitry Andricstruct _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("shared_mutex"))
1480b57cec5SDimitry Andric__shared_mutex_base
1490b57cec5SDimitry Andric{
1500b57cec5SDimitry Andric    mutex               __mut_;
1510b57cec5SDimitry Andric    condition_variable  __gate1_;
1520b57cec5SDimitry Andric    condition_variable  __gate2_;
1530b57cec5SDimitry Andric    unsigned            __state_;
1540b57cec5SDimitry Andric
1550b57cec5SDimitry Andric    static const unsigned __write_entered_ = 1U << (sizeof(unsigned)*__CHAR_BIT__ - 1);
1560b57cec5SDimitry Andric    static const unsigned __n_readers_ = ~__write_entered_;
1570b57cec5SDimitry Andric
1580b57cec5SDimitry Andric    __shared_mutex_base();
1590b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY ~__shared_mutex_base() = default;
1600b57cec5SDimitry Andric
1610b57cec5SDimitry Andric    __shared_mutex_base(const __shared_mutex_base&) = delete;
1620b57cec5SDimitry Andric    __shared_mutex_base& operator=(const __shared_mutex_base&) = delete;
1630b57cec5SDimitry Andric
1640b57cec5SDimitry Andric    // Exclusive ownership
1650b57cec5SDimitry Andric    void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability()); // blocking
1660b57cec5SDimitry Andric    bool try_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_capability(true));
1670b57cec5SDimitry Andric    void unlock() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability());
1680b57cec5SDimitry Andric
1690b57cec5SDimitry Andric    // Shared ownership
1700b57cec5SDimitry Andric    void lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_shared_capability()); // blocking
1710b57cec5SDimitry Andric    bool try_lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_shared_capability(true));
1720b57cec5SDimitry Andric    void unlock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_shared_capability());
1730b57cec5SDimitry Andric
1740b57cec5SDimitry Andric//     typedef implementation-defined native_handle_type; // See 30.2.3
1750b57cec5SDimitry Andric//     native_handle_type native_handle(); // See 30.2.3
1760b57cec5SDimitry Andric};
1770b57cec5SDimitry Andric
1780b57cec5SDimitry Andric
1790b57cec5SDimitry Andric#if _LIBCPP_STD_VER > 14
1800b57cec5SDimitry Andricclass _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_mutex
1810b57cec5SDimitry Andric{
1820b57cec5SDimitry Andric    __shared_mutex_base __base;
1830b57cec5SDimitry Andricpublic:
1840b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY shared_mutex() : __base() {}
1850b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY ~shared_mutex() = default;
1860b57cec5SDimitry Andric
1870b57cec5SDimitry Andric    shared_mutex(const shared_mutex&) = delete;
1880b57cec5SDimitry Andric    shared_mutex& operator=(const shared_mutex&) = delete;
1890b57cec5SDimitry Andric
1900b57cec5SDimitry Andric    // Exclusive ownership
1910b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY void lock()     { return __base.lock(); }
1920b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY bool try_lock() { return __base.try_lock(); }
1930b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY void unlock()   { return __base.unlock(); }
1940b57cec5SDimitry Andric
1950b57cec5SDimitry Andric    // Shared ownership
1960b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY void lock_shared()     { return __base.lock_shared(); }
1970b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY bool try_lock_shared() { return __base.try_lock_shared(); }
1980b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY void unlock_shared()   { return __base.unlock_shared(); }
1990b57cec5SDimitry Andric
2000b57cec5SDimitry Andric//     typedef __shared_mutex_base::native_handle_type native_handle_type;
2010b57cec5SDimitry Andric//     _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() { return __base::unlock_shared(); }
2020b57cec5SDimitry Andric};
2030b57cec5SDimitry Andric#endif
2040b57cec5SDimitry Andric
2050b57cec5SDimitry Andric
2060b57cec5SDimitry Andricclass _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_timed_mutex
2070b57cec5SDimitry Andric{
2080b57cec5SDimitry Andric    __shared_mutex_base __base;
2090b57cec5SDimitry Andricpublic:
2100b57cec5SDimitry Andric    shared_timed_mutex();
2110b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY ~shared_timed_mutex() = default;
2120b57cec5SDimitry Andric
2130b57cec5SDimitry Andric    shared_timed_mutex(const shared_timed_mutex&) = delete;
2140b57cec5SDimitry Andric    shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
2150b57cec5SDimitry Andric
2160b57cec5SDimitry Andric    // Exclusive ownership
2170b57cec5SDimitry Andric    void lock();
2180b57cec5SDimitry Andric    bool try_lock();
2190b57cec5SDimitry Andric    template <class _Rep, class _Period>
2200b57cec5SDimitry Andric        _LIBCPP_INLINE_VISIBILITY
2210b57cec5SDimitry Andric        bool
2220b57cec5SDimitry Andric        try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
2230b57cec5SDimitry Andric        {
2240b57cec5SDimitry Andric            return try_lock_until(chrono::steady_clock::now() + __rel_time);
2250b57cec5SDimitry Andric        }
2260b57cec5SDimitry Andric    template <class _Clock, class _Duration>
2270b57cec5SDimitry Andric        _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
2280b57cec5SDimitry Andric        bool
2290b57cec5SDimitry Andric        try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
2300b57cec5SDimitry Andric    void unlock();
2310b57cec5SDimitry Andric
2320b57cec5SDimitry Andric    // Shared ownership
2330b57cec5SDimitry Andric    void lock_shared();
2340b57cec5SDimitry Andric    bool try_lock_shared();
2350b57cec5SDimitry Andric    template <class _Rep, class _Period>
2360b57cec5SDimitry Andric        _LIBCPP_INLINE_VISIBILITY
2370b57cec5SDimitry Andric        bool
2380b57cec5SDimitry Andric        try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
2390b57cec5SDimitry Andric        {
2400b57cec5SDimitry Andric            return try_lock_shared_until(chrono::steady_clock::now() + __rel_time);
2410b57cec5SDimitry Andric        }
2420b57cec5SDimitry Andric    template <class _Clock, class _Duration>
2430b57cec5SDimitry Andric        _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
2440b57cec5SDimitry Andric        bool
2450b57cec5SDimitry Andric        try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
2460b57cec5SDimitry Andric    void unlock_shared();
2470b57cec5SDimitry Andric};
2480b57cec5SDimitry Andric
2490b57cec5SDimitry Andrictemplate <class _Clock, class _Duration>
2500b57cec5SDimitry Andricbool
2510b57cec5SDimitry Andricshared_timed_mutex::try_lock_until(
2520b57cec5SDimitry Andric                        const chrono::time_point<_Clock, _Duration>& __abs_time)
2530b57cec5SDimitry Andric{
2540b57cec5SDimitry Andric    unique_lock<mutex> __lk(__base.__mut_);
2550b57cec5SDimitry Andric    if (__base.__state_ & __base.__write_entered_)
2560b57cec5SDimitry Andric    {
2570b57cec5SDimitry Andric        while (true)
2580b57cec5SDimitry Andric        {
2590b57cec5SDimitry Andric            cv_status __status = __base.__gate1_.wait_until(__lk, __abs_time);
2600b57cec5SDimitry Andric            if ((__base.__state_ & __base.__write_entered_) == 0)
2610b57cec5SDimitry Andric                break;
2620b57cec5SDimitry Andric            if (__status == cv_status::timeout)
2630b57cec5SDimitry Andric                return false;
2640b57cec5SDimitry Andric        }
2650b57cec5SDimitry Andric    }
2660b57cec5SDimitry Andric    __base.__state_ |= __base.__write_entered_;
2670b57cec5SDimitry Andric    if (__base.__state_ & __base.__n_readers_)
2680b57cec5SDimitry Andric    {
2690b57cec5SDimitry Andric        while (true)
2700b57cec5SDimitry Andric        {
2710b57cec5SDimitry Andric            cv_status __status = __base.__gate2_.wait_until(__lk, __abs_time);
2720b57cec5SDimitry Andric            if ((__base.__state_ & __base.__n_readers_) == 0)
2730b57cec5SDimitry Andric                break;
2740b57cec5SDimitry Andric            if (__status == cv_status::timeout)
2750b57cec5SDimitry Andric            {
2760b57cec5SDimitry Andric                __base.__state_ &= ~__base.__write_entered_;
2770b57cec5SDimitry Andric                __base.__gate1_.notify_all();
2780b57cec5SDimitry Andric                return false;
2790b57cec5SDimitry Andric            }
2800b57cec5SDimitry Andric        }
2810b57cec5SDimitry Andric    }
2820b57cec5SDimitry Andric    return true;
2830b57cec5SDimitry Andric}
2840b57cec5SDimitry Andric
2850b57cec5SDimitry Andrictemplate <class _Clock, class _Duration>
2860b57cec5SDimitry Andricbool
2870b57cec5SDimitry Andricshared_timed_mutex::try_lock_shared_until(
2880b57cec5SDimitry Andric                        const chrono::time_point<_Clock, _Duration>& __abs_time)
2890b57cec5SDimitry Andric{
2900b57cec5SDimitry Andric    unique_lock<mutex> __lk(__base.__mut_);
2910b57cec5SDimitry Andric    if ((__base.__state_ & __base.__write_entered_) || (__base.__state_ & __base.__n_readers_) == __base.__n_readers_)
2920b57cec5SDimitry Andric    {
2930b57cec5SDimitry Andric        while (true)
2940b57cec5SDimitry Andric        {
2950b57cec5SDimitry Andric            cv_status status = __base.__gate1_.wait_until(__lk, __abs_time);
2960b57cec5SDimitry Andric            if ((__base.__state_ & __base.__write_entered_) == 0 &&
2970b57cec5SDimitry Andric                                       (__base.__state_ & __base.__n_readers_) < __base.__n_readers_)
2980b57cec5SDimitry Andric                break;
2990b57cec5SDimitry Andric            if (status == cv_status::timeout)
3000b57cec5SDimitry Andric                return false;
3010b57cec5SDimitry Andric        }
3020b57cec5SDimitry Andric    }
3030b57cec5SDimitry Andric    unsigned __num_readers = (__base.__state_ & __base.__n_readers_) + 1;
3040b57cec5SDimitry Andric    __base.__state_ &= ~__base.__n_readers_;
3050b57cec5SDimitry Andric    __base.__state_ |= __num_readers;
3060b57cec5SDimitry Andric    return true;
3070b57cec5SDimitry Andric}
3080b57cec5SDimitry Andric
3090b57cec5SDimitry Andrictemplate <class _Mutex>
3100b57cec5SDimitry Andricclass shared_lock
3110b57cec5SDimitry Andric{
3120b57cec5SDimitry Andricpublic:
3130b57cec5SDimitry Andric    typedef _Mutex mutex_type;
3140b57cec5SDimitry Andric
3150b57cec5SDimitry Andricprivate:
3160b57cec5SDimitry Andric    mutex_type* __m_;
3170b57cec5SDimitry Andric    bool __owns_;
3180b57cec5SDimitry Andric
3190b57cec5SDimitry Andricpublic:
3200b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
3210b57cec5SDimitry Andric    shared_lock() _NOEXCEPT
3220b57cec5SDimitry Andric        : __m_(nullptr),
3230b57cec5SDimitry Andric          __owns_(false)
3240b57cec5SDimitry Andric        {}
3250b57cec5SDimitry Andric
3260b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
3270b57cec5SDimitry Andric    explicit shared_lock(mutex_type& __m)
3280b57cec5SDimitry Andric        : __m_(_VSTD::addressof(__m)),
3290b57cec5SDimitry Andric          __owns_(true)
3300b57cec5SDimitry Andric        {__m_->lock_shared();}
3310b57cec5SDimitry Andric
3320b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
3330b57cec5SDimitry Andric    shared_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
3340b57cec5SDimitry Andric        : __m_(_VSTD::addressof(__m)),
3350b57cec5SDimitry Andric          __owns_(false)
3360b57cec5SDimitry Andric        {}
3370b57cec5SDimitry Andric
3380b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
3390b57cec5SDimitry Andric    shared_lock(mutex_type& __m, try_to_lock_t)
3400b57cec5SDimitry Andric        : __m_(_VSTD::addressof(__m)),
3410b57cec5SDimitry Andric          __owns_(__m.try_lock_shared())
3420b57cec5SDimitry Andric        {}
3430b57cec5SDimitry Andric
3440b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
3450b57cec5SDimitry Andric    shared_lock(mutex_type& __m, adopt_lock_t)
3460b57cec5SDimitry Andric        : __m_(_VSTD::addressof(__m)),
3470b57cec5SDimitry Andric          __owns_(true)
3480b57cec5SDimitry Andric        {}
3490b57cec5SDimitry Andric
3500b57cec5SDimitry Andric    template <class _Clock, class _Duration>
3510b57cec5SDimitry Andric        _LIBCPP_INLINE_VISIBILITY
3520b57cec5SDimitry Andric        shared_lock(mutex_type& __m,
3530b57cec5SDimitry Andric                    const chrono::time_point<_Clock, _Duration>& __abs_time)
3540b57cec5SDimitry Andric            : __m_(_VSTD::addressof(__m)),
3550b57cec5SDimitry Andric              __owns_(__m.try_lock_shared_until(__abs_time))
3560b57cec5SDimitry Andric            {}
3570b57cec5SDimitry Andric
3580b57cec5SDimitry Andric    template <class _Rep, class _Period>
3590b57cec5SDimitry Andric        _LIBCPP_INLINE_VISIBILITY
3600b57cec5SDimitry Andric        shared_lock(mutex_type& __m,
3610b57cec5SDimitry Andric                    const chrono::duration<_Rep, _Period>& __rel_time)
3620b57cec5SDimitry Andric            : __m_(_VSTD::addressof(__m)),
3630b57cec5SDimitry Andric              __owns_(__m.try_lock_shared_for(__rel_time))
3640b57cec5SDimitry Andric            {}
3650b57cec5SDimitry Andric
3660b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
3670b57cec5SDimitry Andric    ~shared_lock()
3680b57cec5SDimitry Andric    {
3690b57cec5SDimitry Andric        if (__owns_)
3700b57cec5SDimitry Andric            __m_->unlock_shared();
3710b57cec5SDimitry Andric    }
3720b57cec5SDimitry Andric
3730b57cec5SDimitry Andric    shared_lock(shared_lock const&) = delete;
3740b57cec5SDimitry Andric    shared_lock& operator=(shared_lock const&) = delete;
3750b57cec5SDimitry Andric
3760b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
3770b57cec5SDimitry Andric    shared_lock(shared_lock&& __u) _NOEXCEPT
3780b57cec5SDimitry Andric        : __m_(__u.__m_),
3790b57cec5SDimitry Andric          __owns_(__u.__owns_)
3800b57cec5SDimitry Andric        {
3810b57cec5SDimitry Andric            __u.__m_ = nullptr;
3820b57cec5SDimitry Andric            __u.__owns_ = false;
3830b57cec5SDimitry Andric        }
3840b57cec5SDimitry Andric
3850b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
3860b57cec5SDimitry Andric    shared_lock& operator=(shared_lock&& __u) _NOEXCEPT
3870b57cec5SDimitry Andric    {
3880b57cec5SDimitry Andric        if (__owns_)
3890b57cec5SDimitry Andric            __m_->unlock_shared();
3900b57cec5SDimitry Andric        __m_ = nullptr;
3910b57cec5SDimitry Andric        __owns_ = false;
3920b57cec5SDimitry Andric        __m_ = __u.__m_;
3930b57cec5SDimitry Andric        __owns_ = __u.__owns_;
3940b57cec5SDimitry Andric        __u.__m_ = nullptr;
3950b57cec5SDimitry Andric        __u.__owns_ = false;
3960b57cec5SDimitry Andric        return *this;
3970b57cec5SDimitry Andric    }
3980b57cec5SDimitry Andric
3990b57cec5SDimitry Andric    void lock();
4000b57cec5SDimitry Andric    bool try_lock();
4010b57cec5SDimitry Andric    template <class Rep, class Period>
4020b57cec5SDimitry Andric        bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
4030b57cec5SDimitry Andric    template <class Clock, class Duration>
4040b57cec5SDimitry Andric        bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
4050b57cec5SDimitry Andric    void unlock();
4060b57cec5SDimitry Andric
4070b57cec5SDimitry Andric    // Setters
4080b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
4090b57cec5SDimitry Andric    void swap(shared_lock& __u) _NOEXCEPT
4100b57cec5SDimitry Andric    {
4110b57cec5SDimitry Andric        _VSTD::swap(__m_, __u.__m_);
4120b57cec5SDimitry Andric        _VSTD::swap(__owns_, __u.__owns_);
4130b57cec5SDimitry Andric    }
4140b57cec5SDimitry Andric
4150b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
4160b57cec5SDimitry Andric    mutex_type* release() _NOEXCEPT
4170b57cec5SDimitry Andric    {
4180b57cec5SDimitry Andric        mutex_type* __m = __m_;
4190b57cec5SDimitry Andric        __m_ = nullptr;
4200b57cec5SDimitry Andric        __owns_ = false;
4210b57cec5SDimitry Andric        return __m;
4220b57cec5SDimitry Andric    }
4230b57cec5SDimitry Andric
4240b57cec5SDimitry Andric    // Getters
4250b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
4260b57cec5SDimitry Andric    bool owns_lock() const _NOEXCEPT {return __owns_;}
4270b57cec5SDimitry Andric
4280b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
4290b57cec5SDimitry Andric    explicit operator bool () const _NOEXCEPT {return __owns_;}
4300b57cec5SDimitry Andric
4310b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
4320b57cec5SDimitry Andric    mutex_type* mutex() const _NOEXCEPT {return __m_;}
4330b57cec5SDimitry Andric};
4340b57cec5SDimitry Andric
4350b57cec5SDimitry Andrictemplate <class _Mutex>
4360b57cec5SDimitry Andricvoid
4370b57cec5SDimitry Andricshared_lock<_Mutex>::lock()
4380b57cec5SDimitry Andric{
4390b57cec5SDimitry Andric    if (__m_ == nullptr)
4400b57cec5SDimitry Andric        __throw_system_error(EPERM, "shared_lock::lock: references null mutex");
4410b57cec5SDimitry Andric    if (__owns_)
4420b57cec5SDimitry Andric        __throw_system_error(EDEADLK, "shared_lock::lock: already locked");
4430b57cec5SDimitry Andric    __m_->lock_shared();
4440b57cec5SDimitry Andric    __owns_ = true;
4450b57cec5SDimitry Andric}
4460b57cec5SDimitry Andric
4470b57cec5SDimitry Andrictemplate <class _Mutex>
4480b57cec5SDimitry Andricbool
4490b57cec5SDimitry Andricshared_lock<_Mutex>::try_lock()
4500b57cec5SDimitry Andric{
4510b57cec5SDimitry Andric    if (__m_ == nullptr)
4520b57cec5SDimitry Andric        __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex");
4530b57cec5SDimitry Andric    if (__owns_)
4540b57cec5SDimitry Andric        __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked");
4550b57cec5SDimitry Andric    __owns_ = __m_->try_lock_shared();
4560b57cec5SDimitry Andric    return __owns_;
4570b57cec5SDimitry Andric}
4580b57cec5SDimitry Andric
4590b57cec5SDimitry Andrictemplate <class _Mutex>
4600b57cec5SDimitry Andrictemplate <class _Rep, class _Period>
4610b57cec5SDimitry Andricbool
4620b57cec5SDimitry Andricshared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
4630b57cec5SDimitry Andric{
4640b57cec5SDimitry Andric    if (__m_ == nullptr)
4650b57cec5SDimitry Andric        __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex");
4660b57cec5SDimitry Andric    if (__owns_)
4670b57cec5SDimitry Andric        __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked");
4680b57cec5SDimitry Andric    __owns_ = __m_->try_lock_shared_for(__d);
4690b57cec5SDimitry Andric    return __owns_;
4700b57cec5SDimitry Andric}
4710b57cec5SDimitry Andric
4720b57cec5SDimitry Andrictemplate <class _Mutex>
4730b57cec5SDimitry Andrictemplate <class _Clock, class _Duration>
4740b57cec5SDimitry Andricbool
4750b57cec5SDimitry Andricshared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
4760b57cec5SDimitry Andric{
4770b57cec5SDimitry Andric    if (__m_ == nullptr)
4780b57cec5SDimitry Andric        __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex");
4790b57cec5SDimitry Andric    if (__owns_)
4800b57cec5SDimitry Andric        __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked");
4810b57cec5SDimitry Andric    __owns_ = __m_->try_lock_shared_until(__t);
4820b57cec5SDimitry Andric    return __owns_;
4830b57cec5SDimitry Andric}
4840b57cec5SDimitry Andric
4850b57cec5SDimitry Andrictemplate <class _Mutex>
4860b57cec5SDimitry Andricvoid
4870b57cec5SDimitry Andricshared_lock<_Mutex>::unlock()
4880b57cec5SDimitry Andric{
4890b57cec5SDimitry Andric    if (!__owns_)
4900b57cec5SDimitry Andric        __throw_system_error(EPERM, "shared_lock::unlock: not locked");
4910b57cec5SDimitry Andric    __m_->unlock_shared();
4920b57cec5SDimitry Andric    __owns_ = false;
4930b57cec5SDimitry Andric}
4940b57cec5SDimitry Andric
4950b57cec5SDimitry Andrictemplate <class _Mutex>
4960b57cec5SDimitry Andricinline _LIBCPP_INLINE_VISIBILITY
4970b57cec5SDimitry Andricvoid
4980b57cec5SDimitry Andricswap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) _NOEXCEPT
4990b57cec5SDimitry Andric    {__x.swap(__y);}
5000b57cec5SDimitry Andric
5010b57cec5SDimitry Andric_LIBCPP_END_NAMESPACE_STD
5020b57cec5SDimitry Andric
5030b57cec5SDimitry Andric#endif // !_LIBCPP_HAS_NO_THREADS
5040b57cec5SDimitry Andric
5050b57cec5SDimitry Andric#endif // _LIBCPP_STD_VER > 11
5060b57cec5SDimitry Andric
5070b57cec5SDimitry Andric_LIBCPP_POP_MACROS
5080b57cec5SDimitry Andric
5090b57cec5SDimitry Andric#endif // _LIBCPP_SHARED_MUTEX
510