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