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