xref: /freebsd/contrib/llvm-project/libcxx/include/mutex (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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_MUTEX
110b57cec5SDimitry Andric#define _LIBCPP_MUTEX
120b57cec5SDimitry Andric
130b57cec5SDimitry Andric/*
140b57cec5SDimitry Andric    mutex synopsis
150b57cec5SDimitry Andric
160b57cec5SDimitry Andricnamespace std
170b57cec5SDimitry Andric{
180b57cec5SDimitry Andric
190b57cec5SDimitry Andricclass mutex
200b57cec5SDimitry Andric{
210b57cec5SDimitry Andricpublic:
220b57cec5SDimitry Andric     constexpr mutex() noexcept;
230b57cec5SDimitry Andric     ~mutex();
240b57cec5SDimitry Andric
250b57cec5SDimitry Andric    mutex(const mutex&) = delete;
260b57cec5SDimitry Andric    mutex& operator=(const mutex&) = delete;
270b57cec5SDimitry Andric
280b57cec5SDimitry Andric    void lock();
290b57cec5SDimitry Andric    bool try_lock();
300b57cec5SDimitry Andric    void unlock();
310b57cec5SDimitry Andric
320b57cec5SDimitry Andric    typedef pthread_mutex_t* native_handle_type;
330b57cec5SDimitry Andric    native_handle_type native_handle();
340b57cec5SDimitry Andric};
350b57cec5SDimitry Andric
360b57cec5SDimitry Andricclass recursive_mutex
370b57cec5SDimitry Andric{
380b57cec5SDimitry Andricpublic:
390b57cec5SDimitry Andric     recursive_mutex();
400b57cec5SDimitry Andric     ~recursive_mutex();
410b57cec5SDimitry Andric
420b57cec5SDimitry Andric    recursive_mutex(const recursive_mutex&) = delete;
430b57cec5SDimitry Andric    recursive_mutex& operator=(const recursive_mutex&) = delete;
440b57cec5SDimitry Andric
450b57cec5SDimitry Andric    void lock();
460b57cec5SDimitry Andric    bool try_lock() noexcept;
470b57cec5SDimitry Andric    void unlock();
480b57cec5SDimitry Andric
490b57cec5SDimitry Andric    typedef pthread_mutex_t* native_handle_type;
500b57cec5SDimitry Andric    native_handle_type native_handle();
510b57cec5SDimitry Andric};
520b57cec5SDimitry Andric
530b57cec5SDimitry Andricclass timed_mutex
540b57cec5SDimitry Andric{
550b57cec5SDimitry Andricpublic:
560b57cec5SDimitry Andric     timed_mutex();
570b57cec5SDimitry Andric     ~timed_mutex();
580b57cec5SDimitry Andric
590b57cec5SDimitry Andric    timed_mutex(const timed_mutex&) = delete;
600b57cec5SDimitry Andric    timed_mutex& operator=(const timed_mutex&) = delete;
610b57cec5SDimitry Andric
620b57cec5SDimitry Andric    void lock();
630b57cec5SDimitry Andric    bool try_lock();
640b57cec5SDimitry Andric    template <class Rep, class Period>
650b57cec5SDimitry Andric        bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
660b57cec5SDimitry Andric    template <class Clock, class Duration>
670b57cec5SDimitry Andric        bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
680b57cec5SDimitry Andric    void unlock();
690b57cec5SDimitry Andric};
700b57cec5SDimitry Andric
710b57cec5SDimitry Andricclass recursive_timed_mutex
720b57cec5SDimitry Andric{
730b57cec5SDimitry Andricpublic:
740b57cec5SDimitry Andric     recursive_timed_mutex();
750b57cec5SDimitry Andric     ~recursive_timed_mutex();
760b57cec5SDimitry Andric
770b57cec5SDimitry Andric    recursive_timed_mutex(const recursive_timed_mutex&) = delete;
780b57cec5SDimitry Andric    recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
790b57cec5SDimitry Andric
800b57cec5SDimitry Andric    void lock();
810b57cec5SDimitry Andric    bool try_lock() noexcept;
820b57cec5SDimitry Andric    template <class Rep, class Period>
830b57cec5SDimitry Andric        bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
840b57cec5SDimitry Andric    template <class Clock, class Duration>
850b57cec5SDimitry Andric        bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
860b57cec5SDimitry Andric    void unlock();
870b57cec5SDimitry Andric};
880b57cec5SDimitry Andric
89e40139ffSDimitry Andricstruct defer_lock_t { explicit defer_lock_t() = default; };
90e40139ffSDimitry Andricstruct try_to_lock_t { explicit try_to_lock_t() = default; };
91e40139ffSDimitry Andricstruct adopt_lock_t { explicit adopt_lock_t() = default; };
920b57cec5SDimitry Andric
930b57cec5SDimitry Andricinline constexpr defer_lock_t  defer_lock{};
940b57cec5SDimitry Andricinline constexpr try_to_lock_t try_to_lock{};
950b57cec5SDimitry Andricinline constexpr adopt_lock_t  adopt_lock{};
960b57cec5SDimitry Andric
970b57cec5SDimitry Andrictemplate <class Mutex>
980b57cec5SDimitry Andricclass lock_guard
990b57cec5SDimitry Andric{
1000b57cec5SDimitry Andricpublic:
1010b57cec5SDimitry Andric    typedef Mutex mutex_type;
1020b57cec5SDimitry Andric
1030b57cec5SDimitry Andric    explicit lock_guard(mutex_type& m);
1040b57cec5SDimitry Andric    lock_guard(mutex_type& m, adopt_lock_t);
1050b57cec5SDimitry Andric    ~lock_guard();
1060b57cec5SDimitry Andric
1070b57cec5SDimitry Andric    lock_guard(lock_guard const&) = delete;
1080b57cec5SDimitry Andric    lock_guard& operator=(lock_guard const&) = delete;
1090b57cec5SDimitry Andric};
1100b57cec5SDimitry Andric
1110b57cec5SDimitry Andrictemplate <class... MutexTypes>
1120b57cec5SDimitry Andricclass scoped_lock // C++17
1130b57cec5SDimitry Andric{
1140b57cec5SDimitry Andricpublic:
115349cc55cSDimitry Andric    using mutex_type = Mutex;  // Only if sizeof...(MutexTypes) == 1
1160b57cec5SDimitry Andric
1170b57cec5SDimitry Andric    explicit scoped_lock(MutexTypes&... m);
1180b57cec5SDimitry Andric    scoped_lock(adopt_lock_t, MutexTypes&... m);
1190b57cec5SDimitry Andric    ~scoped_lock();
1200b57cec5SDimitry Andric    scoped_lock(scoped_lock const&) = delete;
1210b57cec5SDimitry Andric    scoped_lock& operator=(scoped_lock const&) = delete;
1220b57cec5SDimitry Andricprivate:
1230b57cec5SDimitry Andric    tuple<MutexTypes&...> pm; // exposition only
1240b57cec5SDimitry Andric};
1250b57cec5SDimitry Andric
1260b57cec5SDimitry Andrictemplate <class Mutex>
1270b57cec5SDimitry Andricclass unique_lock
1280b57cec5SDimitry Andric{
1290b57cec5SDimitry Andricpublic:
1300b57cec5SDimitry Andric    typedef Mutex mutex_type;
1310b57cec5SDimitry Andric    unique_lock() noexcept;
1320b57cec5SDimitry Andric    explicit unique_lock(mutex_type& m);
1330b57cec5SDimitry Andric    unique_lock(mutex_type& m, defer_lock_t) noexcept;
1340b57cec5SDimitry Andric    unique_lock(mutex_type& m, try_to_lock_t);
1350b57cec5SDimitry Andric    unique_lock(mutex_type& m, adopt_lock_t);
1360b57cec5SDimitry Andric    template <class Clock, class Duration>
1370b57cec5SDimitry Andric        unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);
1380b57cec5SDimitry Andric    template <class Rep, class Period>
1390b57cec5SDimitry Andric        unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time);
1400b57cec5SDimitry Andric    ~unique_lock();
1410b57cec5SDimitry Andric
1420b57cec5SDimitry Andric    unique_lock(unique_lock const&) = delete;
1430b57cec5SDimitry Andric    unique_lock& operator=(unique_lock const&) = delete;
1440b57cec5SDimitry Andric
1450b57cec5SDimitry Andric    unique_lock(unique_lock&& u) noexcept;
1460b57cec5SDimitry Andric    unique_lock& operator=(unique_lock&& u) noexcept;
1470b57cec5SDimitry Andric
1480b57cec5SDimitry Andric    void lock();
1490b57cec5SDimitry Andric    bool try_lock();
1500b57cec5SDimitry Andric
1510b57cec5SDimitry Andric    template <class Rep, class Period>
1520b57cec5SDimitry Andric        bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
1530b57cec5SDimitry Andric    template <class Clock, class Duration>
1540b57cec5SDimitry Andric        bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
1550b57cec5SDimitry Andric
1560b57cec5SDimitry Andric    void unlock();
1570b57cec5SDimitry Andric
1580b57cec5SDimitry Andric    void swap(unique_lock& u) noexcept;
1590b57cec5SDimitry Andric    mutex_type* release() noexcept;
1600b57cec5SDimitry Andric
1610b57cec5SDimitry Andric    bool owns_lock() const noexcept;
1620b57cec5SDimitry Andric    explicit operator bool () const noexcept;
1630b57cec5SDimitry Andric    mutex_type* mutex() const noexcept;
1640b57cec5SDimitry Andric};
1650b57cec5SDimitry Andric
1660b57cec5SDimitry Andrictemplate <class Mutex>
1670b57cec5SDimitry Andric  void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept;
1680b57cec5SDimitry Andric
1690b57cec5SDimitry Andrictemplate <class L1, class L2, class... L3>
1700b57cec5SDimitry Andric  int try_lock(L1&, L2&, L3&...);
1710b57cec5SDimitry Andrictemplate <class L1, class L2, class... L3>
1720b57cec5SDimitry Andric  void lock(L1&, L2&, L3&...);
1730b57cec5SDimitry Andric
1740b57cec5SDimitry Andricstruct once_flag
1750b57cec5SDimitry Andric{
1760b57cec5SDimitry Andric    constexpr once_flag() noexcept;
1770b57cec5SDimitry Andric
1780b57cec5SDimitry Andric    once_flag(const once_flag&) = delete;
1790b57cec5SDimitry Andric    once_flag& operator=(const once_flag&) = delete;
1800b57cec5SDimitry Andric};
1810b57cec5SDimitry Andric
1820b57cec5SDimitry Andrictemplate<class Callable, class ...Args>
1830b57cec5SDimitry Andric  void call_once(once_flag& flag, Callable&& func, Args&&... args);
1840b57cec5SDimitry Andric
1850b57cec5SDimitry Andric}  // std
1860b57cec5SDimitry Andric
1870b57cec5SDimitry Andric*/
1880b57cec5SDimitry Andric
18906c3fb27SDimitry Andric#include <__chrono/steady_clock.h>
19006c3fb27SDimitry Andric#include <__chrono/time_point.h>
19106c3fb27SDimitry Andric#include <__condition_variable/condition_variable.h>
1920b57cec5SDimitry Andric#include <__config>
193bdd1243dSDimitry Andric#include <__memory/shared_ptr.h>
19406c3fb27SDimitry Andric#include <__mutex/lock_guard.h>
19506c3fb27SDimitry Andric#include <__mutex/mutex.h>
1965f757f3fSDimitry Andric#include <__mutex/once_flag.h>
19706c3fb27SDimitry Andric#include <__mutex/tag_types.h>
19806c3fb27SDimitry Andric#include <__mutex/unique_lock.h>
19906c3fb27SDimitry Andric#include <__thread/id.h>
200*0fca6ea1SDimitry Andric#include <__thread/support.h>
201fe6060f1SDimitry Andric#include <__utility/forward.h>
2025f757f3fSDimitry Andric#include <cstddef>
20306c3fb27SDimitry Andric#include <limits>
2040b57cec5SDimitry Andric#ifndef _LIBCPP_CXX03_LANG
2050b57cec5SDimitry Andric#  include <tuple>
2060b57cec5SDimitry Andric#endif
2070b57cec5SDimitry Andric#include <version>
2080b57cec5SDimitry Andric
2090b57cec5SDimitry Andric#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
2100b57cec5SDimitry Andric#  pragma GCC system_header
2110b57cec5SDimitry Andric#endif
2120b57cec5SDimitry Andric
2130b57cec5SDimitry Andric_LIBCPP_PUSH_MACROS
2140b57cec5SDimitry Andric#include <__undef_macros>
2150b57cec5SDimitry Andric
2160b57cec5SDimitry Andric_LIBCPP_BEGIN_NAMESPACE_STD
2170b57cec5SDimitry Andric
2180b57cec5SDimitry Andric#ifndef _LIBCPP_HAS_NO_THREADS
2190b57cec5SDimitry Andric
220cb14a3feSDimitry Andricclass _LIBCPP_EXPORTED_FROM_ABI recursive_mutex {
2210b57cec5SDimitry Andric  __libcpp_recursive_mutex_t __m_;
2220b57cec5SDimitry Andric
2230b57cec5SDimitry Andricpublic:
2240b57cec5SDimitry Andric  recursive_mutex();
2250b57cec5SDimitry Andric  ~recursive_mutex();
2260b57cec5SDimitry Andric
2270eae32dcSDimitry Andric  recursive_mutex(const recursive_mutex&)            = delete;
2280eae32dcSDimitry Andric  recursive_mutex& operator=(const recursive_mutex&) = delete;
2290b57cec5SDimitry Andric
2300b57cec5SDimitry Andric  void lock();
2310b57cec5SDimitry Andric  bool try_lock() _NOEXCEPT;
2320b57cec5SDimitry Andric  void unlock() _NOEXCEPT;
2330b57cec5SDimitry Andric
2340b57cec5SDimitry Andric  typedef __libcpp_recursive_mutex_t* native_handle_type;
2350b57cec5SDimitry Andric
236cb14a3feSDimitry Andric  _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return &__m_; }
2370b57cec5SDimitry Andric};
2380b57cec5SDimitry Andric
239cb14a3feSDimitry Andricclass _LIBCPP_EXPORTED_FROM_ABI timed_mutex {
2400b57cec5SDimitry Andric  mutex __m_;
2410b57cec5SDimitry Andric  condition_variable __cv_;
2420b57cec5SDimitry Andric  bool __locked_;
243cb14a3feSDimitry Andric
2440b57cec5SDimitry Andricpublic:
2450b57cec5SDimitry Andric  timed_mutex();
2460b57cec5SDimitry Andric  ~timed_mutex();
2470b57cec5SDimitry Andric
2480eae32dcSDimitry Andric  timed_mutex(const timed_mutex&)            = delete;
2490eae32dcSDimitry Andric  timed_mutex& operator=(const timed_mutex&) = delete;
2500b57cec5SDimitry Andric
2510b57cec5SDimitry Andricpublic:
2520b57cec5SDimitry Andric  void lock();
2530b57cec5SDimitry Andric  bool try_lock() _NOEXCEPT;
2540b57cec5SDimitry Andric  template <class _Rep, class _Period>
255cb14a3feSDimitry Andric  _LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __d) {
256cb14a3feSDimitry Andric    return try_lock_until(chrono::steady_clock::now() + __d);
257cb14a3feSDimitry Andric  }
2580b57cec5SDimitry Andric  template <class _Clock, class _Duration>
259cb14a3feSDimitry Andric  _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool
260cb14a3feSDimitry Andric  try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
2610b57cec5SDimitry Andric  void unlock() _NOEXCEPT;
2620b57cec5SDimitry Andric};
2630b57cec5SDimitry Andric
2640b57cec5SDimitry Andrictemplate <class _Clock, class _Duration>
265cb14a3feSDimitry Andricbool timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) {
2660b57cec5SDimitry Andric  using namespace chrono;
2670b57cec5SDimitry Andric  unique_lock<mutex> __lk(__m_);
26806c3fb27SDimitry Andric  bool __no_timeout = _Clock::now() < __t;
26906c3fb27SDimitry Andric  while (__no_timeout && __locked_)
27006c3fb27SDimitry Andric    __no_timeout = __cv_.wait_until(__lk, __t) == cv_status::no_timeout;
271cb14a3feSDimitry Andric  if (!__locked_) {
2720b57cec5SDimitry Andric    __locked_ = true;
2730b57cec5SDimitry Andric    return true;
2740b57cec5SDimitry Andric  }
2750b57cec5SDimitry Andric  return false;
2760b57cec5SDimitry Andric}
2770b57cec5SDimitry Andric
278cb14a3feSDimitry Andricclass _LIBCPP_EXPORTED_FROM_ABI recursive_timed_mutex {
2790b57cec5SDimitry Andric  mutex __m_;
2800b57cec5SDimitry Andric  condition_variable __cv_;
2810b57cec5SDimitry Andric  size_t __count_;
2820b57cec5SDimitry Andric  __thread_id __id_;
283cb14a3feSDimitry Andric
2840b57cec5SDimitry Andricpublic:
2850b57cec5SDimitry Andric  recursive_timed_mutex();
2860b57cec5SDimitry Andric  ~recursive_timed_mutex();
2870b57cec5SDimitry Andric
2880eae32dcSDimitry Andric  recursive_timed_mutex(const recursive_timed_mutex&)            = delete;
2890eae32dcSDimitry Andric  recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
2900b57cec5SDimitry Andric
2910b57cec5SDimitry Andric  void lock();
2920b57cec5SDimitry Andric  bool try_lock() _NOEXCEPT;
2930b57cec5SDimitry Andric  template <class _Rep, class _Period>
294cb14a3feSDimitry Andric  _LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __d) {
295cb14a3feSDimitry Andric    return try_lock_until(chrono::steady_clock::now() + __d);
296cb14a3feSDimitry Andric  }
2970b57cec5SDimitry Andric  template <class _Clock, class _Duration>
298cb14a3feSDimitry Andric  _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool
299cb14a3feSDimitry Andric  try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
3000b57cec5SDimitry Andric  void unlock() _NOEXCEPT;
3010b57cec5SDimitry Andric};
3020b57cec5SDimitry Andric
3030b57cec5SDimitry Andrictemplate <class _Clock, class _Duration>
304cb14a3feSDimitry Andricbool recursive_timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) {
3050b57cec5SDimitry Andric  using namespace chrono;
3060b57cec5SDimitry Andric  __thread_id __id = this_thread::get_id();
30706c3fb27SDimitry Andric  unique_lock<mutex> __lk(__m_);
308cb14a3feSDimitry Andric  if (__id == __id_) {
3090b57cec5SDimitry Andric    if (__count_ == numeric_limits<size_t>::max())
3100b57cec5SDimitry Andric      return false;
3110b57cec5SDimitry Andric    ++__count_;
3120b57cec5SDimitry Andric    return true;
3130b57cec5SDimitry Andric  }
31406c3fb27SDimitry Andric  bool __no_timeout = _Clock::now() < __t;
31506c3fb27SDimitry Andric  while (__no_timeout && __count_ != 0)
31606c3fb27SDimitry Andric    __no_timeout = __cv_.wait_until(__lk, __t) == cv_status::no_timeout;
317cb14a3feSDimitry Andric  if (__count_ == 0) {
3180b57cec5SDimitry Andric    __count_ = 1;
3190b57cec5SDimitry Andric    __id_    = __id;
3200b57cec5SDimitry Andric    return true;
3210b57cec5SDimitry Andric  }
3220b57cec5SDimitry Andric  return false;
3230b57cec5SDimitry Andric}
3240b57cec5SDimitry Andric
3250b57cec5SDimitry Andrictemplate <class _L0, class _L1>
326cb14a3feSDimitry Andric_LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1) {
32706c3fb27SDimitry Andric  unique_lock<_L0> __u0(__l0, try_to_lock_t());
328cb14a3feSDimitry Andric  if (__u0.owns_lock()) {
329cb14a3feSDimitry Andric    if (__l1.try_lock()) {
3300b57cec5SDimitry Andric      __u0.release();
3310b57cec5SDimitry Andric      return -1;
332cb14a3feSDimitry Andric    } else
3330b57cec5SDimitry Andric      return 1;
3340b57cec5SDimitry Andric  }
3350b57cec5SDimitry Andric  return 0;
3360b57cec5SDimitry Andric}
3370b57cec5SDimitry Andric
3380b57cec5SDimitry Andric#  ifndef _LIBCPP_CXX03_LANG
3390b57cec5SDimitry Andric
3400b57cec5SDimitry Andrictemplate <class _L0, class _L1, class _L2, class... _L3>
341cb14a3feSDimitry Andric_LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) {
3420b57cec5SDimitry Andric  int __r = 0;
3430b57cec5SDimitry Andric  unique_lock<_L0> __u0(__l0, try_to_lock);
344cb14a3feSDimitry Andric  if (__u0.owns_lock()) {
345bdd1243dSDimitry Andric    __r = std::try_lock(__l1, __l2, __l3...);
3460b57cec5SDimitry Andric    if (__r == -1)
3470b57cec5SDimitry Andric      __u0.release();
3480b57cec5SDimitry Andric    else
3490b57cec5SDimitry Andric      ++__r;
3500b57cec5SDimitry Andric  }
3510b57cec5SDimitry Andric  return __r;
3520b57cec5SDimitry Andric}
3530b57cec5SDimitry Andric
3540b57cec5SDimitry Andric#  endif // _LIBCPP_CXX03_LANG
3550b57cec5SDimitry Andric
3560b57cec5SDimitry Andrictemplate <class _L0, class _L1>
357cb14a3feSDimitry Andric_LIBCPP_HIDE_FROM_ABI void lock(_L0& __l0, _L1& __l1) {
358cb14a3feSDimitry Andric  while (true) {
3590b57cec5SDimitry Andric    {
3600b57cec5SDimitry Andric      unique_lock<_L0> __u0(__l0);
361cb14a3feSDimitry Andric      if (__l1.try_lock()) {
3620b57cec5SDimitry Andric        __u0.release();
3630b57cec5SDimitry Andric        break;
3640b57cec5SDimitry Andric      }
3650b57cec5SDimitry Andric    }
3660b57cec5SDimitry Andric    __libcpp_thread_yield();
3670b57cec5SDimitry Andric    {
3680b57cec5SDimitry Andric      unique_lock<_L1> __u1(__l1);
369cb14a3feSDimitry Andric      if (__l0.try_lock()) {
3700b57cec5SDimitry Andric        __u1.release();
3710b57cec5SDimitry Andric        break;
3720b57cec5SDimitry Andric      }
3730b57cec5SDimitry Andric    }
3740b57cec5SDimitry Andric    __libcpp_thread_yield();
3750b57cec5SDimitry Andric  }
3760b57cec5SDimitry Andric}
3770b57cec5SDimitry Andric
3780b57cec5SDimitry Andric#  ifndef _LIBCPP_CXX03_LANG
3790b57cec5SDimitry Andric
3800b57cec5SDimitry Andrictemplate <class _L0, class _L1, class _L2, class... _L3>
381cb14a3feSDimitry Andricvoid __lock_first(int __i, _L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) {
382cb14a3feSDimitry Andric  while (true) {
383cb14a3feSDimitry Andric    switch (__i) {
384cb14a3feSDimitry Andric    case 0: {
3850b57cec5SDimitry Andric      unique_lock<_L0> __u0(__l0);
386bdd1243dSDimitry Andric      __i = std::try_lock(__l1, __l2, __l3...);
387cb14a3feSDimitry Andric      if (__i == -1) {
3880b57cec5SDimitry Andric        __u0.release();
3890b57cec5SDimitry Andric        return;
3900b57cec5SDimitry Andric      }
3910b57cec5SDimitry Andric    }
3920b57cec5SDimitry Andric      ++__i;
3930b57cec5SDimitry Andric      __libcpp_thread_yield();
3940b57cec5SDimitry Andric      break;
395cb14a3feSDimitry Andric    case 1: {
3960b57cec5SDimitry Andric      unique_lock<_L1> __u1(__l1);
397bdd1243dSDimitry Andric      __i = std::try_lock(__l2, __l3..., __l0);
398cb14a3feSDimitry Andric      if (__i == -1) {
3990b57cec5SDimitry Andric        __u1.release();
4000b57cec5SDimitry Andric        return;
4010b57cec5SDimitry Andric      }
4020b57cec5SDimitry Andric    }
4030b57cec5SDimitry Andric      if (__i == sizeof...(_L3) + 1)
4040b57cec5SDimitry Andric        __i = 0;
4050b57cec5SDimitry Andric      else
4060b57cec5SDimitry Andric        __i += 2;
4070b57cec5SDimitry Andric      __libcpp_thread_yield();
4080b57cec5SDimitry Andric      break;
4090b57cec5SDimitry Andric    default:
410bdd1243dSDimitry Andric      std::__lock_first(__i - 2, __l2, __l3..., __l0, __l1);
4110b57cec5SDimitry Andric      return;
4120b57cec5SDimitry Andric    }
4130b57cec5SDimitry Andric  }
4140b57cec5SDimitry Andric}
4150b57cec5SDimitry Andric
4160b57cec5SDimitry Andrictemplate <class _L0, class _L1, class _L2, class... _L3>
417cb14a3feSDimitry Andricinline _LIBCPP_HIDE_FROM_ABI void lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) {
418bdd1243dSDimitry Andric  std::__lock_first(0, __l0, __l1, __l2, __l3...);
4190b57cec5SDimitry Andric}
4200b57cec5SDimitry Andric
4210b57cec5SDimitry Andric#  endif // _LIBCPP_CXX03_LANG
4220b57cec5SDimitry Andric
42306c3fb27SDimitry Andric#  if _LIBCPP_STD_VER >= 17
4240b57cec5SDimitry Andrictemplate <class... _Mutexes>
4250b57cec5SDimitry Andricclass _LIBCPP_TEMPLATE_VIS scoped_lock;
4260b57cec5SDimitry Andric
4270b57cec5SDimitry Andrictemplate <>
4280b57cec5SDimitry Andricclass _LIBCPP_TEMPLATE_VIS scoped_lock<> {
4290b57cec5SDimitry Andricpublic:
430*0fca6ea1SDimitry Andric  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit scoped_lock() {}
4310b57cec5SDimitry Andric  ~scoped_lock() = default;
4320b57cec5SDimitry Andric
433*0fca6ea1SDimitry Andric  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(adopt_lock_t) {}
4340b57cec5SDimitry Andric
4350b57cec5SDimitry Andric  scoped_lock(scoped_lock const&)            = delete;
4360b57cec5SDimitry Andric  scoped_lock& operator=(scoped_lock const&) = delete;
4370b57cec5SDimitry Andric};
4380b57cec5SDimitry Andric
4390b57cec5SDimitry Andrictemplate <class _Mutex>
4400b57cec5SDimitry Andricclass _LIBCPP_TEMPLATE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable) scoped_lock<_Mutex> {
4410b57cec5SDimitry Andricpublic:
4420b57cec5SDimitry Andric  typedef _Mutex mutex_type;
443cb14a3feSDimitry Andric
4440b57cec5SDimitry Andricprivate:
4450b57cec5SDimitry Andric  mutex_type& __m_;
446cb14a3feSDimitry Andric
4470b57cec5SDimitry Andricpublic:
448*0fca6ea1SDimitry Andric  [[nodiscard]]
449*0fca6ea1SDimitry Andric  _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(mutex_type& __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability(__m))
450*0fca6ea1SDimitry Andric      : __m_(__m) {
451cb14a3feSDimitry Andric    __m_.lock();
452cb14a3feSDimitry Andric  }
4530b57cec5SDimitry Andric
4540b57cec5SDimitry Andric  ~scoped_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) { __m_.unlock(); }
4550b57cec5SDimitry Andric
456*0fca6ea1SDimitry Andric  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(adopt_lock_t, mutex_type& __m)
457cb14a3feSDimitry Andric      _LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m))
4580b57cec5SDimitry Andric      : __m_(__m) {}
4590b57cec5SDimitry Andric
4600b57cec5SDimitry Andric  scoped_lock(scoped_lock const&)            = delete;
4610b57cec5SDimitry Andric  scoped_lock& operator=(scoped_lock const&) = delete;
4620b57cec5SDimitry Andric};
4630b57cec5SDimitry Andric
4640b57cec5SDimitry Andrictemplate <class... _MArgs>
465cb14a3feSDimitry Andricclass _LIBCPP_TEMPLATE_VIS scoped_lock {
4660b57cec5SDimitry Andric  static_assert(sizeof...(_MArgs) > 1, "At least 2 lock types required");
4670b57cec5SDimitry Andric  typedef tuple<_MArgs&...> _MutexTuple;
4680b57cec5SDimitry Andric
4690b57cec5SDimitry Andricpublic:
470*0fca6ea1SDimitry Andric  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(_MArgs&... __margs) : __t_(__margs...) {
471*0fca6ea1SDimitry Andric    std::lock(__margs...);
472*0fca6ea1SDimitry Andric  }
4730b57cec5SDimitry Andric
474*0fca6ea1SDimitry Andric  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI scoped_lock(adopt_lock_t, _MArgs&... __margs) : __t_(__margs...) {}
4750b57cec5SDimitry Andric
476cb14a3feSDimitry Andric  _LIBCPP_HIDE_FROM_ABI ~scoped_lock() {
4770b57cec5SDimitry Andric    typedef typename __make_tuple_indices<sizeof...(_MArgs)>::type _Indices;
4780b57cec5SDimitry Andric    __unlock_unpack(_Indices{}, __t_);
4790b57cec5SDimitry Andric  }
4800b57cec5SDimitry Andric
4810b57cec5SDimitry Andric  scoped_lock(scoped_lock const&)            = delete;
4820b57cec5SDimitry Andric  scoped_lock& operator=(scoped_lock const&) = delete;
4830b57cec5SDimitry Andric
4840b57cec5SDimitry Andricprivate:
4850b57cec5SDimitry Andric  template <size_t... _Indx>
486cb14a3feSDimitry Andric  _LIBCPP_HIDE_FROM_ABI static void __unlock_unpack(__tuple_indices<_Indx...>, _MutexTuple& __mt) {
487*0fca6ea1SDimitry Andric    (std::get<_Indx>(__mt).unlock(), ...);
4880b57cec5SDimitry Andric  }
4890b57cec5SDimitry Andric
4900b57cec5SDimitry Andric  _MutexTuple __t_;
4910b57cec5SDimitry Andric};
492bdd1243dSDimitry Andric_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(scoped_lock);
4930b57cec5SDimitry Andric
49406c3fb27SDimitry Andric#  endif // _LIBCPP_STD_VER >= 17
4950b57cec5SDimitry Andric#endif   // !_LIBCPP_HAS_NO_THREADS
4960b57cec5SDimitry Andric
4970b57cec5SDimitry Andric_LIBCPP_END_NAMESPACE_STD
4980b57cec5SDimitry Andric
4990b57cec5SDimitry Andric_LIBCPP_POP_MACROS
5000b57cec5SDimitry Andric
501bdd1243dSDimitry Andric#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
50206c3fb27SDimitry Andric#  include <atomic>
503bdd1243dSDimitry Andric#  include <concepts>
50406c3fb27SDimitry Andric#  include <cstdlib>
50506c3fb27SDimitry Andric#  include <cstring>
50606c3fb27SDimitry Andric#  include <ctime>
50706c3fb27SDimitry Andric#  include <initializer_list>
5085f757f3fSDimitry Andric#  include <iosfwd>
50906c3fb27SDimitry Andric#  include <new>
51006c3fb27SDimitry Andric#  include <stdexcept>
51106c3fb27SDimitry Andric#  include <system_error>
512bdd1243dSDimitry Andric#  include <type_traits>
51306c3fb27SDimitry Andric#  include <typeinfo>
514bdd1243dSDimitry Andric#endif
515bdd1243dSDimitry Andric
5160b57cec5SDimitry Andric#endif // _LIBCPP_MUTEX
517