xref: /dflybsd-src/contrib/gcc-8.0/libstdc++-v3/include/std/mutex (revision 38fd149817dfbff97799f62fcb70be98c4e32523)
1*38fd1498Szrj// <mutex> -*- C++ -*-
2*38fd1498Szrj
3*38fd1498Szrj// Copyright (C) 2003-2018 Free Software Foundation, Inc.
4*38fd1498Szrj//
5*38fd1498Szrj// This file is part of the GNU ISO C++ Library.  This library is free
6*38fd1498Szrj// software; you can redistribute it and/or modify it under the
7*38fd1498Szrj// terms of the GNU General Public License as published by the
8*38fd1498Szrj// Free Software Foundation; either version 3, or (at your option)
9*38fd1498Szrj// any later version.
10*38fd1498Szrj
11*38fd1498Szrj// This library is distributed in the hope that it will be useful,
12*38fd1498Szrj// but WITHOUT ANY WARRANTY; without even the implied warranty of
13*38fd1498Szrj// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*38fd1498Szrj// GNU General Public License for more details.
15*38fd1498Szrj
16*38fd1498Szrj// Under Section 7 of GPL version 3, you are granted additional
17*38fd1498Szrj// permissions described in the GCC Runtime Library Exception, version
18*38fd1498Szrj// 3.1, as published by the Free Software Foundation.
19*38fd1498Szrj
20*38fd1498Szrj// You should have received a copy of the GNU General Public License and
21*38fd1498Szrj// a copy of the GCC Runtime Library Exception along with this program;
22*38fd1498Szrj// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23*38fd1498Szrj// <http://www.gnu.org/licenses/>.
24*38fd1498Szrj
25*38fd1498Szrj/** @file include/mutex
26*38fd1498Szrj *  This is a Standard C++ Library header.
27*38fd1498Szrj */
28*38fd1498Szrj
29*38fd1498Szrj#ifndef _GLIBCXX_MUTEX
30*38fd1498Szrj#define _GLIBCXX_MUTEX 1
31*38fd1498Szrj
32*38fd1498Szrj#pragma GCC system_header
33*38fd1498Szrj
34*38fd1498Szrj#if __cplusplus < 201103L
35*38fd1498Szrj# include <bits/c++0x_warning.h>
36*38fd1498Szrj#else
37*38fd1498Szrj
38*38fd1498Szrj#include <tuple>
39*38fd1498Szrj#include <chrono>
40*38fd1498Szrj#include <exception>
41*38fd1498Szrj#include <type_traits>
42*38fd1498Szrj#include <system_error>
43*38fd1498Szrj#include <bits/std_mutex.h>
44*38fd1498Szrj#if ! _GTHREAD_USE_MUTEX_TIMEDLOCK
45*38fd1498Szrj# include <condition_variable>
46*38fd1498Szrj# include <thread>
47*38fd1498Szrj#endif
48*38fd1498Szrj#ifndef _GLIBCXX_HAVE_TLS
49*38fd1498Szrj# include <bits/std_function.h>
50*38fd1498Szrj#endif
51*38fd1498Szrj
52*38fd1498Szrj#ifdef _GLIBCXX_USE_C99_STDINT_TR1
53*38fd1498Szrj
54*38fd1498Szrjnamespace std _GLIBCXX_VISIBILITY(default)
55*38fd1498Szrj{
56*38fd1498Szrj_GLIBCXX_BEGIN_NAMESPACE_VERSION
57*38fd1498Szrj
58*38fd1498Szrj  /**
59*38fd1498Szrj   * @ingroup mutexes
60*38fd1498Szrj   * @{
61*38fd1498Szrj   */
62*38fd1498Szrj
63*38fd1498Szrj#ifdef _GLIBCXX_HAS_GTHREADS
64*38fd1498Szrj
65*38fd1498Szrj  // Common base class for std::recursive_mutex and std::recursive_timed_mutex
66*38fd1498Szrj  class __recursive_mutex_base
67*38fd1498Szrj  {
68*38fd1498Szrj  protected:
69*38fd1498Szrj    typedef __gthread_recursive_mutex_t		__native_type;
70*38fd1498Szrj
71*38fd1498Szrj    __recursive_mutex_base(const __recursive_mutex_base&) = delete;
72*38fd1498Szrj    __recursive_mutex_base& operator=(const __recursive_mutex_base&) = delete;
73*38fd1498Szrj
74*38fd1498Szrj#ifdef __GTHREAD_RECURSIVE_MUTEX_INIT
75*38fd1498Szrj    __native_type  _M_mutex = __GTHREAD_RECURSIVE_MUTEX_INIT;
76*38fd1498Szrj
77*38fd1498Szrj    __recursive_mutex_base() = default;
78*38fd1498Szrj#else
79*38fd1498Szrj    __native_type  _M_mutex;
80*38fd1498Szrj
81*38fd1498Szrj    __recursive_mutex_base()
82*38fd1498Szrj    {
83*38fd1498Szrj      // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
84*38fd1498Szrj      __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
85*38fd1498Szrj    }
86*38fd1498Szrj
87*38fd1498Szrj    ~__recursive_mutex_base()
88*38fd1498Szrj    { __gthread_recursive_mutex_destroy(&_M_mutex); }
89*38fd1498Szrj#endif
90*38fd1498Szrj  };
91*38fd1498Szrj
92*38fd1498Szrj  /// The standard recursive mutex type.
93*38fd1498Szrj  class recursive_mutex : private __recursive_mutex_base
94*38fd1498Szrj  {
95*38fd1498Szrj  public:
96*38fd1498Szrj    typedef __native_type* 			native_handle_type;
97*38fd1498Szrj
98*38fd1498Szrj    recursive_mutex() = default;
99*38fd1498Szrj    ~recursive_mutex() = default;
100*38fd1498Szrj
101*38fd1498Szrj    recursive_mutex(const recursive_mutex&) = delete;
102*38fd1498Szrj    recursive_mutex& operator=(const recursive_mutex&) = delete;
103*38fd1498Szrj
104*38fd1498Szrj    void
105*38fd1498Szrj    lock()
106*38fd1498Szrj    {
107*38fd1498Szrj      int __e = __gthread_recursive_mutex_lock(&_M_mutex);
108*38fd1498Szrj
109*38fd1498Szrj      // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
110*38fd1498Szrj      if (__e)
111*38fd1498Szrj	__throw_system_error(__e);
112*38fd1498Szrj    }
113*38fd1498Szrj
114*38fd1498Szrj    bool
115*38fd1498Szrj    try_lock() noexcept
116*38fd1498Szrj    {
117*38fd1498Szrj      // XXX EINVAL, EAGAIN, EBUSY
118*38fd1498Szrj      return !__gthread_recursive_mutex_trylock(&_M_mutex);
119*38fd1498Szrj    }
120*38fd1498Szrj
121*38fd1498Szrj    void
122*38fd1498Szrj    unlock()
123*38fd1498Szrj    {
124*38fd1498Szrj      // XXX EINVAL, EAGAIN, EBUSY
125*38fd1498Szrj      __gthread_recursive_mutex_unlock(&_M_mutex);
126*38fd1498Szrj    }
127*38fd1498Szrj
128*38fd1498Szrj    native_handle_type
129*38fd1498Szrj    native_handle() noexcept
130*38fd1498Szrj    { return &_M_mutex; }
131*38fd1498Szrj  };
132*38fd1498Szrj
133*38fd1498Szrj#if _GTHREAD_USE_MUTEX_TIMEDLOCK
134*38fd1498Szrj  template<typename _Derived>
135*38fd1498Szrj    class __timed_mutex_impl
136*38fd1498Szrj    {
137*38fd1498Szrj    protected:
138*38fd1498Szrj      typedef chrono::high_resolution_clock 	__clock_t;
139*38fd1498Szrj
140*38fd1498Szrj      template<typename _Rep, typename _Period>
141*38fd1498Szrj	bool
142*38fd1498Szrj	_M_try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
143*38fd1498Szrj	{
144*38fd1498Szrj	  using chrono::steady_clock;
145*38fd1498Szrj	  auto __rt = chrono::duration_cast<steady_clock::duration>(__rtime);
146*38fd1498Szrj	  if (ratio_greater<steady_clock::period, _Period>())
147*38fd1498Szrj	    ++__rt;
148*38fd1498Szrj	  return _M_try_lock_until(steady_clock::now() + __rt);
149*38fd1498Szrj	}
150*38fd1498Szrj
151*38fd1498Szrj      template<typename _Duration>
152*38fd1498Szrj	bool
153*38fd1498Szrj	_M_try_lock_until(const chrono::time_point<__clock_t,
154*38fd1498Szrj						   _Duration>& __atime)
155*38fd1498Szrj	{
156*38fd1498Szrj	  auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
157*38fd1498Szrj	  auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
158*38fd1498Szrj
159*38fd1498Szrj	  __gthread_time_t __ts = {
160*38fd1498Szrj	    static_cast<std::time_t>(__s.time_since_epoch().count()),
161*38fd1498Szrj	    static_cast<long>(__ns.count())
162*38fd1498Szrj	  };
163*38fd1498Szrj
164*38fd1498Szrj	  return static_cast<_Derived*>(this)->_M_timedlock(__ts);
165*38fd1498Szrj	}
166*38fd1498Szrj
167*38fd1498Szrj      template<typename _Clock, typename _Duration>
168*38fd1498Szrj	bool
169*38fd1498Szrj	_M_try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
170*38fd1498Szrj	{
171*38fd1498Szrj	  auto __rtime = __atime - _Clock::now();
172*38fd1498Szrj	  return _M_try_lock_until(__clock_t::now() + __rtime);
173*38fd1498Szrj	}
174*38fd1498Szrj    };
175*38fd1498Szrj
176*38fd1498Szrj  /// The standard timed mutex type.
177*38fd1498Szrj  class timed_mutex
178*38fd1498Szrj  : private __mutex_base, public __timed_mutex_impl<timed_mutex>
179*38fd1498Szrj  {
180*38fd1498Szrj  public:
181*38fd1498Szrj    typedef __native_type* 		  	native_handle_type;
182*38fd1498Szrj
183*38fd1498Szrj    timed_mutex() = default;
184*38fd1498Szrj    ~timed_mutex() = default;
185*38fd1498Szrj
186*38fd1498Szrj    timed_mutex(const timed_mutex&) = delete;
187*38fd1498Szrj    timed_mutex& operator=(const timed_mutex&) = delete;
188*38fd1498Szrj
189*38fd1498Szrj    void
190*38fd1498Szrj    lock()
191*38fd1498Szrj    {
192*38fd1498Szrj      int __e = __gthread_mutex_lock(&_M_mutex);
193*38fd1498Szrj
194*38fd1498Szrj      // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
195*38fd1498Szrj      if (__e)
196*38fd1498Szrj	__throw_system_error(__e);
197*38fd1498Szrj    }
198*38fd1498Szrj
199*38fd1498Szrj    bool
200*38fd1498Szrj    try_lock() noexcept
201*38fd1498Szrj    {
202*38fd1498Szrj      // XXX EINVAL, EAGAIN, EBUSY
203*38fd1498Szrj      return !__gthread_mutex_trylock(&_M_mutex);
204*38fd1498Szrj    }
205*38fd1498Szrj
206*38fd1498Szrj    template <class _Rep, class _Period>
207*38fd1498Szrj      bool
208*38fd1498Szrj      try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
209*38fd1498Szrj      { return _M_try_lock_for(__rtime); }
210*38fd1498Szrj
211*38fd1498Szrj    template <class _Clock, class _Duration>
212*38fd1498Szrj      bool
213*38fd1498Szrj      try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
214*38fd1498Szrj      { return _M_try_lock_until(__atime); }
215*38fd1498Szrj
216*38fd1498Szrj    void
217*38fd1498Szrj    unlock()
218*38fd1498Szrj    {
219*38fd1498Szrj      // XXX EINVAL, EAGAIN, EBUSY
220*38fd1498Szrj      __gthread_mutex_unlock(&_M_mutex);
221*38fd1498Szrj    }
222*38fd1498Szrj
223*38fd1498Szrj    native_handle_type
224*38fd1498Szrj    native_handle() noexcept
225*38fd1498Szrj    { return &_M_mutex; }
226*38fd1498Szrj
227*38fd1498Szrj    private:
228*38fd1498Szrj      friend class __timed_mutex_impl<timed_mutex>;
229*38fd1498Szrj
230*38fd1498Szrj      bool
231*38fd1498Szrj      _M_timedlock(const __gthread_time_t& __ts)
232*38fd1498Szrj      { return !__gthread_mutex_timedlock(&_M_mutex, &__ts); }
233*38fd1498Szrj  };
234*38fd1498Szrj
235*38fd1498Szrj  /// recursive_timed_mutex
236*38fd1498Szrj  class recursive_timed_mutex
237*38fd1498Szrj  : private __recursive_mutex_base,
238*38fd1498Szrj    public __timed_mutex_impl<recursive_timed_mutex>
239*38fd1498Szrj  {
240*38fd1498Szrj  public:
241*38fd1498Szrj    typedef __native_type* 			native_handle_type;
242*38fd1498Szrj
243*38fd1498Szrj    recursive_timed_mutex() = default;
244*38fd1498Szrj    ~recursive_timed_mutex() = default;
245*38fd1498Szrj
246*38fd1498Szrj    recursive_timed_mutex(const recursive_timed_mutex&) = delete;
247*38fd1498Szrj    recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
248*38fd1498Szrj
249*38fd1498Szrj    void
250*38fd1498Szrj    lock()
251*38fd1498Szrj    {
252*38fd1498Szrj      int __e = __gthread_recursive_mutex_lock(&_M_mutex);
253*38fd1498Szrj
254*38fd1498Szrj      // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
255*38fd1498Szrj      if (__e)
256*38fd1498Szrj	__throw_system_error(__e);
257*38fd1498Szrj    }
258*38fd1498Szrj
259*38fd1498Szrj    bool
260*38fd1498Szrj    try_lock() noexcept
261*38fd1498Szrj    {
262*38fd1498Szrj      // XXX EINVAL, EAGAIN, EBUSY
263*38fd1498Szrj      return !__gthread_recursive_mutex_trylock(&_M_mutex);
264*38fd1498Szrj    }
265*38fd1498Szrj
266*38fd1498Szrj    template <class _Rep, class _Period>
267*38fd1498Szrj      bool
268*38fd1498Szrj      try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
269*38fd1498Szrj      { return _M_try_lock_for(__rtime); }
270*38fd1498Szrj
271*38fd1498Szrj    template <class _Clock, class _Duration>
272*38fd1498Szrj      bool
273*38fd1498Szrj      try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
274*38fd1498Szrj      { return _M_try_lock_until(__atime); }
275*38fd1498Szrj
276*38fd1498Szrj    void
277*38fd1498Szrj    unlock()
278*38fd1498Szrj    {
279*38fd1498Szrj      // XXX EINVAL, EAGAIN, EBUSY
280*38fd1498Szrj      __gthread_recursive_mutex_unlock(&_M_mutex);
281*38fd1498Szrj    }
282*38fd1498Szrj
283*38fd1498Szrj    native_handle_type
284*38fd1498Szrj    native_handle() noexcept
285*38fd1498Szrj    { return &_M_mutex; }
286*38fd1498Szrj
287*38fd1498Szrj    private:
288*38fd1498Szrj      friend class __timed_mutex_impl<recursive_timed_mutex>;
289*38fd1498Szrj
290*38fd1498Szrj      bool
291*38fd1498Szrj      _M_timedlock(const __gthread_time_t& __ts)
292*38fd1498Szrj      { return !__gthread_recursive_mutex_timedlock(&_M_mutex, &__ts); }
293*38fd1498Szrj  };
294*38fd1498Szrj
295*38fd1498Szrj#else // !_GTHREAD_USE_MUTEX_TIMEDLOCK
296*38fd1498Szrj
297*38fd1498Szrj  /// timed_mutex
298*38fd1498Szrj  class timed_mutex
299*38fd1498Szrj  {
300*38fd1498Szrj    mutex		_M_mut;
301*38fd1498Szrj    condition_variable	_M_cv;
302*38fd1498Szrj    bool		_M_locked = false;
303*38fd1498Szrj
304*38fd1498Szrj  public:
305*38fd1498Szrj
306*38fd1498Szrj    timed_mutex() = default;
307*38fd1498Szrj    ~timed_mutex() { __glibcxx_assert( !_M_locked ); }
308*38fd1498Szrj
309*38fd1498Szrj    timed_mutex(const timed_mutex&) = delete;
310*38fd1498Szrj    timed_mutex& operator=(const timed_mutex&) = delete;
311*38fd1498Szrj
312*38fd1498Szrj    void
313*38fd1498Szrj    lock()
314*38fd1498Szrj    {
315*38fd1498Szrj      unique_lock<mutex> __lk(_M_mut);
316*38fd1498Szrj      _M_cv.wait(__lk, [&]{ return !_M_locked; });
317*38fd1498Szrj      _M_locked = true;
318*38fd1498Szrj    }
319*38fd1498Szrj
320*38fd1498Szrj    bool
321*38fd1498Szrj    try_lock()
322*38fd1498Szrj    {
323*38fd1498Szrj      lock_guard<mutex> __lk(_M_mut);
324*38fd1498Szrj      if (_M_locked)
325*38fd1498Szrj	return false;
326*38fd1498Szrj      _M_locked = true;
327*38fd1498Szrj      return true;
328*38fd1498Szrj    }
329*38fd1498Szrj
330*38fd1498Szrj    template<typename _Rep, typename _Period>
331*38fd1498Szrj      bool
332*38fd1498Szrj      try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
333*38fd1498Szrj      {
334*38fd1498Szrj	unique_lock<mutex> __lk(_M_mut);
335*38fd1498Szrj	if (!_M_cv.wait_for(__lk, __rtime, [&]{ return !_M_locked; }))
336*38fd1498Szrj	  return false;
337*38fd1498Szrj	_M_locked = true;
338*38fd1498Szrj	return true;
339*38fd1498Szrj      }
340*38fd1498Szrj
341*38fd1498Szrj    template<typename _Clock, typename _Duration>
342*38fd1498Szrj      bool
343*38fd1498Szrj      try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
344*38fd1498Szrj      {
345*38fd1498Szrj	unique_lock<mutex> __lk(_M_mut);
346*38fd1498Szrj	if (!_M_cv.wait_until(__lk, __atime, [&]{ return !_M_locked; }))
347*38fd1498Szrj	  return false;
348*38fd1498Szrj	_M_locked = true;
349*38fd1498Szrj	return true;
350*38fd1498Szrj      }
351*38fd1498Szrj
352*38fd1498Szrj    void
353*38fd1498Szrj    unlock()
354*38fd1498Szrj    {
355*38fd1498Szrj      lock_guard<mutex> __lk(_M_mut);
356*38fd1498Szrj      __glibcxx_assert( _M_locked );
357*38fd1498Szrj      _M_locked = false;
358*38fd1498Szrj      _M_cv.notify_one();
359*38fd1498Szrj    }
360*38fd1498Szrj  };
361*38fd1498Szrj
362*38fd1498Szrj  /// recursive_timed_mutex
363*38fd1498Szrj  class recursive_timed_mutex
364*38fd1498Szrj  {
365*38fd1498Szrj    mutex		_M_mut;
366*38fd1498Szrj    condition_variable	_M_cv;
367*38fd1498Szrj    thread::id		_M_owner;
368*38fd1498Szrj    unsigned		_M_count = 0;
369*38fd1498Szrj
370*38fd1498Szrj    // Predicate type that tests whether the current thread can lock a mutex.
371*38fd1498Szrj    struct _Can_lock
372*38fd1498Szrj    {
373*38fd1498Szrj      // Returns true if the mutex is unlocked or is locked by _M_caller.
374*38fd1498Szrj      bool
375*38fd1498Szrj      operator()() const noexcept
376*38fd1498Szrj      { return _M_mx->_M_count == 0 || _M_mx->_M_owner == _M_caller; }
377*38fd1498Szrj
378*38fd1498Szrj      const recursive_timed_mutex* _M_mx;
379*38fd1498Szrj      thread::id _M_caller;
380*38fd1498Szrj    };
381*38fd1498Szrj
382*38fd1498Szrj  public:
383*38fd1498Szrj
384*38fd1498Szrj    recursive_timed_mutex() = default;
385*38fd1498Szrj    ~recursive_timed_mutex() { __glibcxx_assert( _M_count == 0 ); }
386*38fd1498Szrj
387*38fd1498Szrj    recursive_timed_mutex(const recursive_timed_mutex&) = delete;
388*38fd1498Szrj    recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
389*38fd1498Szrj
390*38fd1498Szrj    void
391*38fd1498Szrj    lock()
392*38fd1498Szrj    {
393*38fd1498Szrj      auto __id = this_thread::get_id();
394*38fd1498Szrj      _Can_lock __can_lock{this, __id};
395*38fd1498Szrj      unique_lock<mutex> __lk(_M_mut);
396*38fd1498Szrj      _M_cv.wait(__lk, __can_lock);
397*38fd1498Szrj      if (_M_count == -1u)
398*38fd1498Szrj	__throw_system_error(EAGAIN); // [thread.timedmutex.recursive]/3
399*38fd1498Szrj      _M_owner = __id;
400*38fd1498Szrj      ++_M_count;
401*38fd1498Szrj    }
402*38fd1498Szrj
403*38fd1498Szrj    bool
404*38fd1498Szrj    try_lock()
405*38fd1498Szrj    {
406*38fd1498Szrj      auto __id = this_thread::get_id();
407*38fd1498Szrj      _Can_lock __can_lock{this, __id};
408*38fd1498Szrj      lock_guard<mutex> __lk(_M_mut);
409*38fd1498Szrj      if (!__can_lock())
410*38fd1498Szrj	return false;
411*38fd1498Szrj      if (_M_count == -1u)
412*38fd1498Szrj	return false;
413*38fd1498Szrj      _M_owner = __id;
414*38fd1498Szrj      ++_M_count;
415*38fd1498Szrj      return true;
416*38fd1498Szrj    }
417*38fd1498Szrj
418*38fd1498Szrj    template<typename _Rep, typename _Period>
419*38fd1498Szrj      bool
420*38fd1498Szrj      try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
421*38fd1498Szrj      {
422*38fd1498Szrj	auto __id = this_thread::get_id();
423*38fd1498Szrj	_Can_lock __can_lock{this, __id};
424*38fd1498Szrj	unique_lock<mutex> __lk(_M_mut);
425*38fd1498Szrj	if (!_M_cv.wait_for(__lk, __rtime, __can_lock))
426*38fd1498Szrj	  return false;
427*38fd1498Szrj	if (_M_count == -1u)
428*38fd1498Szrj	  return false;
429*38fd1498Szrj	_M_owner = __id;
430*38fd1498Szrj	++_M_count;
431*38fd1498Szrj	return true;
432*38fd1498Szrj      }
433*38fd1498Szrj
434*38fd1498Szrj    template<typename _Clock, typename _Duration>
435*38fd1498Szrj      bool
436*38fd1498Szrj      try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
437*38fd1498Szrj      {
438*38fd1498Szrj	auto __id = this_thread::get_id();
439*38fd1498Szrj	_Can_lock __can_lock{this, __id};
440*38fd1498Szrj	unique_lock<mutex> __lk(_M_mut);
441*38fd1498Szrj	if (!_M_cv.wait_until(__lk, __atime, __can_lock))
442*38fd1498Szrj	  return false;
443*38fd1498Szrj	if (_M_count == -1u)
444*38fd1498Szrj	  return false;
445*38fd1498Szrj	_M_owner = __id;
446*38fd1498Szrj	++_M_count;
447*38fd1498Szrj	return true;
448*38fd1498Szrj      }
449*38fd1498Szrj
450*38fd1498Szrj    void
451*38fd1498Szrj    unlock()
452*38fd1498Szrj    {
453*38fd1498Szrj      lock_guard<mutex> __lk(_M_mut);
454*38fd1498Szrj      __glibcxx_assert( _M_owner == this_thread::get_id() );
455*38fd1498Szrj      __glibcxx_assert( _M_count > 0 );
456*38fd1498Szrj      if (--_M_count == 0)
457*38fd1498Szrj	{
458*38fd1498Szrj	  _M_owner = {};
459*38fd1498Szrj	  _M_cv.notify_one();
460*38fd1498Szrj	}
461*38fd1498Szrj    }
462*38fd1498Szrj  };
463*38fd1498Szrj
464*38fd1498Szrj#endif
465*38fd1498Szrj#endif // _GLIBCXX_HAS_GTHREADS
466*38fd1498Szrj
467*38fd1498Szrj  template<typename _Lock>
468*38fd1498Szrj    inline unique_lock<_Lock>
469*38fd1498Szrj    __try_to_lock(_Lock& __l)
470*38fd1498Szrj    { return unique_lock<_Lock>{__l, try_to_lock}; }
471*38fd1498Szrj
472*38fd1498Szrj  template<int _Idx, bool _Continue = true>
473*38fd1498Szrj    struct __try_lock_impl
474*38fd1498Szrj    {
475*38fd1498Szrj      template<typename... _Lock>
476*38fd1498Szrj	static void
477*38fd1498Szrj	__do_try_lock(tuple<_Lock&...>& __locks, int& __idx)
478*38fd1498Szrj	{
479*38fd1498Szrj          __idx = _Idx;
480*38fd1498Szrj          auto __lock = std::__try_to_lock(std::get<_Idx>(__locks));
481*38fd1498Szrj          if (__lock.owns_lock())
482*38fd1498Szrj            {
483*38fd1498Szrj	      constexpr bool __cont = _Idx + 2 < sizeof...(_Lock);
484*38fd1498Szrj	      using __try_locker = __try_lock_impl<_Idx + 1, __cont>;
485*38fd1498Szrj	      __try_locker::__do_try_lock(__locks, __idx);
486*38fd1498Szrj              if (__idx == -1)
487*38fd1498Szrj                __lock.release();
488*38fd1498Szrj            }
489*38fd1498Szrj	}
490*38fd1498Szrj    };
491*38fd1498Szrj
492*38fd1498Szrj  template<int _Idx>
493*38fd1498Szrj    struct __try_lock_impl<_Idx, false>
494*38fd1498Szrj    {
495*38fd1498Szrj      template<typename... _Lock>
496*38fd1498Szrj	static void
497*38fd1498Szrj	__do_try_lock(tuple<_Lock&...>& __locks, int& __idx)
498*38fd1498Szrj	{
499*38fd1498Szrj          __idx = _Idx;
500*38fd1498Szrj          auto __lock = std::__try_to_lock(std::get<_Idx>(__locks));
501*38fd1498Szrj          if (__lock.owns_lock())
502*38fd1498Szrj            {
503*38fd1498Szrj              __idx = -1;
504*38fd1498Szrj              __lock.release();
505*38fd1498Szrj            }
506*38fd1498Szrj	}
507*38fd1498Szrj    };
508*38fd1498Szrj
509*38fd1498Szrj  /** @brief Generic try_lock.
510*38fd1498Szrj   *  @param __l1 Meets Lockable requirements (try_lock() may throw).
511*38fd1498Szrj   *  @param __l2 Meets Lockable requirements (try_lock() may throw).
512*38fd1498Szrj   *  @param __l3 Meets Lockable requirements (try_lock() may throw).
513*38fd1498Szrj   *  @return Returns -1 if all try_lock() calls return true. Otherwise returns
514*38fd1498Szrj   *          a 0-based index corresponding to the argument that returned false.
515*38fd1498Szrj   *  @post Either all arguments are locked, or none will be.
516*38fd1498Szrj   *
517*38fd1498Szrj   *  Sequentially calls try_lock() on each argument.
518*38fd1498Szrj   */
519*38fd1498Szrj  template<typename _Lock1, typename _Lock2, typename... _Lock3>
520*38fd1498Szrj    int
521*38fd1498Szrj    try_lock(_Lock1& __l1, _Lock2& __l2, _Lock3&... __l3)
522*38fd1498Szrj    {
523*38fd1498Szrj      int __idx;
524*38fd1498Szrj      auto __locks = std::tie(__l1, __l2, __l3...);
525*38fd1498Szrj      __try_lock_impl<0>::__do_try_lock(__locks, __idx);
526*38fd1498Szrj      return __idx;
527*38fd1498Szrj    }
528*38fd1498Szrj
529*38fd1498Szrj  /** @brief Generic lock.
530*38fd1498Szrj   *  @param __l1 Meets Lockable requirements (try_lock() may throw).
531*38fd1498Szrj   *  @param __l2 Meets Lockable requirements (try_lock() may throw).
532*38fd1498Szrj   *  @param __l3 Meets Lockable requirements (try_lock() may throw).
533*38fd1498Szrj   *  @throw An exception thrown by an argument's lock() or try_lock() member.
534*38fd1498Szrj   *  @post All arguments are locked.
535*38fd1498Szrj   *
536*38fd1498Szrj   *  All arguments are locked via a sequence of calls to lock(), try_lock()
537*38fd1498Szrj   *  and unlock().  If the call exits via an exception any locks that were
538*38fd1498Szrj   *  obtained will be released.
539*38fd1498Szrj   */
540*38fd1498Szrj  template<typename _L1, typename _L2, typename... _L3>
541*38fd1498Szrj    void
542*38fd1498Szrj    lock(_L1& __l1, _L2& __l2, _L3&... __l3)
543*38fd1498Szrj    {
544*38fd1498Szrj      while (true)
545*38fd1498Szrj        {
546*38fd1498Szrj          using __try_locker = __try_lock_impl<0, sizeof...(_L3) != 0>;
547*38fd1498Szrj          unique_lock<_L1> __first(__l1);
548*38fd1498Szrj          int __idx;
549*38fd1498Szrj          auto __locks = std::tie(__l2, __l3...);
550*38fd1498Szrj          __try_locker::__do_try_lock(__locks, __idx);
551*38fd1498Szrj          if (__idx == -1)
552*38fd1498Szrj            {
553*38fd1498Szrj              __first.release();
554*38fd1498Szrj              return;
555*38fd1498Szrj            }
556*38fd1498Szrj        }
557*38fd1498Szrj    }
558*38fd1498Szrj
559*38fd1498Szrj#if __cplusplus >= 201703L
560*38fd1498Szrj#define __cpp_lib_scoped_lock 201703
561*38fd1498Szrj  /** @brief A scoped lock type for multiple lockable objects.
562*38fd1498Szrj   *
563*38fd1498Szrj   * A scoped_lock controls mutex ownership within a scope, releasing
564*38fd1498Szrj   * ownership in the destructor.
565*38fd1498Szrj   */
566*38fd1498Szrj  template<typename... _MutexTypes>
567*38fd1498Szrj    class scoped_lock
568*38fd1498Szrj    {
569*38fd1498Szrj    public:
570*38fd1498Szrj      explicit scoped_lock(_MutexTypes&... __m) : _M_devices(std::tie(__m...))
571*38fd1498Szrj      { std::lock(__m...); }
572*38fd1498Szrj
573*38fd1498Szrj      explicit scoped_lock(adopt_lock_t, _MutexTypes&... __m) noexcept
574*38fd1498Szrj      : _M_devices(std::tie(__m...))
575*38fd1498Szrj      { } // calling thread owns mutex
576*38fd1498Szrj
577*38fd1498Szrj      ~scoped_lock()
578*38fd1498Szrj      {
579*38fd1498Szrj	std::apply([](_MutexTypes&... __m) {
580*38fd1498Szrj	  char __i[] __attribute__((__unused__)) = { (__m.unlock(), 0)... };
581*38fd1498Szrj	}, _M_devices);
582*38fd1498Szrj      }
583*38fd1498Szrj
584*38fd1498Szrj      scoped_lock(const scoped_lock&) = delete;
585*38fd1498Szrj      scoped_lock& operator=(const scoped_lock&) = delete;
586*38fd1498Szrj
587*38fd1498Szrj    private:
588*38fd1498Szrj      tuple<_MutexTypes&...> _M_devices;
589*38fd1498Szrj    };
590*38fd1498Szrj
591*38fd1498Szrj  template<>
592*38fd1498Szrj    class scoped_lock<>
593*38fd1498Szrj    {
594*38fd1498Szrj    public:
595*38fd1498Szrj      explicit scoped_lock() = default;
596*38fd1498Szrj      explicit scoped_lock(adopt_lock_t) noexcept { }
597*38fd1498Szrj      ~scoped_lock() = default;
598*38fd1498Szrj
599*38fd1498Szrj      scoped_lock(const scoped_lock&) = delete;
600*38fd1498Szrj      scoped_lock& operator=(const scoped_lock&) = delete;
601*38fd1498Szrj    };
602*38fd1498Szrj
603*38fd1498Szrj  template<typename _Mutex>
604*38fd1498Szrj    class scoped_lock<_Mutex>
605*38fd1498Szrj    {
606*38fd1498Szrj    public:
607*38fd1498Szrj      using mutex_type = _Mutex;
608*38fd1498Szrj
609*38fd1498Szrj      explicit scoped_lock(mutex_type& __m) : _M_device(__m)
610*38fd1498Szrj      { _M_device.lock(); }
611*38fd1498Szrj
612*38fd1498Szrj      explicit scoped_lock(adopt_lock_t, mutex_type& __m) noexcept
613*38fd1498Szrj      : _M_device(__m)
614*38fd1498Szrj      { } // calling thread owns mutex
615*38fd1498Szrj
616*38fd1498Szrj      ~scoped_lock()
617*38fd1498Szrj      { _M_device.unlock(); }
618*38fd1498Szrj
619*38fd1498Szrj      scoped_lock(const scoped_lock&) = delete;
620*38fd1498Szrj      scoped_lock& operator=(const scoped_lock&) = delete;
621*38fd1498Szrj
622*38fd1498Szrj    private:
623*38fd1498Szrj      mutex_type&  _M_device;
624*38fd1498Szrj    };
625*38fd1498Szrj#endif // C++17
626*38fd1498Szrj
627*38fd1498Szrj#ifdef _GLIBCXX_HAS_GTHREADS
628*38fd1498Szrj  /// once_flag
629*38fd1498Szrj  struct once_flag
630*38fd1498Szrj  {
631*38fd1498Szrj  private:
632*38fd1498Szrj    typedef __gthread_once_t __native_type;
633*38fd1498Szrj    __native_type  _M_once = __GTHREAD_ONCE_INIT;
634*38fd1498Szrj
635*38fd1498Szrj  public:
636*38fd1498Szrj    /// Constructor
637*38fd1498Szrj    constexpr once_flag() noexcept = default;
638*38fd1498Szrj
639*38fd1498Szrj    /// Deleted copy constructor
640*38fd1498Szrj    once_flag(const once_flag&) = delete;
641*38fd1498Szrj    /// Deleted assignment operator
642*38fd1498Szrj    once_flag& operator=(const once_flag&) = delete;
643*38fd1498Szrj
644*38fd1498Szrj    template<typename _Callable, typename... _Args>
645*38fd1498Szrj      friend void
646*38fd1498Szrj      call_once(once_flag& __once, _Callable&& __f, _Args&&... __args);
647*38fd1498Szrj  };
648*38fd1498Szrj
649*38fd1498Szrj#ifdef _GLIBCXX_HAVE_TLS
650*38fd1498Szrj  extern __thread void* __once_callable;
651*38fd1498Szrj  extern __thread void (*__once_call)();
652*38fd1498Szrj#else
653*38fd1498Szrj  extern function<void()> __once_functor;
654*38fd1498Szrj
655*38fd1498Szrj  extern void
656*38fd1498Szrj  __set_once_functor_lock_ptr(unique_lock<mutex>*);
657*38fd1498Szrj
658*38fd1498Szrj  extern mutex&
659*38fd1498Szrj  __get_once_mutex();
660*38fd1498Szrj#endif
661*38fd1498Szrj
662*38fd1498Szrj  extern "C" void __once_proxy(void);
663*38fd1498Szrj
664*38fd1498Szrj  /// call_once
665*38fd1498Szrj  template<typename _Callable, typename... _Args>
666*38fd1498Szrj    void
667*38fd1498Szrj    call_once(once_flag& __once, _Callable&& __f, _Args&&... __args)
668*38fd1498Szrj    {
669*38fd1498Szrj      // _GLIBCXX_RESOLVE_LIB_DEFECTS
670*38fd1498Szrj      // 2442. call_once() shouldn't DECAY_COPY()
671*38fd1498Szrj      auto __callable = [&] {
672*38fd1498Szrj	  std::__invoke(std::forward<_Callable>(__f),
673*38fd1498Szrj			std::forward<_Args>(__args)...);
674*38fd1498Szrj      };
675*38fd1498Szrj#ifdef _GLIBCXX_HAVE_TLS
676*38fd1498Szrj      __once_callable = std::__addressof(__callable);
677*38fd1498Szrj      __once_call = []{ (*(decltype(__callable)*)__once_callable)(); };
678*38fd1498Szrj#else
679*38fd1498Szrj      unique_lock<mutex> __functor_lock(__get_once_mutex());
680*38fd1498Szrj      __once_functor = __callable;
681*38fd1498Szrj      __set_once_functor_lock_ptr(&__functor_lock);
682*38fd1498Szrj#endif
683*38fd1498Szrj
684*38fd1498Szrj      int __e = __gthread_once(&__once._M_once, &__once_proxy);
685*38fd1498Szrj
686*38fd1498Szrj#ifndef _GLIBCXX_HAVE_TLS
687*38fd1498Szrj      if (__functor_lock)
688*38fd1498Szrj        __set_once_functor_lock_ptr(0);
689*38fd1498Szrj#endif
690*38fd1498Szrj
691*38fd1498Szrj#ifdef __clang_analyzer__
692*38fd1498Szrj      // PR libstdc++/82481
693*38fd1498Szrj      __once_callable = nullptr;
694*38fd1498Szrj      __once_call = nullptr;
695*38fd1498Szrj#endif
696*38fd1498Szrj
697*38fd1498Szrj      if (__e)
698*38fd1498Szrj	__throw_system_error(__e);
699*38fd1498Szrj    }
700*38fd1498Szrj#endif // _GLIBCXX_HAS_GTHREADS
701*38fd1498Szrj
702*38fd1498Szrj  // @} group mutexes
703*38fd1498Szrj_GLIBCXX_END_NAMESPACE_VERSION
704*38fd1498Szrj} // namespace
705*38fd1498Szrj#endif // _GLIBCXX_USE_C99_STDINT_TR1
706*38fd1498Szrj
707*38fd1498Szrj#endif // C++11
708*38fd1498Szrj
709*38fd1498Szrj#endif // _GLIBCXX_MUTEX
710