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