xref: /netbsd-src/external/gpl3/gcc.old/dist/libstdc++-v3/include/std/mutex (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
11debfc3dSmrg// <mutex> -*- C++ -*-
21debfc3dSmrg
3*8feb0f0bSmrg// Copyright (C) 2003-2020 Free Software Foundation, Inc.
41debfc3dSmrg//
51debfc3dSmrg// This file is part of the GNU ISO C++ Library.  This library is free
61debfc3dSmrg// software; you can redistribute it and/or modify it under the
71debfc3dSmrg// terms of the GNU General Public License as published by the
81debfc3dSmrg// Free Software Foundation; either version 3, or (at your option)
91debfc3dSmrg// any later version.
101debfc3dSmrg
111debfc3dSmrg// This library is distributed in the hope that it will be useful,
121debfc3dSmrg// but WITHOUT ANY WARRANTY; without even the implied warranty of
131debfc3dSmrg// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
141debfc3dSmrg// GNU General Public License for more details.
151debfc3dSmrg
161debfc3dSmrg// Under Section 7 of GPL version 3, you are granted additional
171debfc3dSmrg// permissions described in the GCC Runtime Library Exception, version
181debfc3dSmrg// 3.1, as published by the Free Software Foundation.
191debfc3dSmrg
201debfc3dSmrg// You should have received a copy of the GNU General Public License and
211debfc3dSmrg// a copy of the GCC Runtime Library Exception along with this program;
221debfc3dSmrg// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
231debfc3dSmrg// <http://www.gnu.org/licenses/>.
241debfc3dSmrg
251debfc3dSmrg/** @file include/mutex
261debfc3dSmrg *  This is a Standard C++ Library header.
271debfc3dSmrg */
281debfc3dSmrg
291debfc3dSmrg#ifndef _GLIBCXX_MUTEX
301debfc3dSmrg#define _GLIBCXX_MUTEX 1
311debfc3dSmrg
321debfc3dSmrg#pragma GCC system_header
331debfc3dSmrg
341debfc3dSmrg#if __cplusplus < 201103L
351debfc3dSmrg# include <bits/c++0x_warning.h>
361debfc3dSmrg#else
371debfc3dSmrg
381debfc3dSmrg#include <tuple>
391debfc3dSmrg#include <chrono>
401debfc3dSmrg#include <exception>
411debfc3dSmrg#include <type_traits>
421debfc3dSmrg#include <system_error>
431debfc3dSmrg#include <bits/std_mutex.h>
44c0a68be4Smrg#include <bits/unique_lock.h>
451debfc3dSmrg#if ! _GTHREAD_USE_MUTEX_TIMEDLOCK
461debfc3dSmrg# include <condition_variable>
471debfc3dSmrg# include <thread>
481debfc3dSmrg#endif
491debfc3dSmrg#ifndef _GLIBCXX_HAVE_TLS
501debfc3dSmrg# include <bits/std_function.h>
511debfc3dSmrg#endif
521debfc3dSmrg
531debfc3dSmrgnamespace std _GLIBCXX_VISIBILITY(default)
541debfc3dSmrg{
551debfc3dSmrg_GLIBCXX_BEGIN_NAMESPACE_VERSION
561debfc3dSmrg
571debfc3dSmrg  /**
58*8feb0f0bSmrg   * @addtogroup mutexes
591debfc3dSmrg   * @{
601debfc3dSmrg   */
611debfc3dSmrg
621debfc3dSmrg#ifdef _GLIBCXX_HAS_GTHREADS
631debfc3dSmrg
641debfc3dSmrg  // Common base class for std::recursive_mutex and std::recursive_timed_mutex
651debfc3dSmrg  class __recursive_mutex_base
661debfc3dSmrg  {
671debfc3dSmrg  protected:
681debfc3dSmrg    typedef __gthread_recursive_mutex_t		__native_type;
691debfc3dSmrg
701debfc3dSmrg    __recursive_mutex_base(const __recursive_mutex_base&) = delete;
711debfc3dSmrg    __recursive_mutex_base& operator=(const __recursive_mutex_base&) = delete;
721debfc3dSmrg
731debfc3dSmrg#ifdef __GTHREAD_RECURSIVE_MUTEX_INIT
741debfc3dSmrg    __native_type  _M_mutex = __GTHREAD_RECURSIVE_MUTEX_INIT;
751debfc3dSmrg
761debfc3dSmrg    __recursive_mutex_base() = default;
771debfc3dSmrg#else
781debfc3dSmrg    __native_type  _M_mutex;
791debfc3dSmrg
801debfc3dSmrg    __recursive_mutex_base()
811debfc3dSmrg    {
821debfc3dSmrg      // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
831debfc3dSmrg      __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
841debfc3dSmrg    }
851debfc3dSmrg
861debfc3dSmrg    ~__recursive_mutex_base()
871debfc3dSmrg    { __gthread_recursive_mutex_destroy(&_M_mutex); }
881debfc3dSmrg#endif
891debfc3dSmrg  };
901debfc3dSmrg
911debfc3dSmrg  /// The standard recursive mutex type.
921debfc3dSmrg  class recursive_mutex : private __recursive_mutex_base
931debfc3dSmrg  {
941debfc3dSmrg  public:
951debfc3dSmrg    typedef __native_type* 			native_handle_type;
961debfc3dSmrg
971debfc3dSmrg    recursive_mutex() = default;
981debfc3dSmrg    ~recursive_mutex() = default;
991debfc3dSmrg
1001debfc3dSmrg    recursive_mutex(const recursive_mutex&) = delete;
1011debfc3dSmrg    recursive_mutex& operator=(const recursive_mutex&) = delete;
1021debfc3dSmrg
1031debfc3dSmrg    void
1041debfc3dSmrg    lock()
1051debfc3dSmrg    {
1061debfc3dSmrg      int __e = __gthread_recursive_mutex_lock(&_M_mutex);
1071debfc3dSmrg
1081debfc3dSmrg      // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
1091debfc3dSmrg      if (__e)
1101debfc3dSmrg	__throw_system_error(__e);
1111debfc3dSmrg    }
1121debfc3dSmrg
1131debfc3dSmrg    bool
1141debfc3dSmrg    try_lock() noexcept
1151debfc3dSmrg    {
1161debfc3dSmrg      // XXX EINVAL, EAGAIN, EBUSY
1171debfc3dSmrg      return !__gthread_recursive_mutex_trylock(&_M_mutex);
1181debfc3dSmrg    }
1191debfc3dSmrg
1201debfc3dSmrg    void
1211debfc3dSmrg    unlock()
1221debfc3dSmrg    {
1231debfc3dSmrg      // XXX EINVAL, EAGAIN, EBUSY
1241debfc3dSmrg      __gthread_recursive_mutex_unlock(&_M_mutex);
1251debfc3dSmrg    }
1261debfc3dSmrg
1271debfc3dSmrg    native_handle_type
1281debfc3dSmrg    native_handle() noexcept
1291debfc3dSmrg    { return &_M_mutex; }
1301debfc3dSmrg  };
1311debfc3dSmrg
1321debfc3dSmrg#if _GTHREAD_USE_MUTEX_TIMEDLOCK
1331debfc3dSmrg  template<typename _Derived>
1341debfc3dSmrg    class __timed_mutex_impl
1351debfc3dSmrg    {
1361debfc3dSmrg    protected:
1371debfc3dSmrg      template<typename _Rep, typename _Period>
1381debfc3dSmrg	bool
1391debfc3dSmrg	_M_try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
1401debfc3dSmrg	{
141*8feb0f0bSmrg#if _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK
142*8feb0f0bSmrg	  using __clock = chrono::steady_clock;
143*8feb0f0bSmrg#else
144*8feb0f0bSmrg	  using __clock = chrono::system_clock;
145*8feb0f0bSmrg#endif
146*8feb0f0bSmrg
147*8feb0f0bSmrg	  auto __rt = chrono::duration_cast<__clock::duration>(__rtime);
148*8feb0f0bSmrg	  if (ratio_greater<__clock::period, _Period>())
1491debfc3dSmrg	    ++__rt;
150*8feb0f0bSmrg	  return _M_try_lock_until(__clock::now() + __rt);
1511debfc3dSmrg	}
1521debfc3dSmrg
1531debfc3dSmrg      template<typename _Duration>
1541debfc3dSmrg	bool
155*8feb0f0bSmrg	_M_try_lock_until(const chrono::time_point<chrono::system_clock,
1561debfc3dSmrg						   _Duration>& __atime)
1571debfc3dSmrg	{
1581debfc3dSmrg	  auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
1591debfc3dSmrg	  auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
1601debfc3dSmrg
1611debfc3dSmrg	  __gthread_time_t __ts = {
1621debfc3dSmrg	    static_cast<std::time_t>(__s.time_since_epoch().count()),
1631debfc3dSmrg	    static_cast<long>(__ns.count())
1641debfc3dSmrg	  };
1651debfc3dSmrg
1661debfc3dSmrg	  return static_cast<_Derived*>(this)->_M_timedlock(__ts);
1671debfc3dSmrg	}
1681debfc3dSmrg
169*8feb0f0bSmrg#ifdef _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK
170*8feb0f0bSmrg      template<typename _Duration>
171*8feb0f0bSmrg	bool
172*8feb0f0bSmrg	_M_try_lock_until(const chrono::time_point<chrono::steady_clock,
173*8feb0f0bSmrg						   _Duration>& __atime)
174*8feb0f0bSmrg	{
175*8feb0f0bSmrg	  auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
176*8feb0f0bSmrg	  auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
177*8feb0f0bSmrg
178*8feb0f0bSmrg	  __gthread_time_t __ts = {
179*8feb0f0bSmrg	    static_cast<std::time_t>(__s.time_since_epoch().count()),
180*8feb0f0bSmrg	    static_cast<long>(__ns.count())
181*8feb0f0bSmrg	  };
182*8feb0f0bSmrg
183*8feb0f0bSmrg	  return static_cast<_Derived*>(this)->_M_clocklock(CLOCK_MONOTONIC,
184*8feb0f0bSmrg							    __ts);
185*8feb0f0bSmrg	}
186*8feb0f0bSmrg#endif
187*8feb0f0bSmrg
1881debfc3dSmrg      template<typename _Clock, typename _Duration>
1891debfc3dSmrg	bool
1901debfc3dSmrg	_M_try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
1911debfc3dSmrg	{
192*8feb0f0bSmrg#if __cplusplus > 201703L
193*8feb0f0bSmrg	  static_assert(chrono::is_clock_v<_Clock>);
194*8feb0f0bSmrg#endif
195*8feb0f0bSmrg	  // The user-supplied clock may not tick at the same rate as
196*8feb0f0bSmrg	  // steady_clock, so we must loop in order to guarantee that
197*8feb0f0bSmrg	  // the timeout has expired before returning false.
198*8feb0f0bSmrg	  auto __now = _Clock::now();
199*8feb0f0bSmrg	  do {
200*8feb0f0bSmrg	    auto __rtime = __atime - __now;
201*8feb0f0bSmrg	    if (_M_try_lock_for(__rtime))
202*8feb0f0bSmrg	      return true;
203*8feb0f0bSmrg	    __now = _Clock::now();
204*8feb0f0bSmrg	  } while (__atime > __now);
205*8feb0f0bSmrg	  return false;
2061debfc3dSmrg	}
2071debfc3dSmrg    };
2081debfc3dSmrg
2091debfc3dSmrg  /// The standard timed mutex type.
2101debfc3dSmrg  class timed_mutex
2111debfc3dSmrg  : private __mutex_base, public __timed_mutex_impl<timed_mutex>
2121debfc3dSmrg  {
2131debfc3dSmrg  public:
2141debfc3dSmrg    typedef __native_type* 		  	native_handle_type;
2151debfc3dSmrg
2161debfc3dSmrg    timed_mutex() = default;
2171debfc3dSmrg    ~timed_mutex() = default;
2181debfc3dSmrg
2191debfc3dSmrg    timed_mutex(const timed_mutex&) = delete;
2201debfc3dSmrg    timed_mutex& operator=(const timed_mutex&) = delete;
2211debfc3dSmrg
2221debfc3dSmrg    void
2231debfc3dSmrg    lock()
2241debfc3dSmrg    {
2251debfc3dSmrg      int __e = __gthread_mutex_lock(&_M_mutex);
2261debfc3dSmrg
2271debfc3dSmrg      // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
2281debfc3dSmrg      if (__e)
2291debfc3dSmrg	__throw_system_error(__e);
2301debfc3dSmrg    }
2311debfc3dSmrg
2321debfc3dSmrg    bool
2331debfc3dSmrg    try_lock() noexcept
2341debfc3dSmrg    {
2351debfc3dSmrg      // XXX EINVAL, EAGAIN, EBUSY
2361debfc3dSmrg      return !__gthread_mutex_trylock(&_M_mutex);
2371debfc3dSmrg    }
2381debfc3dSmrg
2391debfc3dSmrg    template <class _Rep, class _Period>
2401debfc3dSmrg      bool
2411debfc3dSmrg      try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
2421debfc3dSmrg      { return _M_try_lock_for(__rtime); }
2431debfc3dSmrg
2441debfc3dSmrg    template <class _Clock, class _Duration>
2451debfc3dSmrg      bool
2461debfc3dSmrg      try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
2471debfc3dSmrg      { return _M_try_lock_until(__atime); }
2481debfc3dSmrg
2491debfc3dSmrg    void
2501debfc3dSmrg    unlock()
2511debfc3dSmrg    {
2521debfc3dSmrg      // XXX EINVAL, EAGAIN, EBUSY
2531debfc3dSmrg      __gthread_mutex_unlock(&_M_mutex);
2541debfc3dSmrg    }
2551debfc3dSmrg
2561debfc3dSmrg    native_handle_type
2571debfc3dSmrg    native_handle() noexcept
2581debfc3dSmrg    { return &_M_mutex; }
2591debfc3dSmrg
2601debfc3dSmrg    private:
2611debfc3dSmrg      friend class __timed_mutex_impl<timed_mutex>;
2621debfc3dSmrg
2631debfc3dSmrg      bool
2641debfc3dSmrg      _M_timedlock(const __gthread_time_t& __ts)
2651debfc3dSmrg      { return !__gthread_mutex_timedlock(&_M_mutex, &__ts); }
266*8feb0f0bSmrg
267*8feb0f0bSmrg#if _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK
268*8feb0f0bSmrg      bool
269*8feb0f0bSmrg      _M_clocklock(clockid_t clockid, const __gthread_time_t& __ts)
270*8feb0f0bSmrg      { return !pthread_mutex_clocklock(&_M_mutex, clockid, &__ts); }
271*8feb0f0bSmrg#endif
2721debfc3dSmrg  };
2731debfc3dSmrg
2741debfc3dSmrg  /// recursive_timed_mutex
2751debfc3dSmrg  class recursive_timed_mutex
2761debfc3dSmrg  : private __recursive_mutex_base,
2771debfc3dSmrg    public __timed_mutex_impl<recursive_timed_mutex>
2781debfc3dSmrg  {
2791debfc3dSmrg  public:
2801debfc3dSmrg    typedef __native_type* 			native_handle_type;
2811debfc3dSmrg
2821debfc3dSmrg    recursive_timed_mutex() = default;
2831debfc3dSmrg    ~recursive_timed_mutex() = default;
2841debfc3dSmrg
2851debfc3dSmrg    recursive_timed_mutex(const recursive_timed_mutex&) = delete;
2861debfc3dSmrg    recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
2871debfc3dSmrg
2881debfc3dSmrg    void
2891debfc3dSmrg    lock()
2901debfc3dSmrg    {
2911debfc3dSmrg      int __e = __gthread_recursive_mutex_lock(&_M_mutex);
2921debfc3dSmrg
2931debfc3dSmrg      // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
2941debfc3dSmrg      if (__e)
2951debfc3dSmrg	__throw_system_error(__e);
2961debfc3dSmrg    }
2971debfc3dSmrg
2981debfc3dSmrg    bool
2991debfc3dSmrg    try_lock() noexcept
3001debfc3dSmrg    {
3011debfc3dSmrg      // XXX EINVAL, EAGAIN, EBUSY
3021debfc3dSmrg      return !__gthread_recursive_mutex_trylock(&_M_mutex);
3031debfc3dSmrg    }
3041debfc3dSmrg
3051debfc3dSmrg    template <class _Rep, class _Period>
3061debfc3dSmrg      bool
3071debfc3dSmrg      try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
3081debfc3dSmrg      { return _M_try_lock_for(__rtime); }
3091debfc3dSmrg
3101debfc3dSmrg    template <class _Clock, class _Duration>
3111debfc3dSmrg      bool
3121debfc3dSmrg      try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
3131debfc3dSmrg      { return _M_try_lock_until(__atime); }
3141debfc3dSmrg
3151debfc3dSmrg    void
3161debfc3dSmrg    unlock()
3171debfc3dSmrg    {
3181debfc3dSmrg      // XXX EINVAL, EAGAIN, EBUSY
3191debfc3dSmrg      __gthread_recursive_mutex_unlock(&_M_mutex);
3201debfc3dSmrg    }
3211debfc3dSmrg
3221debfc3dSmrg    native_handle_type
3231debfc3dSmrg    native_handle() noexcept
3241debfc3dSmrg    { return &_M_mutex; }
3251debfc3dSmrg
3261debfc3dSmrg    private:
3271debfc3dSmrg      friend class __timed_mutex_impl<recursive_timed_mutex>;
3281debfc3dSmrg
3291debfc3dSmrg      bool
3301debfc3dSmrg      _M_timedlock(const __gthread_time_t& __ts)
3311debfc3dSmrg      { return !__gthread_recursive_mutex_timedlock(&_M_mutex, &__ts); }
332*8feb0f0bSmrg
333*8feb0f0bSmrg#ifdef _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK
334*8feb0f0bSmrg      bool
335*8feb0f0bSmrg      _M_clocklock(clockid_t clockid, const __gthread_time_t& __ts)
336*8feb0f0bSmrg      { return !pthread_mutex_clocklock(&_M_mutex, clockid, &__ts); }
337*8feb0f0bSmrg#endif
3381debfc3dSmrg  };
3391debfc3dSmrg
3401debfc3dSmrg#else // !_GTHREAD_USE_MUTEX_TIMEDLOCK
3411debfc3dSmrg
3421debfc3dSmrg  /// timed_mutex
3431debfc3dSmrg  class timed_mutex
3441debfc3dSmrg  {
3451debfc3dSmrg    mutex		_M_mut;
3461debfc3dSmrg    condition_variable	_M_cv;
3471debfc3dSmrg    bool		_M_locked = false;
3481debfc3dSmrg
3491debfc3dSmrg  public:
3501debfc3dSmrg
3511debfc3dSmrg    timed_mutex() = default;
3521debfc3dSmrg    ~timed_mutex() { __glibcxx_assert( !_M_locked ); }
3531debfc3dSmrg
3541debfc3dSmrg    timed_mutex(const timed_mutex&) = delete;
3551debfc3dSmrg    timed_mutex& operator=(const timed_mutex&) = delete;
3561debfc3dSmrg
3571debfc3dSmrg    void
3581debfc3dSmrg    lock()
3591debfc3dSmrg    {
3601debfc3dSmrg      unique_lock<mutex> __lk(_M_mut);
3611debfc3dSmrg      _M_cv.wait(__lk, [&]{ return !_M_locked; });
3621debfc3dSmrg      _M_locked = true;
3631debfc3dSmrg    }
3641debfc3dSmrg
3651debfc3dSmrg    bool
3661debfc3dSmrg    try_lock()
3671debfc3dSmrg    {
3681debfc3dSmrg      lock_guard<mutex> __lk(_M_mut);
3691debfc3dSmrg      if (_M_locked)
3701debfc3dSmrg	return false;
3711debfc3dSmrg      _M_locked = true;
3721debfc3dSmrg      return true;
3731debfc3dSmrg    }
3741debfc3dSmrg
3751debfc3dSmrg    template<typename _Rep, typename _Period>
3761debfc3dSmrg      bool
3771debfc3dSmrg      try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
3781debfc3dSmrg      {
3791debfc3dSmrg	unique_lock<mutex> __lk(_M_mut);
3801debfc3dSmrg	if (!_M_cv.wait_for(__lk, __rtime, [&]{ return !_M_locked; }))
3811debfc3dSmrg	  return false;
3821debfc3dSmrg	_M_locked = true;
3831debfc3dSmrg	return true;
3841debfc3dSmrg      }
3851debfc3dSmrg
3861debfc3dSmrg    template<typename _Clock, typename _Duration>
3871debfc3dSmrg      bool
3881debfc3dSmrg      try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
3891debfc3dSmrg      {
3901debfc3dSmrg	unique_lock<mutex> __lk(_M_mut);
3911debfc3dSmrg	if (!_M_cv.wait_until(__lk, __atime, [&]{ return !_M_locked; }))
3921debfc3dSmrg	  return false;
3931debfc3dSmrg	_M_locked = true;
3941debfc3dSmrg	return true;
3951debfc3dSmrg      }
3961debfc3dSmrg
3971debfc3dSmrg    void
3981debfc3dSmrg    unlock()
3991debfc3dSmrg    {
4001debfc3dSmrg      lock_guard<mutex> __lk(_M_mut);
4011debfc3dSmrg      __glibcxx_assert( _M_locked );
4021debfc3dSmrg      _M_locked = false;
4031debfc3dSmrg      _M_cv.notify_one();
4041debfc3dSmrg    }
4051debfc3dSmrg  };
4061debfc3dSmrg
4071debfc3dSmrg  /// recursive_timed_mutex
4081debfc3dSmrg  class recursive_timed_mutex
4091debfc3dSmrg  {
4101debfc3dSmrg    mutex		_M_mut;
4111debfc3dSmrg    condition_variable	_M_cv;
4121debfc3dSmrg    thread::id		_M_owner;
4131debfc3dSmrg    unsigned		_M_count = 0;
4141debfc3dSmrg
4151debfc3dSmrg    // Predicate type that tests whether the current thread can lock a mutex.
4161debfc3dSmrg    struct _Can_lock
4171debfc3dSmrg    {
4181debfc3dSmrg      // Returns true if the mutex is unlocked or is locked by _M_caller.
4191debfc3dSmrg      bool
4201debfc3dSmrg      operator()() const noexcept
4211debfc3dSmrg      { return _M_mx->_M_count == 0 || _M_mx->_M_owner == _M_caller; }
4221debfc3dSmrg
4231debfc3dSmrg      const recursive_timed_mutex* _M_mx;
4241debfc3dSmrg      thread::id _M_caller;
4251debfc3dSmrg    };
4261debfc3dSmrg
4271debfc3dSmrg  public:
4281debfc3dSmrg
4291debfc3dSmrg    recursive_timed_mutex() = default;
4301debfc3dSmrg    ~recursive_timed_mutex() { __glibcxx_assert( _M_count == 0 ); }
4311debfc3dSmrg
4321debfc3dSmrg    recursive_timed_mutex(const recursive_timed_mutex&) = delete;
4331debfc3dSmrg    recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
4341debfc3dSmrg
4351debfc3dSmrg    void
4361debfc3dSmrg    lock()
4371debfc3dSmrg    {
4381debfc3dSmrg      auto __id = this_thread::get_id();
4391debfc3dSmrg      _Can_lock __can_lock{this, __id};
4401debfc3dSmrg      unique_lock<mutex> __lk(_M_mut);
4411debfc3dSmrg      _M_cv.wait(__lk, __can_lock);
4421debfc3dSmrg      if (_M_count == -1u)
4431debfc3dSmrg	__throw_system_error(EAGAIN); // [thread.timedmutex.recursive]/3
4441debfc3dSmrg      _M_owner = __id;
4451debfc3dSmrg      ++_M_count;
4461debfc3dSmrg    }
4471debfc3dSmrg
4481debfc3dSmrg    bool
4491debfc3dSmrg    try_lock()
4501debfc3dSmrg    {
4511debfc3dSmrg      auto __id = this_thread::get_id();
4521debfc3dSmrg      _Can_lock __can_lock{this, __id};
4531debfc3dSmrg      lock_guard<mutex> __lk(_M_mut);
4541debfc3dSmrg      if (!__can_lock())
4551debfc3dSmrg	return false;
4561debfc3dSmrg      if (_M_count == -1u)
4571debfc3dSmrg	return false;
4581debfc3dSmrg      _M_owner = __id;
4591debfc3dSmrg      ++_M_count;
4601debfc3dSmrg      return true;
4611debfc3dSmrg    }
4621debfc3dSmrg
4631debfc3dSmrg    template<typename _Rep, typename _Period>
4641debfc3dSmrg      bool
4651debfc3dSmrg      try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
4661debfc3dSmrg      {
4671debfc3dSmrg	auto __id = this_thread::get_id();
4681debfc3dSmrg	_Can_lock __can_lock{this, __id};
4691debfc3dSmrg	unique_lock<mutex> __lk(_M_mut);
4701debfc3dSmrg	if (!_M_cv.wait_for(__lk, __rtime, __can_lock))
4711debfc3dSmrg	  return false;
4721debfc3dSmrg	if (_M_count == -1u)
4731debfc3dSmrg	  return false;
4741debfc3dSmrg	_M_owner = __id;
4751debfc3dSmrg	++_M_count;
4761debfc3dSmrg	return true;
4771debfc3dSmrg      }
4781debfc3dSmrg
4791debfc3dSmrg    template<typename _Clock, typename _Duration>
4801debfc3dSmrg      bool
4811debfc3dSmrg      try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
4821debfc3dSmrg      {
4831debfc3dSmrg	auto __id = this_thread::get_id();
4841debfc3dSmrg	_Can_lock __can_lock{this, __id};
4851debfc3dSmrg	unique_lock<mutex> __lk(_M_mut);
4861debfc3dSmrg	if (!_M_cv.wait_until(__lk, __atime, __can_lock))
4871debfc3dSmrg	  return false;
4881debfc3dSmrg	if (_M_count == -1u)
4891debfc3dSmrg	  return false;
4901debfc3dSmrg	_M_owner = __id;
4911debfc3dSmrg	++_M_count;
4921debfc3dSmrg	return true;
4931debfc3dSmrg      }
4941debfc3dSmrg
4951debfc3dSmrg    void
4961debfc3dSmrg    unlock()
4971debfc3dSmrg    {
4981debfc3dSmrg      lock_guard<mutex> __lk(_M_mut);
4991debfc3dSmrg      __glibcxx_assert( _M_owner == this_thread::get_id() );
5001debfc3dSmrg      __glibcxx_assert( _M_count > 0 );
5011debfc3dSmrg      if (--_M_count == 0)
5021debfc3dSmrg	{
5031debfc3dSmrg	  _M_owner = {};
5041debfc3dSmrg	  _M_cv.notify_one();
5051debfc3dSmrg	}
5061debfc3dSmrg    }
5071debfc3dSmrg  };
5081debfc3dSmrg
5091debfc3dSmrg#endif
5101debfc3dSmrg#endif // _GLIBCXX_HAS_GTHREADS
5111debfc3dSmrg
512*8feb0f0bSmrg  /// @cond undocumented
5131debfc3dSmrg  template<typename _Lock>
5141debfc3dSmrg    inline unique_lock<_Lock>
5151debfc3dSmrg    __try_to_lock(_Lock& __l)
5161debfc3dSmrg    { return unique_lock<_Lock>{__l, try_to_lock}; }
5171debfc3dSmrg
5181debfc3dSmrg  template<int _Idx, bool _Continue = true>
5191debfc3dSmrg    struct __try_lock_impl
5201debfc3dSmrg    {
5211debfc3dSmrg      template<typename... _Lock>
5221debfc3dSmrg	static void
5231debfc3dSmrg	__do_try_lock(tuple<_Lock&...>& __locks, int& __idx)
5241debfc3dSmrg	{
5251debfc3dSmrg          __idx = _Idx;
5261debfc3dSmrg          auto __lock = std::__try_to_lock(std::get<_Idx>(__locks));
5271debfc3dSmrg          if (__lock.owns_lock())
5281debfc3dSmrg            {
5291debfc3dSmrg	      constexpr bool __cont = _Idx + 2 < sizeof...(_Lock);
5301debfc3dSmrg	      using __try_locker = __try_lock_impl<_Idx + 1, __cont>;
5311debfc3dSmrg	      __try_locker::__do_try_lock(__locks, __idx);
5321debfc3dSmrg              if (__idx == -1)
5331debfc3dSmrg                __lock.release();
5341debfc3dSmrg            }
5351debfc3dSmrg	}
5361debfc3dSmrg    };
5371debfc3dSmrg
5381debfc3dSmrg  template<int _Idx>
5391debfc3dSmrg    struct __try_lock_impl<_Idx, false>
5401debfc3dSmrg    {
5411debfc3dSmrg      template<typename... _Lock>
5421debfc3dSmrg	static void
5431debfc3dSmrg	__do_try_lock(tuple<_Lock&...>& __locks, int& __idx)
5441debfc3dSmrg	{
5451debfc3dSmrg          __idx = _Idx;
5461debfc3dSmrg          auto __lock = std::__try_to_lock(std::get<_Idx>(__locks));
5471debfc3dSmrg          if (__lock.owns_lock())
5481debfc3dSmrg            {
5491debfc3dSmrg              __idx = -1;
5501debfc3dSmrg              __lock.release();
5511debfc3dSmrg            }
5521debfc3dSmrg	}
5531debfc3dSmrg    };
554*8feb0f0bSmrg  /// @endcond
5551debfc3dSmrg
5561debfc3dSmrg  /** @brief Generic try_lock.
557a2dc1f3fSmrg   *  @param __l1 Meets Lockable requirements (try_lock() may throw).
558a2dc1f3fSmrg   *  @param __l2 Meets Lockable requirements (try_lock() may throw).
559a2dc1f3fSmrg   *  @param __l3 Meets Lockable requirements (try_lock() may throw).
5601debfc3dSmrg   *  @return Returns -1 if all try_lock() calls return true. Otherwise returns
5611debfc3dSmrg   *          a 0-based index corresponding to the argument that returned false.
5621debfc3dSmrg   *  @post Either all arguments are locked, or none will be.
5631debfc3dSmrg   *
5641debfc3dSmrg   *  Sequentially calls try_lock() on each argument.
5651debfc3dSmrg   */
5661debfc3dSmrg  template<typename _Lock1, typename _Lock2, typename... _Lock3>
5671debfc3dSmrg    int
5681debfc3dSmrg    try_lock(_Lock1& __l1, _Lock2& __l2, _Lock3&... __l3)
5691debfc3dSmrg    {
5701debfc3dSmrg      int __idx;
5711debfc3dSmrg      auto __locks = std::tie(__l1, __l2, __l3...);
5721debfc3dSmrg      __try_lock_impl<0>::__do_try_lock(__locks, __idx);
5731debfc3dSmrg      return __idx;
5741debfc3dSmrg    }
5751debfc3dSmrg
5761debfc3dSmrg  /** @brief Generic lock.
577a2dc1f3fSmrg   *  @param __l1 Meets Lockable requirements (try_lock() may throw).
578a2dc1f3fSmrg   *  @param __l2 Meets Lockable requirements (try_lock() may throw).
579a2dc1f3fSmrg   *  @param __l3 Meets Lockable requirements (try_lock() may throw).
5801debfc3dSmrg   *  @throw An exception thrown by an argument's lock() or try_lock() member.
5811debfc3dSmrg   *  @post All arguments are locked.
5821debfc3dSmrg   *
5831debfc3dSmrg   *  All arguments are locked via a sequence of calls to lock(), try_lock()
5841debfc3dSmrg   *  and unlock().  If the call exits via an exception any locks that were
5851debfc3dSmrg   *  obtained will be released.
5861debfc3dSmrg   */
5871debfc3dSmrg  template<typename _L1, typename _L2, typename... _L3>
5881debfc3dSmrg    void
5891debfc3dSmrg    lock(_L1& __l1, _L2& __l2, _L3&... __l3)
5901debfc3dSmrg    {
5911debfc3dSmrg      while (true)
5921debfc3dSmrg        {
5931debfc3dSmrg          using __try_locker = __try_lock_impl<0, sizeof...(_L3) != 0>;
5941debfc3dSmrg          unique_lock<_L1> __first(__l1);
5951debfc3dSmrg          int __idx;
5961debfc3dSmrg          auto __locks = std::tie(__l2, __l3...);
5971debfc3dSmrg          __try_locker::__do_try_lock(__locks, __idx);
5981debfc3dSmrg          if (__idx == -1)
5991debfc3dSmrg            {
6001debfc3dSmrg              __first.release();
6011debfc3dSmrg              return;
6021debfc3dSmrg            }
6031debfc3dSmrg        }
6041debfc3dSmrg    }
6051debfc3dSmrg
6061debfc3dSmrg#if __cplusplus >= 201703L
6071debfc3dSmrg#define __cpp_lib_scoped_lock 201703
6081debfc3dSmrg  /** @brief A scoped lock type for multiple lockable objects.
6091debfc3dSmrg   *
6101debfc3dSmrg   * A scoped_lock controls mutex ownership within a scope, releasing
6111debfc3dSmrg   * ownership in the destructor.
6121debfc3dSmrg   */
6131debfc3dSmrg  template<typename... _MutexTypes>
6141debfc3dSmrg    class scoped_lock
6151debfc3dSmrg    {
6161debfc3dSmrg    public:
6171debfc3dSmrg      explicit scoped_lock(_MutexTypes&... __m) : _M_devices(std::tie(__m...))
6181debfc3dSmrg      { std::lock(__m...); }
6191debfc3dSmrg
6201debfc3dSmrg      explicit scoped_lock(adopt_lock_t, _MutexTypes&... __m) noexcept
6211debfc3dSmrg      : _M_devices(std::tie(__m...))
6221debfc3dSmrg      { } // calling thread owns mutex
6231debfc3dSmrg
6241debfc3dSmrg      ~scoped_lock()
625*8feb0f0bSmrg      { std::apply([](auto&... __m) { (__m.unlock(), ...); }, _M_devices); }
6261debfc3dSmrg
6271debfc3dSmrg      scoped_lock(const scoped_lock&) = delete;
6281debfc3dSmrg      scoped_lock& operator=(const scoped_lock&) = delete;
6291debfc3dSmrg
6301debfc3dSmrg    private:
6311debfc3dSmrg      tuple<_MutexTypes&...> _M_devices;
6321debfc3dSmrg    };
6331debfc3dSmrg
6341debfc3dSmrg  template<>
6351debfc3dSmrg    class scoped_lock<>
6361debfc3dSmrg    {
6371debfc3dSmrg    public:
6381debfc3dSmrg      explicit scoped_lock() = default;
6391debfc3dSmrg      explicit scoped_lock(adopt_lock_t) noexcept { }
6401debfc3dSmrg      ~scoped_lock() = default;
6411debfc3dSmrg
6421debfc3dSmrg      scoped_lock(const scoped_lock&) = delete;
6431debfc3dSmrg      scoped_lock& operator=(const scoped_lock&) = delete;
6441debfc3dSmrg    };
6451debfc3dSmrg
6461debfc3dSmrg  template<typename _Mutex>
6471debfc3dSmrg    class scoped_lock<_Mutex>
6481debfc3dSmrg    {
6491debfc3dSmrg    public:
6501debfc3dSmrg      using mutex_type = _Mutex;
6511debfc3dSmrg
6521debfc3dSmrg      explicit scoped_lock(mutex_type& __m) : _M_device(__m)
6531debfc3dSmrg      { _M_device.lock(); }
6541debfc3dSmrg
6551debfc3dSmrg      explicit scoped_lock(adopt_lock_t, mutex_type& __m) noexcept
6561debfc3dSmrg      : _M_device(__m)
6571debfc3dSmrg      { } // calling thread owns mutex
6581debfc3dSmrg
6591debfc3dSmrg      ~scoped_lock()
6601debfc3dSmrg      { _M_device.unlock(); }
6611debfc3dSmrg
6621debfc3dSmrg      scoped_lock(const scoped_lock&) = delete;
6631debfc3dSmrg      scoped_lock& operator=(const scoped_lock&) = delete;
6641debfc3dSmrg
6651debfc3dSmrg    private:
6661debfc3dSmrg      mutex_type&  _M_device;
6671debfc3dSmrg    };
6681debfc3dSmrg#endif // C++17
6691debfc3dSmrg
6701debfc3dSmrg#ifdef _GLIBCXX_HAS_GTHREADS
671*8feb0f0bSmrg  /// Flag type used by std::call_once
6721debfc3dSmrg  struct once_flag
6731debfc3dSmrg  {
6741debfc3dSmrg  private:
6751debfc3dSmrg    typedef __gthread_once_t __native_type;
6761debfc3dSmrg    __native_type  _M_once = __GTHREAD_ONCE_INIT;
6771debfc3dSmrg
6781debfc3dSmrg  public:
6791debfc3dSmrg    /// Constructor
6801debfc3dSmrg    constexpr once_flag() noexcept = default;
6811debfc3dSmrg
6821debfc3dSmrg    /// Deleted copy constructor
6831debfc3dSmrg    once_flag(const once_flag&) = delete;
6841debfc3dSmrg    /// Deleted assignment operator
6851debfc3dSmrg    once_flag& operator=(const once_flag&) = delete;
6861debfc3dSmrg
6871debfc3dSmrg    template<typename _Callable, typename... _Args>
6881debfc3dSmrg      friend void
6891debfc3dSmrg      call_once(once_flag& __once, _Callable&& __f, _Args&&... __args);
6901debfc3dSmrg  };
6911debfc3dSmrg
692*8feb0f0bSmrg  /// @cond undocumented
6931debfc3dSmrg#ifdef _GLIBCXX_HAVE_TLS
6941debfc3dSmrg  extern __thread void* __once_callable;
6951debfc3dSmrg  extern __thread void (*__once_call)();
6961debfc3dSmrg#else
6971debfc3dSmrg  extern function<void()> __once_functor;
6981debfc3dSmrg
6991debfc3dSmrg  extern void
7001debfc3dSmrg  __set_once_functor_lock_ptr(unique_lock<mutex>*);
7011debfc3dSmrg
7021debfc3dSmrg  extern mutex&
7031debfc3dSmrg  __get_once_mutex();
7041debfc3dSmrg#endif
7051debfc3dSmrg
7061debfc3dSmrg  extern "C" void __once_proxy(void);
707*8feb0f0bSmrg  /// @endcond
7081debfc3dSmrg
709*8feb0f0bSmrg  /// Invoke a callable and synchronize with other calls using the same flag
7101debfc3dSmrg  template<typename _Callable, typename... _Args>
7111debfc3dSmrg    void
7121debfc3dSmrg    call_once(once_flag& __once, _Callable&& __f, _Args&&... __args)
7131debfc3dSmrg    {
7141debfc3dSmrg      // _GLIBCXX_RESOLVE_LIB_DEFECTS
7151debfc3dSmrg      // 2442. call_once() shouldn't DECAY_COPY()
7161debfc3dSmrg      auto __callable = [&] {
7171debfc3dSmrg	  std::__invoke(std::forward<_Callable>(__f),
7181debfc3dSmrg			std::forward<_Args>(__args)...);
7191debfc3dSmrg      };
7201debfc3dSmrg#ifdef _GLIBCXX_HAVE_TLS
721*8feb0f0bSmrg      __once_callable = std::__addressof(__callable); // NOLINT: PR 82481
7221debfc3dSmrg      __once_call = []{ (*(decltype(__callable)*)__once_callable)(); };
7231debfc3dSmrg#else
7241debfc3dSmrg      unique_lock<mutex> __functor_lock(__get_once_mutex());
7251debfc3dSmrg      __once_functor = __callable;
7261debfc3dSmrg      __set_once_functor_lock_ptr(&__functor_lock);
7271debfc3dSmrg#endif
7281debfc3dSmrg
7291debfc3dSmrg      int __e = __gthread_once(&__once._M_once, &__once_proxy);
7301debfc3dSmrg
7311debfc3dSmrg#ifndef _GLIBCXX_HAVE_TLS
7321debfc3dSmrg      if (__functor_lock)
7331debfc3dSmrg        __set_once_functor_lock_ptr(0);
7341debfc3dSmrg#endif
7351debfc3dSmrg
7361debfc3dSmrg      if (__e)
7371debfc3dSmrg	__throw_system_error(__e);
7381debfc3dSmrg    }
7391debfc3dSmrg#endif // _GLIBCXX_HAS_GTHREADS
7401debfc3dSmrg
741*8feb0f0bSmrg  /// @} group mutexes
7421debfc3dSmrg_GLIBCXX_END_NAMESPACE_VERSION
7431debfc3dSmrg} // namespace
7441debfc3dSmrg
7451debfc3dSmrg#endif // C++11
7461debfc3dSmrg
7471debfc3dSmrg#endif // _GLIBCXX_MUTEX
748