xref: /freebsd/contrib/llvm-project/libcxx/include/shared_mutex (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
10b57cec5SDimitry Andric// -*- C++ -*-
2349cc55cSDimitry Andric//===----------------------------------------------------------------------===//
30b57cec5SDimitry Andric//
40b57cec5SDimitry Andric// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
50b57cec5SDimitry Andric// See https://llvm.org/LICENSE.txt for license information.
60b57cec5SDimitry Andric// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
70b57cec5SDimitry Andric//
80b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
90b57cec5SDimitry Andric
100b57cec5SDimitry Andric#ifndef _LIBCPP_SHARED_MUTEX
110b57cec5SDimitry Andric#define _LIBCPP_SHARED_MUTEX
120b57cec5SDimitry Andric
130b57cec5SDimitry Andric/*
140b57cec5SDimitry Andric    shared_mutex synopsis
150b57cec5SDimitry Andric
160b57cec5SDimitry Andric// C++1y
170b57cec5SDimitry Andric
180b57cec5SDimitry Andricnamespace std
190b57cec5SDimitry Andric{
200b57cec5SDimitry Andric
210b57cec5SDimitry Andricclass shared_mutex      // C++17
220b57cec5SDimitry Andric{
230b57cec5SDimitry Andricpublic:
240b57cec5SDimitry Andric    shared_mutex();
250b57cec5SDimitry Andric    ~shared_mutex();
260b57cec5SDimitry Andric
270b57cec5SDimitry Andric    shared_mutex(const shared_mutex&) = delete;
280b57cec5SDimitry Andric    shared_mutex& operator=(const shared_mutex&) = delete;
290b57cec5SDimitry Andric
300b57cec5SDimitry Andric    // Exclusive ownership
310b57cec5SDimitry Andric    void lock(); // blocking
320b57cec5SDimitry Andric    bool try_lock();
330b57cec5SDimitry Andric    void unlock();
340b57cec5SDimitry Andric
350b57cec5SDimitry Andric    // Shared ownership
360b57cec5SDimitry Andric    void lock_shared(); // blocking
370b57cec5SDimitry Andric    bool try_lock_shared();
380b57cec5SDimitry Andric    void unlock_shared();
390b57cec5SDimitry Andric
400b57cec5SDimitry Andric    typedef implementation-defined native_handle_type; // See 30.2.3
410b57cec5SDimitry Andric    native_handle_type native_handle(); // See 30.2.3
420b57cec5SDimitry Andric};
430b57cec5SDimitry Andric
440b57cec5SDimitry Andricclass shared_timed_mutex
450b57cec5SDimitry Andric{
460b57cec5SDimitry Andricpublic:
470b57cec5SDimitry Andric    shared_timed_mutex();
480b57cec5SDimitry Andric    ~shared_timed_mutex();
490b57cec5SDimitry Andric
500b57cec5SDimitry Andric    shared_timed_mutex(const shared_timed_mutex&) = delete;
510b57cec5SDimitry Andric    shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
520b57cec5SDimitry Andric
530b57cec5SDimitry Andric    // Exclusive ownership
540b57cec5SDimitry Andric    void lock(); // blocking
550b57cec5SDimitry Andric    bool try_lock();
560b57cec5SDimitry Andric    template <class Rep, class Period>
570b57cec5SDimitry Andric        bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
580b57cec5SDimitry Andric    template <class Clock, class Duration>
590b57cec5SDimitry Andric        bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
600b57cec5SDimitry Andric    void unlock();
610b57cec5SDimitry Andric
620b57cec5SDimitry Andric    // Shared ownership
630b57cec5SDimitry Andric    void lock_shared(); // blocking
640b57cec5SDimitry Andric    bool try_lock_shared();
650b57cec5SDimitry Andric    template <class Rep, class Period>
660b57cec5SDimitry Andric        bool
670b57cec5SDimitry Andric        try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time);
680b57cec5SDimitry Andric    template <class Clock, class Duration>
690b57cec5SDimitry Andric        bool
700b57cec5SDimitry Andric        try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time);
710b57cec5SDimitry Andric    void unlock_shared();
720b57cec5SDimitry Andric};
730b57cec5SDimitry Andric
740b57cec5SDimitry Andrictemplate <class Mutex>
750b57cec5SDimitry Andricclass shared_lock
760b57cec5SDimitry Andric{
770b57cec5SDimitry Andricpublic:
780b57cec5SDimitry Andric    typedef Mutex mutex_type;
790b57cec5SDimitry Andric
800b57cec5SDimitry Andric    // Shared locking
810b57cec5SDimitry Andric    shared_lock() noexcept;
820b57cec5SDimitry Andric    explicit shared_lock(mutex_type& m); // blocking
830b57cec5SDimitry Andric    shared_lock(mutex_type& m, defer_lock_t) noexcept;
840b57cec5SDimitry Andric    shared_lock(mutex_type& m, try_to_lock_t);
850b57cec5SDimitry Andric    shared_lock(mutex_type& m, adopt_lock_t);
860b57cec5SDimitry Andric    template <class Clock, class Duration>
870b57cec5SDimitry Andric        shared_lock(mutex_type& m,
880b57cec5SDimitry Andric                    const chrono::time_point<Clock, Duration>& abs_time);
890b57cec5SDimitry Andric    template <class Rep, class Period>
900b57cec5SDimitry Andric        shared_lock(mutex_type& m,
910b57cec5SDimitry Andric                    const chrono::duration<Rep, Period>& rel_time);
920b57cec5SDimitry Andric    ~shared_lock();
930b57cec5SDimitry Andric
940b57cec5SDimitry Andric    shared_lock(shared_lock const&) = delete;
950b57cec5SDimitry Andric    shared_lock& operator=(shared_lock const&) = delete;
960b57cec5SDimitry Andric
970b57cec5SDimitry Andric    shared_lock(shared_lock&& u) noexcept;
980b57cec5SDimitry Andric    shared_lock& operator=(shared_lock&& u) noexcept;
990b57cec5SDimitry Andric
1000b57cec5SDimitry Andric    void lock(); // blocking
1010b57cec5SDimitry Andric    bool try_lock();
1020b57cec5SDimitry Andric    template <class Rep, class Period>
1030b57cec5SDimitry Andric        bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
1040b57cec5SDimitry Andric    template <class Clock, class Duration>
1050b57cec5SDimitry Andric        bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
1060b57cec5SDimitry Andric    void unlock();
1070b57cec5SDimitry Andric
1080b57cec5SDimitry Andric    // Setters
1090b57cec5SDimitry Andric    void swap(shared_lock& u) noexcept;
1100b57cec5SDimitry Andric    mutex_type* release() noexcept;
1110b57cec5SDimitry Andric
1120b57cec5SDimitry Andric    // Getters
1130b57cec5SDimitry Andric    bool owns_lock() const noexcept;
1140b57cec5SDimitry Andric    explicit operator bool () const noexcept;
1150b57cec5SDimitry Andric    mutex_type* mutex() const noexcept;
1160b57cec5SDimitry Andric};
1170b57cec5SDimitry Andric
1180b57cec5SDimitry Andrictemplate <class Mutex>
1190b57cec5SDimitry Andric    void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
1200b57cec5SDimitry Andric
1210b57cec5SDimitry Andric}  // std
1220b57cec5SDimitry Andric
1230b57cec5SDimitry Andric*/
1240b57cec5SDimitry Andric
12581ad6265SDimitry Andric#include <__assert> // all public C++ headers provide the assertion handler
126e8d8bef9SDimitry Andric#include <__availability>
127fe6060f1SDimitry Andric#include <__config>
1280b57cec5SDimitry Andric#include <version>
1290b57cec5SDimitry Andric
1300b57cec5SDimitry Andric_LIBCPP_PUSH_MACROS
1310b57cec5SDimitry Andric#include <__undef_macros>
1320b57cec5SDimitry Andric
1330b57cec5SDimitry Andric
1340b57cec5SDimitry Andric#if _LIBCPP_STD_VER > 11 || defined(_LIBCPP_BUILDING_LIBRARY)
1350b57cec5SDimitry Andric
1360b57cec5SDimitry Andric#include <__mutex_base>
1370b57cec5SDimitry Andric
1380b57cec5SDimitry Andric#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
1390b57cec5SDimitry Andric#  pragma GCC system_header
1400b57cec5SDimitry Andric#endif
1410b57cec5SDimitry Andric
1420b57cec5SDimitry Andric#ifdef _LIBCPP_HAS_NO_THREADS
14381ad6265SDimitry Andric# error "<shared_mutex> is not supported since libc++ has been configured without support for threads."
14481ad6265SDimitry Andric#endif
1450b57cec5SDimitry Andric
1460b57cec5SDimitry Andric_LIBCPP_BEGIN_NAMESPACE_STD
1470b57cec5SDimitry Andric
1480b57cec5SDimitry Andricstruct _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("shared_mutex"))
1490b57cec5SDimitry Andric__shared_mutex_base
1500b57cec5SDimitry Andric{
1510b57cec5SDimitry Andric    mutex               __mut_;
1520b57cec5SDimitry Andric    condition_variable  __gate1_;
1530b57cec5SDimitry Andric    condition_variable  __gate2_;
1540b57cec5SDimitry Andric    unsigned            __state_;
1550b57cec5SDimitry Andric
1560b57cec5SDimitry Andric    static const unsigned __write_entered_ = 1U << (sizeof(unsigned)*__CHAR_BIT__ - 1);
1570b57cec5SDimitry Andric    static const unsigned __n_readers_ = ~__write_entered_;
1580b57cec5SDimitry Andric
1590b57cec5SDimitry Andric    __shared_mutex_base();
1600b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY ~__shared_mutex_base() = default;
1610b57cec5SDimitry Andric
1620b57cec5SDimitry Andric    __shared_mutex_base(const __shared_mutex_base&) = delete;
1630b57cec5SDimitry Andric    __shared_mutex_base& operator=(const __shared_mutex_base&) = delete;
1640b57cec5SDimitry Andric
1650b57cec5SDimitry Andric    // Exclusive ownership
1660b57cec5SDimitry Andric    void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability()); // blocking
1670b57cec5SDimitry Andric    bool try_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_capability(true));
1680b57cec5SDimitry Andric    void unlock() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability());
1690b57cec5SDimitry Andric
1700b57cec5SDimitry Andric    // Shared ownership
1710b57cec5SDimitry Andric    void lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_shared_capability()); // blocking
1720b57cec5SDimitry Andric    bool try_lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_shared_capability(true));
1730b57cec5SDimitry Andric    void unlock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_shared_capability());
1740b57cec5SDimitry Andric
1750b57cec5SDimitry Andric//     typedef implementation-defined native_handle_type; // See 30.2.3
1760b57cec5SDimitry Andric//     native_handle_type native_handle(); // See 30.2.3
1770b57cec5SDimitry Andric};
1780b57cec5SDimitry Andric
1790b57cec5SDimitry Andric
1800b57cec5SDimitry Andric#if _LIBCPP_STD_VER > 14
1810b57cec5SDimitry Andricclass _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_mutex
1820b57cec5SDimitry Andric{
183*bdd1243dSDimitry Andric    __shared_mutex_base __base_;
1840b57cec5SDimitry Andricpublic:
185*bdd1243dSDimitry Andric    _LIBCPP_INLINE_VISIBILITY shared_mutex() : __base_() {}
1860b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY ~shared_mutex() = default;
1870b57cec5SDimitry Andric
1880b57cec5SDimitry Andric    shared_mutex(const shared_mutex&) = delete;
1890b57cec5SDimitry Andric    shared_mutex& operator=(const shared_mutex&) = delete;
1900b57cec5SDimitry Andric
1910b57cec5SDimitry Andric    // Exclusive ownership
192*bdd1243dSDimitry Andric    _LIBCPP_INLINE_VISIBILITY void lock()     { return __base_.lock(); }
193*bdd1243dSDimitry Andric    _LIBCPP_INLINE_VISIBILITY bool try_lock() { return __base_.try_lock(); }
194*bdd1243dSDimitry Andric    _LIBCPP_INLINE_VISIBILITY void unlock()   { return __base_.unlock(); }
1950b57cec5SDimitry Andric
1960b57cec5SDimitry Andric    // Shared ownership
197*bdd1243dSDimitry Andric    _LIBCPP_INLINE_VISIBILITY void lock_shared()     { return __base_.lock_shared(); }
198*bdd1243dSDimitry Andric    _LIBCPP_INLINE_VISIBILITY bool try_lock_shared() { return __base_.try_lock_shared(); }
199*bdd1243dSDimitry Andric    _LIBCPP_INLINE_VISIBILITY void unlock_shared()   { return __base_.unlock_shared(); }
2000b57cec5SDimitry Andric
2010b57cec5SDimitry Andric//     typedef __shared_mutex_base::native_handle_type native_handle_type;
2020b57cec5SDimitry Andric//     _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() { return __base::unlock_shared(); }
2030b57cec5SDimitry Andric};
2040b57cec5SDimitry Andric#endif
2050b57cec5SDimitry Andric
2060b57cec5SDimitry Andric
2070b57cec5SDimitry Andricclass _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_timed_mutex
2080b57cec5SDimitry Andric{
209*bdd1243dSDimitry Andric    __shared_mutex_base __base_;
2100b57cec5SDimitry Andricpublic:
2110b57cec5SDimitry Andric    shared_timed_mutex();
2120b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY ~shared_timed_mutex() = default;
2130b57cec5SDimitry Andric
2140b57cec5SDimitry Andric    shared_timed_mutex(const shared_timed_mutex&) = delete;
2150b57cec5SDimitry Andric    shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
2160b57cec5SDimitry Andric
2170b57cec5SDimitry Andric    // Exclusive ownership
2180b57cec5SDimitry Andric    void lock();
2190b57cec5SDimitry Andric    bool try_lock();
2200b57cec5SDimitry Andric    template <class _Rep, class _Period>
2210b57cec5SDimitry Andric        _LIBCPP_INLINE_VISIBILITY
2220b57cec5SDimitry Andric        bool
2230b57cec5SDimitry Andric        try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
2240b57cec5SDimitry Andric        {
2250b57cec5SDimitry Andric            return try_lock_until(chrono::steady_clock::now() + __rel_time);
2260b57cec5SDimitry Andric        }
2270b57cec5SDimitry Andric    template <class _Clock, class _Duration>
2280b57cec5SDimitry Andric        _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
2290b57cec5SDimitry Andric        bool
2300b57cec5SDimitry Andric        try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
2310b57cec5SDimitry Andric    void unlock();
2320b57cec5SDimitry Andric
2330b57cec5SDimitry Andric    // Shared ownership
2340b57cec5SDimitry Andric    void lock_shared();
2350b57cec5SDimitry Andric    bool try_lock_shared();
2360b57cec5SDimitry Andric    template <class _Rep, class _Period>
2370b57cec5SDimitry Andric        _LIBCPP_INLINE_VISIBILITY
2380b57cec5SDimitry Andric        bool
2390b57cec5SDimitry Andric        try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
2400b57cec5SDimitry Andric        {
2410b57cec5SDimitry Andric            return try_lock_shared_until(chrono::steady_clock::now() + __rel_time);
2420b57cec5SDimitry Andric        }
2430b57cec5SDimitry Andric    template <class _Clock, class _Duration>
2440b57cec5SDimitry Andric        _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
2450b57cec5SDimitry Andric        bool
2460b57cec5SDimitry Andric        try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
2470b57cec5SDimitry Andric    void unlock_shared();
2480b57cec5SDimitry Andric};
2490b57cec5SDimitry Andric
2500b57cec5SDimitry Andrictemplate <class _Clock, class _Duration>
2510b57cec5SDimitry Andricbool
2520b57cec5SDimitry Andricshared_timed_mutex::try_lock_until(
2530b57cec5SDimitry Andric                        const chrono::time_point<_Clock, _Duration>& __abs_time)
2540b57cec5SDimitry Andric{
255*bdd1243dSDimitry Andric    unique_lock<mutex> __lk(__base_.__mut_);
256*bdd1243dSDimitry Andric    if (__base_.__state_ & __base_.__write_entered_)
2570b57cec5SDimitry Andric    {
2580b57cec5SDimitry Andric        while (true)
2590b57cec5SDimitry Andric        {
260*bdd1243dSDimitry Andric            cv_status __status = __base_.__gate1_.wait_until(__lk, __abs_time);
261*bdd1243dSDimitry Andric            if ((__base_.__state_ & __base_.__write_entered_) == 0)
2620b57cec5SDimitry Andric                break;
2630b57cec5SDimitry Andric            if (__status == cv_status::timeout)
2640b57cec5SDimitry Andric                return false;
2650b57cec5SDimitry Andric        }
2660b57cec5SDimitry Andric    }
267*bdd1243dSDimitry Andric    __base_.__state_ |= __base_.__write_entered_;
268*bdd1243dSDimitry Andric    if (__base_.__state_ & __base_.__n_readers_)
2690b57cec5SDimitry Andric    {
2700b57cec5SDimitry Andric        while (true)
2710b57cec5SDimitry Andric        {
272*bdd1243dSDimitry Andric            cv_status __status = __base_.__gate2_.wait_until(__lk, __abs_time);
273*bdd1243dSDimitry Andric            if ((__base_.__state_ & __base_.__n_readers_) == 0)
2740b57cec5SDimitry Andric                break;
2750b57cec5SDimitry Andric            if (__status == cv_status::timeout)
2760b57cec5SDimitry Andric            {
277*bdd1243dSDimitry Andric                __base_.__state_ &= ~__base_.__write_entered_;
278*bdd1243dSDimitry Andric                __base_.__gate1_.notify_all();
2790b57cec5SDimitry Andric                return false;
2800b57cec5SDimitry Andric            }
2810b57cec5SDimitry Andric        }
2820b57cec5SDimitry Andric    }
2830b57cec5SDimitry Andric    return true;
2840b57cec5SDimitry Andric}
2850b57cec5SDimitry Andric
2860b57cec5SDimitry Andrictemplate <class _Clock, class _Duration>
2870b57cec5SDimitry Andricbool
2880b57cec5SDimitry Andricshared_timed_mutex::try_lock_shared_until(
2890b57cec5SDimitry Andric                        const chrono::time_point<_Clock, _Duration>& __abs_time)
2900b57cec5SDimitry Andric{
291*bdd1243dSDimitry Andric    unique_lock<mutex> __lk(__base_.__mut_);
292*bdd1243dSDimitry Andric    if ((__base_.__state_ & __base_.__write_entered_) || (__base_.__state_ & __base_.__n_readers_) == __base_.__n_readers_)
2930b57cec5SDimitry Andric    {
2940b57cec5SDimitry Andric        while (true)
2950b57cec5SDimitry Andric        {
296*bdd1243dSDimitry Andric            cv_status status = __base_.__gate1_.wait_until(__lk, __abs_time);
297*bdd1243dSDimitry Andric            if ((__base_.__state_ & __base_.__write_entered_) == 0 &&
298*bdd1243dSDimitry Andric                                       (__base_.__state_ & __base_.__n_readers_) < __base_.__n_readers_)
2990b57cec5SDimitry Andric                break;
3000b57cec5SDimitry Andric            if (status == cv_status::timeout)
3010b57cec5SDimitry Andric                return false;
3020b57cec5SDimitry Andric        }
3030b57cec5SDimitry Andric    }
304*bdd1243dSDimitry Andric    unsigned __num_readers = (__base_.__state_ & __base_.__n_readers_) + 1;
305*bdd1243dSDimitry Andric    __base_.__state_ &= ~__base_.__n_readers_;
306*bdd1243dSDimitry Andric    __base_.__state_ |= __num_readers;
3070b57cec5SDimitry Andric    return true;
3080b57cec5SDimitry Andric}
3090b57cec5SDimitry Andric
3100b57cec5SDimitry Andrictemplate <class _Mutex>
3110b57cec5SDimitry Andricclass shared_lock
3120b57cec5SDimitry Andric{
3130b57cec5SDimitry Andricpublic:
3140b57cec5SDimitry Andric    typedef _Mutex mutex_type;
3150b57cec5SDimitry Andric
3160b57cec5SDimitry Andricprivate:
3170b57cec5SDimitry Andric    mutex_type* __m_;
3180b57cec5SDimitry Andric    bool __owns_;
3190b57cec5SDimitry Andric
3200b57cec5SDimitry Andricpublic:
3210b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
3220b57cec5SDimitry Andric    shared_lock() _NOEXCEPT
3230b57cec5SDimitry Andric        : __m_(nullptr),
3240b57cec5SDimitry Andric          __owns_(false)
3250b57cec5SDimitry Andric        {}
3260b57cec5SDimitry Andric
3270b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
3280b57cec5SDimitry Andric    explicit shared_lock(mutex_type& __m)
3290b57cec5SDimitry Andric        : __m_(_VSTD::addressof(__m)),
3300b57cec5SDimitry Andric          __owns_(true)
3310b57cec5SDimitry Andric        {__m_->lock_shared();}
3320b57cec5SDimitry Andric
3330b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
3340b57cec5SDimitry Andric    shared_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
3350b57cec5SDimitry Andric        : __m_(_VSTD::addressof(__m)),
3360b57cec5SDimitry Andric          __owns_(false)
3370b57cec5SDimitry Andric        {}
3380b57cec5SDimitry Andric
3390b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
3400b57cec5SDimitry Andric    shared_lock(mutex_type& __m, try_to_lock_t)
3410b57cec5SDimitry Andric        : __m_(_VSTD::addressof(__m)),
3420b57cec5SDimitry Andric          __owns_(__m.try_lock_shared())
3430b57cec5SDimitry Andric        {}
3440b57cec5SDimitry Andric
3450b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
3460b57cec5SDimitry Andric    shared_lock(mutex_type& __m, adopt_lock_t)
3470b57cec5SDimitry Andric        : __m_(_VSTD::addressof(__m)),
3480b57cec5SDimitry Andric          __owns_(true)
3490b57cec5SDimitry Andric        {}
3500b57cec5SDimitry Andric
3510b57cec5SDimitry Andric    template <class _Clock, class _Duration>
3520b57cec5SDimitry Andric        _LIBCPP_INLINE_VISIBILITY
3530b57cec5SDimitry Andric        shared_lock(mutex_type& __m,
3540b57cec5SDimitry Andric                    const chrono::time_point<_Clock, _Duration>& __abs_time)
3550b57cec5SDimitry Andric            : __m_(_VSTD::addressof(__m)),
3560b57cec5SDimitry Andric              __owns_(__m.try_lock_shared_until(__abs_time))
3570b57cec5SDimitry Andric            {}
3580b57cec5SDimitry Andric
3590b57cec5SDimitry Andric    template <class _Rep, class _Period>
3600b57cec5SDimitry Andric        _LIBCPP_INLINE_VISIBILITY
3610b57cec5SDimitry Andric        shared_lock(mutex_type& __m,
3620b57cec5SDimitry Andric                    const chrono::duration<_Rep, _Period>& __rel_time)
3630b57cec5SDimitry Andric            : __m_(_VSTD::addressof(__m)),
3640b57cec5SDimitry Andric              __owns_(__m.try_lock_shared_for(__rel_time))
3650b57cec5SDimitry Andric            {}
3660b57cec5SDimitry Andric
3670b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
3680b57cec5SDimitry Andric    ~shared_lock()
3690b57cec5SDimitry Andric    {
3700b57cec5SDimitry Andric        if (__owns_)
3710b57cec5SDimitry Andric            __m_->unlock_shared();
3720b57cec5SDimitry Andric    }
3730b57cec5SDimitry Andric
3740b57cec5SDimitry Andric    shared_lock(shared_lock const&) = delete;
3750b57cec5SDimitry Andric    shared_lock& operator=(shared_lock const&) = delete;
3760b57cec5SDimitry Andric
3770b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
3780b57cec5SDimitry Andric    shared_lock(shared_lock&& __u) _NOEXCEPT
3790b57cec5SDimitry Andric        : __m_(__u.__m_),
3800b57cec5SDimitry Andric          __owns_(__u.__owns_)
3810b57cec5SDimitry Andric        {
3820b57cec5SDimitry Andric            __u.__m_ = nullptr;
3830b57cec5SDimitry Andric            __u.__owns_ = false;
3840b57cec5SDimitry Andric        }
3850b57cec5SDimitry Andric
3860b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
3870b57cec5SDimitry Andric    shared_lock& operator=(shared_lock&& __u) _NOEXCEPT
3880b57cec5SDimitry Andric    {
3890b57cec5SDimitry Andric        if (__owns_)
3900b57cec5SDimitry Andric            __m_->unlock_shared();
3910b57cec5SDimitry Andric        __m_ = nullptr;
3920b57cec5SDimitry Andric        __owns_ = false;
3930b57cec5SDimitry Andric        __m_ = __u.__m_;
3940b57cec5SDimitry Andric        __owns_ = __u.__owns_;
3950b57cec5SDimitry Andric        __u.__m_ = nullptr;
3960b57cec5SDimitry Andric        __u.__owns_ = false;
3970b57cec5SDimitry Andric        return *this;
3980b57cec5SDimitry Andric    }
3990b57cec5SDimitry Andric
4000b57cec5SDimitry Andric    void lock();
4010b57cec5SDimitry Andric    bool try_lock();
4020b57cec5SDimitry Andric    template <class Rep, class Period>
403753f127fSDimitry Andric        bool try_lock_for(const chrono::duration<Rep, Period>& __rel_time);
4040b57cec5SDimitry Andric    template <class Clock, class Duration>
405753f127fSDimitry Andric        bool try_lock_until(const chrono::time_point<Clock, Duration>& __abs_time);
4060b57cec5SDimitry Andric    void unlock();
4070b57cec5SDimitry Andric
4080b57cec5SDimitry Andric    // Setters
4090b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
4100b57cec5SDimitry Andric    void swap(shared_lock& __u) _NOEXCEPT
4110b57cec5SDimitry Andric    {
4120b57cec5SDimitry Andric        _VSTD::swap(__m_, __u.__m_);
4130b57cec5SDimitry Andric        _VSTD::swap(__owns_, __u.__owns_);
4140b57cec5SDimitry Andric    }
4150b57cec5SDimitry Andric
4160b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
4170b57cec5SDimitry Andric    mutex_type* release() _NOEXCEPT
4180b57cec5SDimitry Andric    {
4190b57cec5SDimitry Andric        mutex_type* __m = __m_;
4200b57cec5SDimitry Andric        __m_ = nullptr;
4210b57cec5SDimitry Andric        __owns_ = false;
4220b57cec5SDimitry Andric        return __m;
4230b57cec5SDimitry Andric    }
4240b57cec5SDimitry Andric
4250b57cec5SDimitry Andric    // Getters
4260b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
4270b57cec5SDimitry Andric    bool owns_lock() const _NOEXCEPT {return __owns_;}
4280b57cec5SDimitry Andric
4290b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
4300b57cec5SDimitry Andric    explicit operator bool () const _NOEXCEPT {return __owns_;}
4310b57cec5SDimitry Andric
4320b57cec5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
4330b57cec5SDimitry Andric    mutex_type* mutex() const _NOEXCEPT {return __m_;}
4340b57cec5SDimitry Andric};
435*bdd1243dSDimitry Andric_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(shared_lock);
4360b57cec5SDimitry Andric
4370b57cec5SDimitry Andrictemplate <class _Mutex>
4380b57cec5SDimitry Andricvoid
4390b57cec5SDimitry Andricshared_lock<_Mutex>::lock()
4400b57cec5SDimitry Andric{
4410b57cec5SDimitry Andric    if (__m_ == nullptr)
4420b57cec5SDimitry Andric        __throw_system_error(EPERM, "shared_lock::lock: references null mutex");
4430b57cec5SDimitry Andric    if (__owns_)
4440b57cec5SDimitry Andric        __throw_system_error(EDEADLK, "shared_lock::lock: already locked");
4450b57cec5SDimitry Andric    __m_->lock_shared();
4460b57cec5SDimitry Andric    __owns_ = true;
4470b57cec5SDimitry Andric}
4480b57cec5SDimitry Andric
4490b57cec5SDimitry Andrictemplate <class _Mutex>
4500b57cec5SDimitry Andricbool
4510b57cec5SDimitry Andricshared_lock<_Mutex>::try_lock()
4520b57cec5SDimitry Andric{
4530b57cec5SDimitry Andric    if (__m_ == nullptr)
4540b57cec5SDimitry Andric        __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex");
4550b57cec5SDimitry Andric    if (__owns_)
4560b57cec5SDimitry Andric        __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked");
4570b57cec5SDimitry Andric    __owns_ = __m_->try_lock_shared();
4580b57cec5SDimitry Andric    return __owns_;
4590b57cec5SDimitry Andric}
4600b57cec5SDimitry Andric
4610b57cec5SDimitry Andrictemplate <class _Mutex>
4620b57cec5SDimitry Andrictemplate <class _Rep, class _Period>
4630b57cec5SDimitry Andricbool
4640b57cec5SDimitry Andricshared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
4650b57cec5SDimitry Andric{
4660b57cec5SDimitry Andric    if (__m_ == nullptr)
4670b57cec5SDimitry Andric        __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex");
4680b57cec5SDimitry Andric    if (__owns_)
4690b57cec5SDimitry Andric        __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked");
4700b57cec5SDimitry Andric    __owns_ = __m_->try_lock_shared_for(__d);
4710b57cec5SDimitry Andric    return __owns_;
4720b57cec5SDimitry Andric}
4730b57cec5SDimitry Andric
4740b57cec5SDimitry Andrictemplate <class _Mutex>
4750b57cec5SDimitry Andrictemplate <class _Clock, class _Duration>
4760b57cec5SDimitry Andricbool
4770b57cec5SDimitry Andricshared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
4780b57cec5SDimitry Andric{
4790b57cec5SDimitry Andric    if (__m_ == nullptr)
4800b57cec5SDimitry Andric        __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex");
4810b57cec5SDimitry Andric    if (__owns_)
4820b57cec5SDimitry Andric        __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked");
4830b57cec5SDimitry Andric    __owns_ = __m_->try_lock_shared_until(__t);
4840b57cec5SDimitry Andric    return __owns_;
4850b57cec5SDimitry Andric}
4860b57cec5SDimitry Andric
4870b57cec5SDimitry Andrictemplate <class _Mutex>
4880b57cec5SDimitry Andricvoid
4890b57cec5SDimitry Andricshared_lock<_Mutex>::unlock()
4900b57cec5SDimitry Andric{
4910b57cec5SDimitry Andric    if (!__owns_)
4920b57cec5SDimitry Andric        __throw_system_error(EPERM, "shared_lock::unlock: not locked");
4930b57cec5SDimitry Andric    __m_->unlock_shared();
4940b57cec5SDimitry Andric    __owns_ = false;
4950b57cec5SDimitry Andric}
4960b57cec5SDimitry Andric
4970b57cec5SDimitry Andrictemplate <class _Mutex>
4980b57cec5SDimitry Andricinline _LIBCPP_INLINE_VISIBILITY
4990b57cec5SDimitry Andricvoid
5000b57cec5SDimitry Andricswap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) _NOEXCEPT
5010b57cec5SDimitry Andric    {__x.swap(__y);}
5020b57cec5SDimitry Andric
5030b57cec5SDimitry Andric_LIBCPP_END_NAMESPACE_STD
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