xref: /freebsd-12.1/contrib/libc++/include/mutex (revision 4173b67f)
17a984708SDavid Chisnall// -*- C++ -*-
27a984708SDavid Chisnall//===--------------------------- mutex ------------------------------------===//
37a984708SDavid Chisnall//
47a984708SDavid Chisnall//                     The LLVM Compiler Infrastructure
57a984708SDavid Chisnall//
67a984708SDavid Chisnall// This file is dual licensed under the MIT and the University of Illinois Open
77a984708SDavid Chisnall// Source Licenses. See LICENSE.TXT for details.
87a984708SDavid Chisnall//
97a984708SDavid Chisnall//===----------------------------------------------------------------------===//
107a984708SDavid Chisnall
117a984708SDavid Chisnall#ifndef _LIBCPP_MUTEX
127a984708SDavid Chisnall#define _LIBCPP_MUTEX
137a984708SDavid Chisnall
147a984708SDavid Chisnall/*
157a984708SDavid Chisnall    mutex synopsis
167a984708SDavid Chisnall
177a984708SDavid Chisnallnamespace std
187a984708SDavid Chisnall{
197a984708SDavid Chisnall
207a984708SDavid Chisnallclass mutex
217a984708SDavid Chisnall{
227a984708SDavid Chisnallpublic:
23936e9439SDimitry Andric     constexpr mutex() noexcept;
247a984708SDavid Chisnall     ~mutex();
257a984708SDavid Chisnall
267a984708SDavid Chisnall    mutex(const mutex&) = delete;
277a984708SDavid Chisnall    mutex& operator=(const mutex&) = delete;
287a984708SDavid Chisnall
297a984708SDavid Chisnall    void lock();
307a984708SDavid Chisnall    bool try_lock();
317a984708SDavid Chisnall    void unlock();
327a984708SDavid Chisnall
337a984708SDavid Chisnall    typedef pthread_mutex_t* native_handle_type;
347a984708SDavid Chisnall    native_handle_type native_handle();
357a984708SDavid Chisnall};
367a984708SDavid Chisnall
377a984708SDavid Chisnallclass recursive_mutex
387a984708SDavid Chisnall{
397a984708SDavid Chisnallpublic:
407a984708SDavid Chisnall     recursive_mutex();
417a984708SDavid Chisnall     ~recursive_mutex();
427a984708SDavid Chisnall
437a984708SDavid Chisnall    recursive_mutex(const recursive_mutex&) = delete;
447a984708SDavid Chisnall    recursive_mutex& operator=(const recursive_mutex&) = delete;
457a984708SDavid Chisnall
467a984708SDavid Chisnall    void lock();
47936e9439SDimitry Andric    bool try_lock() noexcept;
487a984708SDavid Chisnall    void unlock();
497a984708SDavid Chisnall
507a984708SDavid Chisnall    typedef pthread_mutex_t* native_handle_type;
517a984708SDavid Chisnall    native_handle_type native_handle();
527a984708SDavid Chisnall};
537a984708SDavid Chisnall
547a984708SDavid Chisnallclass timed_mutex
557a984708SDavid Chisnall{
567a984708SDavid Chisnallpublic:
577a984708SDavid Chisnall     timed_mutex();
587a984708SDavid Chisnall     ~timed_mutex();
597a984708SDavid Chisnall
607a984708SDavid Chisnall    timed_mutex(const timed_mutex&) = delete;
617a984708SDavid Chisnall    timed_mutex& operator=(const timed_mutex&) = delete;
627a984708SDavid Chisnall
637a984708SDavid Chisnall    void lock();
647a984708SDavid Chisnall    bool try_lock();
657a984708SDavid Chisnall    template <class Rep, class Period>
667a984708SDavid Chisnall        bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
677a984708SDavid Chisnall    template <class Clock, class Duration>
687a984708SDavid Chisnall        bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
697a984708SDavid Chisnall    void unlock();
707a984708SDavid Chisnall};
717a984708SDavid Chisnall
727a984708SDavid Chisnallclass recursive_timed_mutex
737a984708SDavid Chisnall{
747a984708SDavid Chisnallpublic:
757a984708SDavid Chisnall     recursive_timed_mutex();
767a984708SDavid Chisnall     ~recursive_timed_mutex();
777a984708SDavid Chisnall
787a984708SDavid Chisnall    recursive_timed_mutex(const recursive_timed_mutex&) = delete;
797a984708SDavid Chisnall    recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
807a984708SDavid Chisnall
817a984708SDavid Chisnall    void lock();
82936e9439SDimitry Andric    bool try_lock() noexcept;
837a984708SDavid Chisnall    template <class Rep, class Period>
847a984708SDavid Chisnall        bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
857a984708SDavid Chisnall    template <class Clock, class Duration>
867a984708SDavid Chisnall        bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
877a984708SDavid Chisnall    void unlock();
887a984708SDavid Chisnall};
897a984708SDavid Chisnall
907a984708SDavid Chisnallstruct defer_lock_t {};
917a984708SDavid Chisnallstruct try_to_lock_t {};
927a984708SDavid Chisnallstruct adopt_lock_t {};
937a984708SDavid Chisnall
9430785c0eSDimitry Andricinline constexpr defer_lock_t  defer_lock{};
9530785c0eSDimitry Andricinline constexpr try_to_lock_t try_to_lock{};
9630785c0eSDimitry Andricinline constexpr adopt_lock_t  adopt_lock{};
977a984708SDavid Chisnall
987a984708SDavid Chisnalltemplate <class Mutex>
997a984708SDavid Chisnallclass lock_guard
1007a984708SDavid Chisnall{
1017a984708SDavid Chisnallpublic:
1027a984708SDavid Chisnall    typedef Mutex mutex_type;
1037a984708SDavid Chisnall
1047a984708SDavid Chisnall    explicit lock_guard(mutex_type& m);
1057a984708SDavid Chisnall    lock_guard(mutex_type& m, adopt_lock_t);
1067a984708SDavid Chisnall    ~lock_guard();
1077a984708SDavid Chisnall
1087a984708SDavid Chisnall    lock_guard(lock_guard const&) = delete;
1097a984708SDavid Chisnall    lock_guard& operator=(lock_guard const&) = delete;
1107a984708SDavid Chisnall};
1117a984708SDavid Chisnall
112540d2a8bSDimitry Andrictemplate <class... MutexTypes>
113540d2a8bSDimitry Andricclass scoped_lock // C++17
1147c82a1ecSDimitry Andric{
1157c82a1ecSDimitry Andricpublic:
116540d2a8bSDimitry Andric    using mutex_type = Mutex;  // If MutexTypes... consists of the single type Mutex
117540d2a8bSDimitry Andric
118540d2a8bSDimitry Andric    explicit scoped_lock(MutexTypes&... m);
1199dc417c3SDimitry Andric    scoped_lock(adopt_lock_t, MutexTypes&... m);
120540d2a8bSDimitry Andric    ~scoped_lock();
121540d2a8bSDimitry Andric    scoped_lock(scoped_lock const&) = delete;
122540d2a8bSDimitry Andric    scoped_lock& operator=(scoped_lock const&) = delete;
1237c82a1ecSDimitry Andricprivate:
1247c82a1ecSDimitry Andric    tuple<MutexTypes&...> pm; // exposition only
1257c82a1ecSDimitry Andric};
1267c82a1ecSDimitry Andric
1277a984708SDavid Chisnalltemplate <class Mutex>
1287a984708SDavid Chisnallclass unique_lock
1297a984708SDavid Chisnall{
1307a984708SDavid Chisnallpublic:
1317a984708SDavid Chisnall    typedef Mutex mutex_type;
132936e9439SDimitry Andric    unique_lock() noexcept;
1337a984708SDavid Chisnall    explicit unique_lock(mutex_type& m);
134936e9439SDimitry Andric    unique_lock(mutex_type& m, defer_lock_t) noexcept;
1357a984708SDavid Chisnall    unique_lock(mutex_type& m, try_to_lock_t);
1367a984708SDavid Chisnall    unique_lock(mutex_type& m, adopt_lock_t);
1377a984708SDavid Chisnall    template <class Clock, class Duration>
1387a984708SDavid Chisnall        unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);
1397a984708SDavid Chisnall    template <class Rep, class Period>
1407a984708SDavid Chisnall        unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time);
1417a984708SDavid Chisnall    ~unique_lock();
1427a984708SDavid Chisnall
1437a984708SDavid Chisnall    unique_lock(unique_lock const&) = delete;
1447a984708SDavid Chisnall    unique_lock& operator=(unique_lock const&) = delete;
1457a984708SDavid Chisnall
146936e9439SDimitry Andric    unique_lock(unique_lock&& u) noexcept;
147936e9439SDimitry Andric    unique_lock& operator=(unique_lock&& u) noexcept;
1487a984708SDavid Chisnall
1497a984708SDavid Chisnall    void lock();
1507a984708SDavid Chisnall    bool try_lock();
1517a984708SDavid Chisnall
1527a984708SDavid Chisnall    template <class Rep, class Period>
1537a984708SDavid Chisnall        bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
1547a984708SDavid Chisnall    template <class Clock, class Duration>
1557a984708SDavid Chisnall        bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
1567a984708SDavid Chisnall
1577a984708SDavid Chisnall    void unlock();
1587a984708SDavid Chisnall
159936e9439SDimitry Andric    void swap(unique_lock& u) noexcept;
160936e9439SDimitry Andric    mutex_type* release() noexcept;
1617a984708SDavid Chisnall
162936e9439SDimitry Andric    bool owns_lock() const noexcept;
163936e9439SDimitry Andric    explicit operator bool () const noexcept;
164936e9439SDimitry Andric    mutex_type* mutex() const noexcept;
1657a984708SDavid Chisnall};
1667a984708SDavid Chisnall
1677a984708SDavid Chisnalltemplate <class Mutex>
168936e9439SDimitry Andric  void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept;
1697a984708SDavid Chisnall
1707a984708SDavid Chisnalltemplate <class L1, class L2, class... L3>
1717a984708SDavid Chisnall  int try_lock(L1&, L2&, L3&...);
1727a984708SDavid Chisnalltemplate <class L1, class L2, class... L3>
1737a984708SDavid Chisnall  void lock(L1&, L2&, L3&...);
1747a984708SDavid Chisnall
1757a984708SDavid Chisnallstruct once_flag
1767a984708SDavid Chisnall{
177936e9439SDimitry Andric    constexpr once_flag() noexcept;
1787a984708SDavid Chisnall
1797a984708SDavid Chisnall    once_flag(const once_flag&) = delete;
1807a984708SDavid Chisnall    once_flag& operator=(const once_flag&) = delete;
1817a984708SDavid Chisnall};
1827a984708SDavid Chisnall
1837a984708SDavid Chisnalltemplate<class Callable, class ...Args>
1847a984708SDavid Chisnall  void call_once(once_flag& flag, Callable&& func, Args&&... args);
1857a984708SDavid Chisnall
1867a984708SDavid Chisnall}  // std
1877a984708SDavid Chisnall
1887a984708SDavid Chisnall*/
1897a984708SDavid Chisnall
1907a984708SDavid Chisnall#include <__config>
1917a984708SDavid Chisnall#include <__mutex_base>
1927a984708SDavid Chisnall#include <functional>
193854fa44bSDimitry Andric#include <memory>
194540d2a8bSDimitry Andric#ifndef _LIBCPP_CXX03_LANG
1957a984708SDavid Chisnall#include <tuple>
1967a984708SDavid Chisnall#endif
197b5893f02SDimitry Andric#include <version>
1987c82a1ecSDimitry Andric#include <__threading_support>
1997a984708SDavid Chisnall
2007a984708SDavid Chisnall#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
2017a984708SDavid Chisnall#pragma GCC system_header
2027a984708SDavid Chisnall#endif
2037a984708SDavid Chisnall
204f9448bf3SDimitry Andric_LIBCPP_PUSH_MACROS
205f9448bf3SDimitry Andric#include <__undef_macros>
206f9448bf3SDimitry Andric
207f9448bf3SDimitry Andric
2087a984708SDavid Chisnall_LIBCPP_BEGIN_NAMESPACE_STD
2097a984708SDavid Chisnall
210d72607e9SDimitry Andric#ifndef _LIBCPP_HAS_NO_THREADS
211d72607e9SDimitry Andric
2121bf9f7c1SDimitry Andricclass _LIBCPP_TYPE_VIS recursive_mutex
2137a984708SDavid Chisnall{
214aed8d94eSDimitry Andric    __libcpp_recursive_mutex_t __m_;
2157a984708SDavid Chisnall
2167a984708SDavid Chisnallpublic:
2177a984708SDavid Chisnall     recursive_mutex();
2187a984708SDavid Chisnall     ~recursive_mutex();
2197a984708SDavid Chisnall
2207a984708SDavid Chisnallprivate:
2217a984708SDavid Chisnall    recursive_mutex(const recursive_mutex&); // = delete;
2227a984708SDavid Chisnall    recursive_mutex& operator=(const recursive_mutex&); // = delete;
2237a984708SDavid Chisnall
2247a984708SDavid Chisnallpublic:
2257a984708SDavid Chisnall    void lock();
226936e9439SDimitry Andric    bool try_lock() _NOEXCEPT;
227936e9439SDimitry Andric    void unlock()  _NOEXCEPT;
2287a984708SDavid Chisnall
229aed8d94eSDimitry Andric    typedef __libcpp_recursive_mutex_t* native_handle_type;
230aed8d94eSDimitry Andric
2317a984708SDavid Chisnall    _LIBCPP_INLINE_VISIBILITY
2327a984708SDavid Chisnall    native_handle_type native_handle() {return &__m_;}
2337a984708SDavid Chisnall};
2347a984708SDavid Chisnall
2351bf9f7c1SDimitry Andricclass _LIBCPP_TYPE_VIS timed_mutex
2367a984708SDavid Chisnall{
2377a984708SDavid Chisnall    mutex              __m_;
2387a984708SDavid Chisnall    condition_variable __cv_;
2397a984708SDavid Chisnall    bool               __locked_;
2407a984708SDavid Chisnallpublic:
2417a984708SDavid Chisnall     timed_mutex();
2427a984708SDavid Chisnall     ~timed_mutex();
2437a984708SDavid Chisnall
2447a984708SDavid Chisnallprivate:
2457a984708SDavid Chisnall    timed_mutex(const timed_mutex&); // = delete;
2467a984708SDavid Chisnall    timed_mutex& operator=(const timed_mutex&); // = delete;
2477a984708SDavid Chisnall
2487a984708SDavid Chisnallpublic:
2497a984708SDavid Chisnall    void lock();
250936e9439SDimitry Andric    bool try_lock() _NOEXCEPT;
2517a984708SDavid Chisnall    template <class _Rep, class _Period>
2527a984708SDavid Chisnall        _LIBCPP_INLINE_VISIBILITY
2537a984708SDavid Chisnall        bool try_lock_for(const chrono::duration<_Rep, _Period>& __d)
2547a984708SDavid Chisnall            {return try_lock_until(chrono::steady_clock::now() + __d);}
2557a984708SDavid Chisnall    template <class _Clock, class _Duration>
256540d2a8bSDimitry Andric        _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
2577a984708SDavid Chisnall        bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
258936e9439SDimitry Andric    void unlock() _NOEXCEPT;
2597a984708SDavid Chisnall};
2607a984708SDavid Chisnall
2617a984708SDavid Chisnalltemplate <class _Clock, class _Duration>
2627a984708SDavid Chisnallbool
2637a984708SDavid Chisnalltimed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
2647a984708SDavid Chisnall{
2657a984708SDavid Chisnall    using namespace chrono;
2667a984708SDavid Chisnall    unique_lock<mutex> __lk(__m_);
2677a984708SDavid Chisnall    bool no_timeout = _Clock::now() < __t;
2687a984708SDavid Chisnall    while (no_timeout && __locked_)
2697a984708SDavid Chisnall        no_timeout = __cv_.wait_until(__lk, __t) == cv_status::no_timeout;
2707a984708SDavid Chisnall    if (!__locked_)
2717a984708SDavid Chisnall    {
2727a984708SDavid Chisnall        __locked_ = true;
2737a984708SDavid Chisnall        return true;
2747a984708SDavid Chisnall    }
2757a984708SDavid Chisnall    return false;
2767a984708SDavid Chisnall}
2777a984708SDavid Chisnall
2781bf9f7c1SDimitry Andricclass _LIBCPP_TYPE_VIS recursive_timed_mutex
2797a984708SDavid Chisnall{
2807a984708SDavid Chisnall    mutex              __m_;
2817a984708SDavid Chisnall    condition_variable __cv_;
2827a984708SDavid Chisnall    size_t             __count_;
283*4173b67fSDimitry Andric    __thread_id        __id_;
2847a984708SDavid Chisnallpublic:
2857a984708SDavid Chisnall     recursive_timed_mutex();
2867a984708SDavid Chisnall     ~recursive_timed_mutex();
2877a984708SDavid Chisnall
2887a984708SDavid Chisnallprivate:
2897a984708SDavid Chisnall    recursive_timed_mutex(const recursive_timed_mutex&); // = delete;
2907a984708SDavid Chisnall    recursive_timed_mutex& operator=(const recursive_timed_mutex&); // = delete;
2917a984708SDavid Chisnall
2927a984708SDavid Chisnallpublic:
2937a984708SDavid Chisnall    void lock();
294936e9439SDimitry Andric    bool try_lock() _NOEXCEPT;
2957a984708SDavid Chisnall    template <class _Rep, class _Period>
2967a984708SDavid Chisnall        _LIBCPP_INLINE_VISIBILITY
2977a984708SDavid Chisnall        bool try_lock_for(const chrono::duration<_Rep, _Period>& __d)
2987a984708SDavid Chisnall            {return try_lock_until(chrono::steady_clock::now() + __d);}
2997a984708SDavid Chisnall    template <class _Clock, class _Duration>
300540d2a8bSDimitry Andric        _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
3017a984708SDavid Chisnall        bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
302936e9439SDimitry Andric    void unlock() _NOEXCEPT;
3037a984708SDavid Chisnall};
3047a984708SDavid Chisnall
3057a984708SDavid Chisnalltemplate <class _Clock, class _Duration>
3067a984708SDavid Chisnallbool
3077a984708SDavid Chisnallrecursive_timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
3087a984708SDavid Chisnall{
3097a984708SDavid Chisnall    using namespace chrono;
310*4173b67fSDimitry Andric    __thread_id __id = this_thread::get_id();
3117a984708SDavid Chisnall    unique_lock<mutex> lk(__m_);
312*4173b67fSDimitry Andric    if (__id == __id_)
3137a984708SDavid Chisnall    {
3147a984708SDavid Chisnall        if (__count_ == numeric_limits<size_t>::max())
3157a984708SDavid Chisnall            return false;
3167a984708SDavid Chisnall        ++__count_;
3177a984708SDavid Chisnall        return true;
3187a984708SDavid Chisnall    }
3197a984708SDavid Chisnall    bool no_timeout = _Clock::now() < __t;
3207a984708SDavid Chisnall    while (no_timeout && __count_ != 0)
3217a984708SDavid Chisnall        no_timeout = __cv_.wait_until(lk, __t) == cv_status::no_timeout;
3227a984708SDavid Chisnall    if (__count_ == 0)
3237a984708SDavid Chisnall    {
3247a984708SDavid Chisnall        __count_ = 1;
3257a984708SDavid Chisnall        __id_ = __id;
3267a984708SDavid Chisnall        return true;
3277a984708SDavid Chisnall    }
3287a984708SDavid Chisnall    return false;
3297a984708SDavid Chisnall}
3307a984708SDavid Chisnall
3317a984708SDavid Chisnalltemplate <class _L0, class _L1>
3327a984708SDavid Chisnallint
3337a984708SDavid Chisnalltry_lock(_L0& __l0, _L1& __l1)
3347a984708SDavid Chisnall{
3357a984708SDavid Chisnall    unique_lock<_L0> __u0(__l0, try_to_lock);
3367a984708SDavid Chisnall    if (__u0.owns_lock())
3377a984708SDavid Chisnall    {
3387a984708SDavid Chisnall        if (__l1.try_lock())
3397a984708SDavid Chisnall        {
3407a984708SDavid Chisnall            __u0.release();
3417a984708SDavid Chisnall            return -1;
3427a984708SDavid Chisnall        }
3437a984708SDavid Chisnall        else
3447a984708SDavid Chisnall            return 1;
3457a984708SDavid Chisnall    }
3467a984708SDavid Chisnall    return 0;
3477a984708SDavid Chisnall}
3487a984708SDavid Chisnall
349540d2a8bSDimitry Andric#ifndef _LIBCPP_CXX03_LANG
3507a984708SDavid Chisnall
3517a984708SDavid Chisnalltemplate <class _L0, class _L1, class _L2, class... _L3>
3527a984708SDavid Chisnallint
3537a984708SDavid Chisnalltry_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3)
3547a984708SDavid Chisnall{
3557a984708SDavid Chisnall    int __r = 0;
3567a984708SDavid Chisnall    unique_lock<_L0> __u0(__l0, try_to_lock);
3577a984708SDavid Chisnall    if (__u0.owns_lock())
3587a984708SDavid Chisnall    {
3597a984708SDavid Chisnall        __r = try_lock(__l1, __l2, __l3...);
3607a984708SDavid Chisnall        if (__r == -1)
3617a984708SDavid Chisnall            __u0.release();
3627a984708SDavid Chisnall        else
3637a984708SDavid Chisnall            ++__r;
3647a984708SDavid Chisnall    }
3657a984708SDavid Chisnall    return __r;
3667a984708SDavid Chisnall}
3677a984708SDavid Chisnall
368540d2a8bSDimitry Andric#endif  // _LIBCPP_CXX03_LANG
3697a984708SDavid Chisnall
3707a984708SDavid Chisnalltemplate <class _L0, class _L1>
3717a984708SDavid Chisnallvoid
3727a984708SDavid Chisnalllock(_L0& __l0, _L1& __l1)
3737a984708SDavid Chisnall{
3747a984708SDavid Chisnall    while (true)
3757a984708SDavid Chisnall    {
3767a984708SDavid Chisnall        {
3777a984708SDavid Chisnall            unique_lock<_L0> __u0(__l0);
3787a984708SDavid Chisnall            if (__l1.try_lock())
3797a984708SDavid Chisnall            {
3807a984708SDavid Chisnall                __u0.release();
3817a984708SDavid Chisnall                break;
3827a984708SDavid Chisnall            }
3837a984708SDavid Chisnall        }
3847c82a1ecSDimitry Andric        __libcpp_thread_yield();
3857a984708SDavid Chisnall        {
3867a984708SDavid Chisnall            unique_lock<_L1> __u1(__l1);
3877a984708SDavid Chisnall            if (__l0.try_lock())
3887a984708SDavid Chisnall            {
3897a984708SDavid Chisnall                __u1.release();
3907a984708SDavid Chisnall                break;
3917a984708SDavid Chisnall            }
3927a984708SDavid Chisnall        }
3937c82a1ecSDimitry Andric        __libcpp_thread_yield();
3947a984708SDavid Chisnall    }
3957a984708SDavid Chisnall}
3967a984708SDavid Chisnall
397540d2a8bSDimitry Andric#ifndef _LIBCPP_CXX03_LANG
3987a984708SDavid Chisnall
3997a984708SDavid Chisnalltemplate <class _L0, class _L1, class _L2, class ..._L3>
4007a984708SDavid Chisnallvoid
4017a984708SDavid Chisnall__lock_first(int __i, _L0& __l0, _L1& __l1, _L2& __l2, _L3& ...__l3)
4027a984708SDavid Chisnall{
4037a984708SDavid Chisnall    while (true)
4047a984708SDavid Chisnall    {
4057a984708SDavid Chisnall        switch (__i)
4067a984708SDavid Chisnall        {
4077a984708SDavid Chisnall        case 0:
4087a984708SDavid Chisnall            {
4097a984708SDavid Chisnall                unique_lock<_L0> __u0(__l0);
4107a984708SDavid Chisnall                __i = try_lock(__l1, __l2, __l3...);
4117a984708SDavid Chisnall                if (__i == -1)
4127a984708SDavid Chisnall                {
4137a984708SDavid Chisnall                    __u0.release();
4147a984708SDavid Chisnall                    return;
4157a984708SDavid Chisnall                }
4167a984708SDavid Chisnall            }
4177a984708SDavid Chisnall            ++__i;
4187c82a1ecSDimitry Andric            __libcpp_thread_yield();
4197a984708SDavid Chisnall            break;
4207a984708SDavid Chisnall        case 1:
4217a984708SDavid Chisnall            {
4227a984708SDavid Chisnall                unique_lock<_L1> __u1(__l1);
4237a984708SDavid Chisnall                __i = try_lock(__l2, __l3..., __l0);
4247a984708SDavid Chisnall                if (__i == -1)
4257a984708SDavid Chisnall                {
4267a984708SDavid Chisnall                    __u1.release();
4277a984708SDavid Chisnall                    return;
4287a984708SDavid Chisnall                }
4297a984708SDavid Chisnall            }
4307a984708SDavid Chisnall            if (__i == sizeof...(_L3) + 1)
4317a984708SDavid Chisnall                __i = 0;
4327a984708SDavid Chisnall            else
4337a984708SDavid Chisnall                __i += 2;
4347c82a1ecSDimitry Andric            __libcpp_thread_yield();
4357a984708SDavid Chisnall            break;
4367a984708SDavid Chisnall        default:
4377a984708SDavid Chisnall            __lock_first(__i - 2, __l2, __l3..., __l0, __l1);
4387a984708SDavid Chisnall            return;
4397a984708SDavid Chisnall        }
4407a984708SDavid Chisnall    }
4417a984708SDavid Chisnall}
4427a984708SDavid Chisnall
4437a984708SDavid Chisnalltemplate <class _L0, class _L1, class _L2, class ..._L3>
4447a984708SDavid Chisnallinline _LIBCPP_INLINE_VISIBILITY
4457a984708SDavid Chisnallvoid
4467a984708SDavid Chisnalllock(_L0& __l0, _L1& __l1, _L2& __l2, _L3& ...__l3)
4477a984708SDavid Chisnall{
4487a984708SDavid Chisnall    __lock_first(0, __l0, __l1, __l2, __l3...);
4497a984708SDavid Chisnall}
4507a984708SDavid Chisnall
4517c82a1ecSDimitry Andrictemplate <class _L0>
4527c82a1ecSDimitry Andricinline _LIBCPP_INLINE_VISIBILITY
4537c82a1ecSDimitry Andricvoid __unlock(_L0& __l0) {
4547c82a1ecSDimitry Andric    __l0.unlock();
4557c82a1ecSDimitry Andric}
4567c82a1ecSDimitry Andric
4577c82a1ecSDimitry Andrictemplate <class _L0, class _L1>
4587c82a1ecSDimitry Andricinline _LIBCPP_INLINE_VISIBILITY
4597c82a1ecSDimitry Andricvoid __unlock(_L0& __l0, _L1& __l1) {
4607c82a1ecSDimitry Andric    __l0.unlock();
4617c82a1ecSDimitry Andric    __l1.unlock();
4627c82a1ecSDimitry Andric}
4637c82a1ecSDimitry Andric
4647c82a1ecSDimitry Andrictemplate <class _L0, class _L1, class _L2, class ..._L3>
4657c82a1ecSDimitry Andricinline _LIBCPP_INLINE_VISIBILITY
4667c82a1ecSDimitry Andricvoid __unlock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) {
4677c82a1ecSDimitry Andric    __l0.unlock();
4687c82a1ecSDimitry Andric    __l1.unlock();
4697c82a1ecSDimitry Andric    _VSTD::__unlock(__l2, __l3...);
4707c82a1ecSDimitry Andric}
4717c82a1ecSDimitry Andric
472540d2a8bSDimitry Andric#endif  // _LIBCPP_CXX03_LANG
4737a984708SDavid Chisnall
474540d2a8bSDimitry Andric#if _LIBCPP_STD_VER > 14
475540d2a8bSDimitry Andrictemplate <class ..._Mutexes>
476540d2a8bSDimitry Andricclass _LIBCPP_TEMPLATE_VIS scoped_lock;
477540d2a8bSDimitry Andric
478540d2a8bSDimitry Andrictemplate <>
479540d2a8bSDimitry Andricclass _LIBCPP_TEMPLATE_VIS scoped_lock<> {
480540d2a8bSDimitry Andricpublic:
481540d2a8bSDimitry Andric    explicit scoped_lock() {}
482540d2a8bSDimitry Andric    ~scoped_lock() = default;
483540d2a8bSDimitry Andric
484540d2a8bSDimitry Andric    _LIBCPP_INLINE_VISIBILITY
485540d2a8bSDimitry Andric    explicit scoped_lock(adopt_lock_t) {}
486540d2a8bSDimitry Andric
487540d2a8bSDimitry Andric    scoped_lock(scoped_lock const&) = delete;
488540d2a8bSDimitry Andric    scoped_lock& operator=(scoped_lock const&) = delete;
489540d2a8bSDimitry Andric};
490540d2a8bSDimitry Andric
491540d2a8bSDimitry Andrictemplate <class _Mutex>
492b5893f02SDimitry Andricclass _LIBCPP_TEMPLATE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable) scoped_lock<_Mutex> {
493540d2a8bSDimitry Andricpublic:
494540d2a8bSDimitry Andric    typedef _Mutex  mutex_type;
495540d2a8bSDimitry Andricprivate:
496540d2a8bSDimitry Andric    mutex_type& __m_;
497540d2a8bSDimitry Andricpublic:
498540d2a8bSDimitry Andric    explicit scoped_lock(mutex_type & __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability(__m))
499540d2a8bSDimitry Andric        : __m_(__m) {__m_.lock();}
500540d2a8bSDimitry Andric
501540d2a8bSDimitry Andric    ~scoped_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) {__m_.unlock();}
502540d2a8bSDimitry Andric
503540d2a8bSDimitry Andric    _LIBCPP_INLINE_VISIBILITY
5049dc417c3SDimitry Andric    explicit scoped_lock(adopt_lock_t, mutex_type& __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m))
505540d2a8bSDimitry Andric        : __m_(__m) {}
506540d2a8bSDimitry Andric
507540d2a8bSDimitry Andric    scoped_lock(scoped_lock const&) = delete;
508540d2a8bSDimitry Andric    scoped_lock& operator=(scoped_lock const&) = delete;
509540d2a8bSDimitry Andric};
510540d2a8bSDimitry Andric
511540d2a8bSDimitry Andrictemplate <class ..._MArgs>
512540d2a8bSDimitry Andricclass _LIBCPP_TEMPLATE_VIS scoped_lock
513540d2a8bSDimitry Andric{
514540d2a8bSDimitry Andric    static_assert(sizeof...(_MArgs) > 1, "At least 2 lock types required");
515540d2a8bSDimitry Andric    typedef tuple<_MArgs&...> _MutexTuple;
516540d2a8bSDimitry Andric
517540d2a8bSDimitry Andricpublic:
518540d2a8bSDimitry Andric    _LIBCPP_INLINE_VISIBILITY
519540d2a8bSDimitry Andric    explicit scoped_lock(_MArgs&... __margs)
520540d2a8bSDimitry Andric      : __t_(__margs...)
521540d2a8bSDimitry Andric    {
522540d2a8bSDimitry Andric        _VSTD::lock(__margs...);
523540d2a8bSDimitry Andric    }
524540d2a8bSDimitry Andric
525540d2a8bSDimitry Andric    _LIBCPP_INLINE_VISIBILITY
5269dc417c3SDimitry Andric    scoped_lock(adopt_lock_t, _MArgs&... __margs)
527540d2a8bSDimitry Andric        : __t_(__margs...)
528540d2a8bSDimitry Andric    {
529540d2a8bSDimitry Andric    }
530540d2a8bSDimitry Andric
531540d2a8bSDimitry Andric    _LIBCPP_INLINE_VISIBILITY
532540d2a8bSDimitry Andric    ~scoped_lock() {
533540d2a8bSDimitry Andric        typedef typename __make_tuple_indices<sizeof...(_MArgs)>::type _Indices;
534540d2a8bSDimitry Andric        __unlock_unpack(_Indices{}, __t_);
535540d2a8bSDimitry Andric    }
536540d2a8bSDimitry Andric
537540d2a8bSDimitry Andric    scoped_lock(scoped_lock const&) = delete;
538540d2a8bSDimitry Andric    scoped_lock& operator=(scoped_lock const&) = delete;
539540d2a8bSDimitry Andric
540540d2a8bSDimitry Andricprivate:
541540d2a8bSDimitry Andric    template <size_t ..._Indx>
542540d2a8bSDimitry Andric    _LIBCPP_INLINE_VISIBILITY
543540d2a8bSDimitry Andric    static void __unlock_unpack(__tuple_indices<_Indx...>, _MutexTuple& __mt) {
544540d2a8bSDimitry Andric        _VSTD::__unlock(_VSTD::get<_Indx>(__mt)...);
545540d2a8bSDimitry Andric    }
546540d2a8bSDimitry Andric
547540d2a8bSDimitry Andric    _MutexTuple __t_;
548540d2a8bSDimitry Andric};
549540d2a8bSDimitry Andric
550540d2a8bSDimitry Andric#endif // _LIBCPP_STD_VER > 14
551d72607e9SDimitry Andric#endif // !_LIBCPP_HAS_NO_THREADS
552d72607e9SDimitry Andric
553aed8d94eSDimitry Andricstruct _LIBCPP_TEMPLATE_VIS once_flag;
5547a984708SDavid Chisnall
555540d2a8bSDimitry Andric#ifndef _LIBCPP_CXX03_LANG
5567a984708SDavid Chisnall
5577a984708SDavid Chisnalltemplate<class _Callable, class... _Args>
558936e9439SDimitry Andric_LIBCPP_INLINE_VISIBILITY
5597a984708SDavid Chisnallvoid call_once(once_flag&, _Callable&&, _Args&&...);
5607a984708SDavid Chisnall
561540d2a8bSDimitry Andric#else  // _LIBCPP_CXX03_LANG
5627a984708SDavid Chisnall
5637a984708SDavid Chisnalltemplate<class _Callable>
564936e9439SDimitry Andric_LIBCPP_INLINE_VISIBILITY
565854fa44bSDimitry Andricvoid call_once(once_flag&, _Callable&);
566854fa44bSDimitry Andric
567854fa44bSDimitry Andrictemplate<class _Callable>
568854fa44bSDimitry Andric_LIBCPP_INLINE_VISIBILITY
569854fa44bSDimitry Andricvoid call_once(once_flag&, const _Callable&);
5707a984708SDavid Chisnall
571540d2a8bSDimitry Andric#endif  // _LIBCPP_CXX03_LANG
5727a984708SDavid Chisnall
573aed8d94eSDimitry Andricstruct _LIBCPP_TEMPLATE_VIS once_flag
5747a984708SDavid Chisnall{
5757a984708SDavid Chisnall    _LIBCPP_INLINE_VISIBILITY
576936e9439SDimitry Andric    _LIBCPP_CONSTEXPR
577936e9439SDimitry Andric        once_flag() _NOEXCEPT : __state_(0) {}
5787a984708SDavid Chisnall
5797a984708SDavid Chisnallprivate:
5807a984708SDavid Chisnall    once_flag(const once_flag&); // = delete;
5817a984708SDavid Chisnall    once_flag& operator=(const once_flag&); // = delete;
5827a984708SDavid Chisnall
5837a984708SDavid Chisnall    unsigned long __state_;
5847a984708SDavid Chisnall
585540d2a8bSDimitry Andric#ifndef _LIBCPP_CXX03_LANG
5867a984708SDavid Chisnall    template<class _Callable, class... _Args>
5877a984708SDavid Chisnall    friend
5887a984708SDavid Chisnall    void call_once(once_flag&, _Callable&&, _Args&&...);
589540d2a8bSDimitry Andric#else  // _LIBCPP_CXX03_LANG
5907a984708SDavid Chisnall    template<class _Callable>
5917a984708SDavid Chisnall    friend
592854fa44bSDimitry Andric    void call_once(once_flag&, _Callable&);
593854fa44bSDimitry Andric
594854fa44bSDimitry Andric    template<class _Callable>
595854fa44bSDimitry Andric    friend
596854fa44bSDimitry Andric    void call_once(once_flag&, const _Callable&);
597540d2a8bSDimitry Andric#endif  // _LIBCPP_CXX03_LANG
5987a984708SDavid Chisnall};
5997a984708SDavid Chisnall
600540d2a8bSDimitry Andric#ifndef _LIBCPP_CXX03_LANG
6017a984708SDavid Chisnall
60294e3ee44SDavid Chisnalltemplate <class _Fp>
6037a984708SDavid Chisnallclass __call_once_param
6047a984708SDavid Chisnall{
605854fa44bSDimitry Andric    _Fp& __f_;
6067a984708SDavid Chisnallpublic:
6077a984708SDavid Chisnall    _LIBCPP_INLINE_VISIBILITY
608854fa44bSDimitry Andric    explicit __call_once_param(_Fp& __f) : __f_(__f) {}
6097a984708SDavid Chisnall
6107a984708SDavid Chisnall    _LIBCPP_INLINE_VISIBILITY
6117a984708SDavid Chisnall    void operator()()
6127a984708SDavid Chisnall    {
61394e3ee44SDavid Chisnall        typedef typename __make_tuple_indices<tuple_size<_Fp>::value, 1>::type _Index;
6147a984708SDavid Chisnall        __execute(_Index());
6157a984708SDavid Chisnall    }
6167a984708SDavid Chisnall
6177a984708SDavid Chisnallprivate:
6187a984708SDavid Chisnall    template <size_t ..._Indices>
6197a984708SDavid Chisnall    _LIBCPP_INLINE_VISIBILITY
6207a984708SDavid Chisnall    void __execute(__tuple_indices<_Indices...>)
6217a984708SDavid Chisnall    {
622854fa44bSDimitry Andric        __invoke(_VSTD::get<0>(_VSTD::move(__f_)), _VSTD::get<_Indices>(_VSTD::move(__f_))...);
6237a984708SDavid Chisnall    }
6247a984708SDavid Chisnall};
6257a984708SDavid Chisnall
6267a984708SDavid Chisnall#else
6277a984708SDavid Chisnall
62894e3ee44SDavid Chisnalltemplate <class _Fp>
6297a984708SDavid Chisnallclass __call_once_param
6307a984708SDavid Chisnall{
631854fa44bSDimitry Andric    _Fp& __f_;
6327a984708SDavid Chisnallpublic:
6337a984708SDavid Chisnall    _LIBCPP_INLINE_VISIBILITY
634854fa44bSDimitry Andric    explicit __call_once_param(_Fp& __f) : __f_(__f) {}
6357a984708SDavid Chisnall
6367a984708SDavid Chisnall    _LIBCPP_INLINE_VISIBILITY
6377a984708SDavid Chisnall    void operator()()
6387a984708SDavid Chisnall    {
6397a984708SDavid Chisnall        __f_();
6407a984708SDavid Chisnall    }
6417a984708SDavid Chisnall};
6427a984708SDavid Chisnall
6437a984708SDavid Chisnall#endif
6447a984708SDavid Chisnall
64594e3ee44SDavid Chisnalltemplate <class _Fp>
6467a984708SDavid Chisnallvoid
6477a984708SDavid Chisnall__call_once_proxy(void* __vp)
6487a984708SDavid Chisnall{
64994e3ee44SDavid Chisnall    __call_once_param<_Fp>* __p = static_cast<__call_once_param<_Fp>*>(__vp);
6507a984708SDavid Chisnall    (*__p)();
6517a984708SDavid Chisnall}
6527a984708SDavid Chisnall
6534f7ab58eSDimitry Andric_LIBCPP_FUNC_VIS void __call_once(volatile unsigned long&, void*, void(*)(void*));
6547a984708SDavid Chisnall
655540d2a8bSDimitry Andric#ifndef _LIBCPP_CXX03_LANG
6567a984708SDavid Chisnall
6577a984708SDavid Chisnalltemplate<class _Callable, class... _Args>
6587a984708SDavid Chisnallinline _LIBCPP_INLINE_VISIBILITY
6597a984708SDavid Chisnallvoid
6607a984708SDavid Chisnallcall_once(once_flag& __flag, _Callable&& __func, _Args&&... __args)
6617a984708SDavid Chisnall{
662aed8d94eSDimitry Andric    if (__libcpp_acquire_load(&__flag.__state_) != ~0ul)
6637a984708SDavid Chisnall    {
664854fa44bSDimitry Andric        typedef tuple<_Callable&&, _Args&&...> _Gp;
665854fa44bSDimitry Andric        _Gp __f(_VSTD::forward<_Callable>(__func), _VSTD::forward<_Args>(__args)...);
666854fa44bSDimitry Andric        __call_once_param<_Gp> __p(__f);
66794e3ee44SDavid Chisnall        __call_once(__flag.__state_, &__p, &__call_once_proxy<_Gp>);
6687a984708SDavid Chisnall    }
6697a984708SDavid Chisnall}
6707a984708SDavid Chisnall
671540d2a8bSDimitry Andric#else  // _LIBCPP_CXX03_LANG
6727a984708SDavid Chisnall
6737a984708SDavid Chisnalltemplate<class _Callable>
6747a984708SDavid Chisnallinline _LIBCPP_INLINE_VISIBILITY
6757a984708SDavid Chisnallvoid
676854fa44bSDimitry Andriccall_once(once_flag& __flag, _Callable& __func)
6777a984708SDavid Chisnall{
678aed8d94eSDimitry Andric    if (__libcpp_acquire_load(&__flag.__state_) != ~0ul)
6797a984708SDavid Chisnall    {
6807a984708SDavid Chisnall        __call_once_param<_Callable> __p(__func);
6817a984708SDavid Chisnall        __call_once(__flag.__state_, &__p, &__call_once_proxy<_Callable>);
6827a984708SDavid Chisnall    }
6837a984708SDavid Chisnall}
6847a984708SDavid Chisnall
685854fa44bSDimitry Andrictemplate<class _Callable>
686854fa44bSDimitry Andricinline _LIBCPP_INLINE_VISIBILITY
687854fa44bSDimitry Andricvoid
688854fa44bSDimitry Andriccall_once(once_flag& __flag, const _Callable& __func)
689854fa44bSDimitry Andric{
69051690af2SDimitry Andric    if (__libcpp_acquire_load(&__flag.__state_) != ~0ul)
691854fa44bSDimitry Andric    {
692854fa44bSDimitry Andric        __call_once_param<const _Callable> __p(__func);
693854fa44bSDimitry Andric        __call_once(__flag.__state_, &__p, &__call_once_proxy<const _Callable>);
694854fa44bSDimitry Andric    }
695854fa44bSDimitry Andric}
696854fa44bSDimitry Andric
697540d2a8bSDimitry Andric#endif  // _LIBCPP_CXX03_LANG
6987c82a1ecSDimitry Andric
6997a984708SDavid Chisnall_LIBCPP_END_NAMESPACE_STD
7007a984708SDavid Chisnall
701f9448bf3SDimitry Andric_LIBCPP_POP_MACROS
702f9448bf3SDimitry Andric
7037a984708SDavid Chisnall#endif  // _LIBCPP_MUTEX
704