1// <mutex> -*- C++ -*- 2 3// Copyright (C) 2003-2019 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 * @ingroup 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 typedef chrono::high_resolution_clock __clock_t; 138 139 template<typename _Rep, typename _Period> 140 bool 141 _M_try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 142 { 143 using chrono::steady_clock; 144 auto __rt = chrono::duration_cast<steady_clock::duration>(__rtime); 145 if (ratio_greater<steady_clock::period, _Period>()) 146 ++__rt; 147 return _M_try_lock_until(steady_clock::now() + __rt); 148 } 149 150 template<typename _Duration> 151 bool 152 _M_try_lock_until(const chrono::time_point<__clock_t, 153 _Duration>& __atime) 154 { 155 auto __s = chrono::time_point_cast<chrono::seconds>(__atime); 156 auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s); 157 158 __gthread_time_t __ts = { 159 static_cast<std::time_t>(__s.time_since_epoch().count()), 160 static_cast<long>(__ns.count()) 161 }; 162 163 return static_cast<_Derived*>(this)->_M_timedlock(__ts); 164 } 165 166 template<typename _Clock, typename _Duration> 167 bool 168 _M_try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 169 { 170 auto __rtime = __atime - _Clock::now(); 171 return _M_try_lock_until(__clock_t::now() + __rtime); 172 } 173 }; 174 175 /// The standard timed mutex type. 176 class timed_mutex 177 : private __mutex_base, public __timed_mutex_impl<timed_mutex> 178 { 179 public: 180 typedef __native_type* native_handle_type; 181 182 timed_mutex() = default; 183 ~timed_mutex() = default; 184 185 timed_mutex(const timed_mutex&) = delete; 186 timed_mutex& operator=(const timed_mutex&) = delete; 187 188 void 189 lock() 190 { 191 int __e = __gthread_mutex_lock(&_M_mutex); 192 193 // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) 194 if (__e) 195 __throw_system_error(__e); 196 } 197 198 bool 199 try_lock() noexcept 200 { 201 // XXX EINVAL, EAGAIN, EBUSY 202 return !__gthread_mutex_trylock(&_M_mutex); 203 } 204 205 template <class _Rep, class _Period> 206 bool 207 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 208 { return _M_try_lock_for(__rtime); } 209 210 template <class _Clock, class _Duration> 211 bool 212 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 213 { return _M_try_lock_until(__atime); } 214 215 void 216 unlock() 217 { 218 // XXX EINVAL, EAGAIN, EBUSY 219 __gthread_mutex_unlock(&_M_mutex); 220 } 221 222 native_handle_type 223 native_handle() noexcept 224 { return &_M_mutex; } 225 226 private: 227 friend class __timed_mutex_impl<timed_mutex>; 228 229 bool 230 _M_timedlock(const __gthread_time_t& __ts) 231 { return !__gthread_mutex_timedlock(&_M_mutex, &__ts); } 232 }; 233 234 /// recursive_timed_mutex 235 class recursive_timed_mutex 236 : private __recursive_mutex_base, 237 public __timed_mutex_impl<recursive_timed_mutex> 238 { 239 public: 240 typedef __native_type* native_handle_type; 241 242 recursive_timed_mutex() = default; 243 ~recursive_timed_mutex() = default; 244 245 recursive_timed_mutex(const recursive_timed_mutex&) = delete; 246 recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; 247 248 void 249 lock() 250 { 251 int __e = __gthread_recursive_mutex_lock(&_M_mutex); 252 253 // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) 254 if (__e) 255 __throw_system_error(__e); 256 } 257 258 bool 259 try_lock() noexcept 260 { 261 // XXX EINVAL, EAGAIN, EBUSY 262 return !__gthread_recursive_mutex_trylock(&_M_mutex); 263 } 264 265 template <class _Rep, class _Period> 266 bool 267 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 268 { return _M_try_lock_for(__rtime); } 269 270 template <class _Clock, class _Duration> 271 bool 272 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 273 { return _M_try_lock_until(__atime); } 274 275 void 276 unlock() 277 { 278 // XXX EINVAL, EAGAIN, EBUSY 279 __gthread_recursive_mutex_unlock(&_M_mutex); 280 } 281 282 native_handle_type 283 native_handle() noexcept 284 { return &_M_mutex; } 285 286 private: 287 friend class __timed_mutex_impl<recursive_timed_mutex>; 288 289 bool 290 _M_timedlock(const __gthread_time_t& __ts) 291 { return !__gthread_recursive_mutex_timedlock(&_M_mutex, &__ts); } 292 }; 293 294#else // !_GTHREAD_USE_MUTEX_TIMEDLOCK 295 296 /// timed_mutex 297 class timed_mutex 298 { 299 mutex _M_mut; 300 condition_variable _M_cv; 301 bool _M_locked = false; 302 303 public: 304 305 timed_mutex() = default; 306 ~timed_mutex() { __glibcxx_assert( !_M_locked ); } 307 308 timed_mutex(const timed_mutex&) = delete; 309 timed_mutex& operator=(const timed_mutex&) = delete; 310 311 void 312 lock() 313 { 314 unique_lock<mutex> __lk(_M_mut); 315 _M_cv.wait(__lk, [&]{ return !_M_locked; }); 316 _M_locked = true; 317 } 318 319 bool 320 try_lock() 321 { 322 lock_guard<mutex> __lk(_M_mut); 323 if (_M_locked) 324 return false; 325 _M_locked = true; 326 return true; 327 } 328 329 template<typename _Rep, typename _Period> 330 bool 331 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 332 { 333 unique_lock<mutex> __lk(_M_mut); 334 if (!_M_cv.wait_for(__lk, __rtime, [&]{ return !_M_locked; })) 335 return false; 336 _M_locked = true; 337 return true; 338 } 339 340 template<typename _Clock, typename _Duration> 341 bool 342 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 343 { 344 unique_lock<mutex> __lk(_M_mut); 345 if (!_M_cv.wait_until(__lk, __atime, [&]{ return !_M_locked; })) 346 return false; 347 _M_locked = true; 348 return true; 349 } 350 351 void 352 unlock() 353 { 354 lock_guard<mutex> __lk(_M_mut); 355 __glibcxx_assert( _M_locked ); 356 _M_locked = false; 357 _M_cv.notify_one(); 358 } 359 }; 360 361 /// recursive_timed_mutex 362 class recursive_timed_mutex 363 { 364 mutex _M_mut; 365 condition_variable _M_cv; 366 thread::id _M_owner; 367 unsigned _M_count = 0; 368 369 // Predicate type that tests whether the current thread can lock a mutex. 370 struct _Can_lock 371 { 372 // Returns true if the mutex is unlocked or is locked by _M_caller. 373 bool 374 operator()() const noexcept 375 { return _M_mx->_M_count == 0 || _M_mx->_M_owner == _M_caller; } 376 377 const recursive_timed_mutex* _M_mx; 378 thread::id _M_caller; 379 }; 380 381 public: 382 383 recursive_timed_mutex() = default; 384 ~recursive_timed_mutex() { __glibcxx_assert( _M_count == 0 ); } 385 386 recursive_timed_mutex(const recursive_timed_mutex&) = delete; 387 recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; 388 389 void 390 lock() 391 { 392 auto __id = this_thread::get_id(); 393 _Can_lock __can_lock{this, __id}; 394 unique_lock<mutex> __lk(_M_mut); 395 _M_cv.wait(__lk, __can_lock); 396 if (_M_count == -1u) 397 __throw_system_error(EAGAIN); // [thread.timedmutex.recursive]/3 398 _M_owner = __id; 399 ++_M_count; 400 } 401 402 bool 403 try_lock() 404 { 405 auto __id = this_thread::get_id(); 406 _Can_lock __can_lock{this, __id}; 407 lock_guard<mutex> __lk(_M_mut); 408 if (!__can_lock()) 409 return false; 410 if (_M_count == -1u) 411 return false; 412 _M_owner = __id; 413 ++_M_count; 414 return true; 415 } 416 417 template<typename _Rep, typename _Period> 418 bool 419 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 420 { 421 auto __id = this_thread::get_id(); 422 _Can_lock __can_lock{this, __id}; 423 unique_lock<mutex> __lk(_M_mut); 424 if (!_M_cv.wait_for(__lk, __rtime, __can_lock)) 425 return false; 426 if (_M_count == -1u) 427 return false; 428 _M_owner = __id; 429 ++_M_count; 430 return true; 431 } 432 433 template<typename _Clock, typename _Duration> 434 bool 435 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 436 { 437 auto __id = this_thread::get_id(); 438 _Can_lock __can_lock{this, __id}; 439 unique_lock<mutex> __lk(_M_mut); 440 if (!_M_cv.wait_until(__lk, __atime, __can_lock)) 441 return false; 442 if (_M_count == -1u) 443 return false; 444 _M_owner = __id; 445 ++_M_count; 446 return true; 447 } 448 449 void 450 unlock() 451 { 452 lock_guard<mutex> __lk(_M_mut); 453 __glibcxx_assert( _M_owner == this_thread::get_id() ); 454 __glibcxx_assert( _M_count > 0 ); 455 if (--_M_count == 0) 456 { 457 _M_owner = {}; 458 _M_cv.notify_one(); 459 } 460 } 461 }; 462 463#endif 464#endif // _GLIBCXX_HAS_GTHREADS 465 466 template<typename _Lock> 467 inline unique_lock<_Lock> 468 __try_to_lock(_Lock& __l) 469 { return unique_lock<_Lock>{__l, try_to_lock}; } 470 471 template<int _Idx, bool _Continue = true> 472 struct __try_lock_impl 473 { 474 template<typename... _Lock> 475 static void 476 __do_try_lock(tuple<_Lock&...>& __locks, int& __idx) 477 { 478 __idx = _Idx; 479 auto __lock = std::__try_to_lock(std::get<_Idx>(__locks)); 480 if (__lock.owns_lock()) 481 { 482 constexpr bool __cont = _Idx + 2 < sizeof...(_Lock); 483 using __try_locker = __try_lock_impl<_Idx + 1, __cont>; 484 __try_locker::__do_try_lock(__locks, __idx); 485 if (__idx == -1) 486 __lock.release(); 487 } 488 } 489 }; 490 491 template<int _Idx> 492 struct __try_lock_impl<_Idx, false> 493 { 494 template<typename... _Lock> 495 static void 496 __do_try_lock(tuple<_Lock&...>& __locks, int& __idx) 497 { 498 __idx = _Idx; 499 auto __lock = std::__try_to_lock(std::get<_Idx>(__locks)); 500 if (__lock.owns_lock()) 501 { 502 __idx = -1; 503 __lock.release(); 504 } 505 } 506 }; 507 508 /** @brief Generic try_lock. 509 * @param __l1 Meets Lockable requirements (try_lock() may throw). 510 * @param __l2 Meets Lockable requirements (try_lock() may throw). 511 * @param __l3 Meets Lockable requirements (try_lock() may throw). 512 * @return Returns -1 if all try_lock() calls return true. Otherwise returns 513 * a 0-based index corresponding to the argument that returned false. 514 * @post Either all arguments are locked, or none will be. 515 * 516 * Sequentially calls try_lock() on each argument. 517 */ 518 template<typename _Lock1, typename _Lock2, typename... _Lock3> 519 int 520 try_lock(_Lock1& __l1, _Lock2& __l2, _Lock3&... __l3) 521 { 522 int __idx; 523 auto __locks = std::tie(__l1, __l2, __l3...); 524 __try_lock_impl<0>::__do_try_lock(__locks, __idx); 525 return __idx; 526 } 527 528 /** @brief Generic lock. 529 * @param __l1 Meets Lockable requirements (try_lock() may throw). 530 * @param __l2 Meets Lockable requirements (try_lock() may throw). 531 * @param __l3 Meets Lockable requirements (try_lock() may throw). 532 * @throw An exception thrown by an argument's lock() or try_lock() member. 533 * @post All arguments are locked. 534 * 535 * All arguments are locked via a sequence of calls to lock(), try_lock() 536 * and unlock(). If the call exits via an exception any locks that were 537 * obtained will be released. 538 */ 539 template<typename _L1, typename _L2, typename... _L3> 540 void 541 lock(_L1& __l1, _L2& __l2, _L3&... __l3) 542 { 543 while (true) 544 { 545 using __try_locker = __try_lock_impl<0, sizeof...(_L3) != 0>; 546 unique_lock<_L1> __first(__l1); 547 int __idx; 548 auto __locks = std::tie(__l2, __l3...); 549 __try_locker::__do_try_lock(__locks, __idx); 550 if (__idx == -1) 551 { 552 __first.release(); 553 return; 554 } 555 } 556 } 557 558#if __cplusplus >= 201703L 559#define __cpp_lib_scoped_lock 201703 560 /** @brief A scoped lock type for multiple lockable objects. 561 * 562 * A scoped_lock controls mutex ownership within a scope, releasing 563 * ownership in the destructor. 564 */ 565 template<typename... _MutexTypes> 566 class scoped_lock 567 { 568 public: 569 explicit scoped_lock(_MutexTypes&... __m) : _M_devices(std::tie(__m...)) 570 { std::lock(__m...); } 571 572 explicit scoped_lock(adopt_lock_t, _MutexTypes&... __m) noexcept 573 : _M_devices(std::tie(__m...)) 574 { } // calling thread owns mutex 575 576 ~scoped_lock() 577 { 578 std::apply([](_MutexTypes&... __m) { 579 char __i[] __attribute__((__unused__)) = { (__m.unlock(), 0)... }; 580 }, _M_devices); 581 } 582 583 scoped_lock(const scoped_lock&) = delete; 584 scoped_lock& operator=(const scoped_lock&) = delete; 585 586 private: 587 tuple<_MutexTypes&...> _M_devices; 588 }; 589 590 template<> 591 class scoped_lock<> 592 { 593 public: 594 explicit scoped_lock() = default; 595 explicit scoped_lock(adopt_lock_t) noexcept { } 596 ~scoped_lock() = default; 597 598 scoped_lock(const scoped_lock&) = delete; 599 scoped_lock& operator=(const scoped_lock&) = delete; 600 }; 601 602 template<typename _Mutex> 603 class scoped_lock<_Mutex> 604 { 605 public: 606 using mutex_type = _Mutex; 607 608 explicit scoped_lock(mutex_type& __m) : _M_device(__m) 609 { _M_device.lock(); } 610 611 explicit scoped_lock(adopt_lock_t, mutex_type& __m) noexcept 612 : _M_device(__m) 613 { } // calling thread owns mutex 614 615 ~scoped_lock() 616 { _M_device.unlock(); } 617 618 scoped_lock(const scoped_lock&) = delete; 619 scoped_lock& operator=(const scoped_lock&) = delete; 620 621 private: 622 mutex_type& _M_device; 623 }; 624#endif // C++17 625 626#ifdef _GLIBCXX_HAS_GTHREADS 627 /// once_flag 628 struct once_flag 629 { 630 private: 631 typedef __gthread_once_t __native_type; 632 __native_type _M_once = __GTHREAD_ONCE_INIT; 633 634 public: 635 /// Constructor 636 constexpr once_flag() noexcept = default; 637 638 /// Deleted copy constructor 639 once_flag(const once_flag&) = delete; 640 /// Deleted assignment operator 641 once_flag& operator=(const once_flag&) = delete; 642 643 template<typename _Callable, typename... _Args> 644 friend void 645 call_once(once_flag& __once, _Callable&& __f, _Args&&... __args); 646 }; 647 648#ifdef _GLIBCXX_HAVE_TLS 649 extern __thread void* __once_callable; 650 extern __thread void (*__once_call)(); 651#else 652 extern function<void()> __once_functor; 653 654 extern void 655 __set_once_functor_lock_ptr(unique_lock<mutex>*); 656 657 extern mutex& 658 __get_once_mutex(); 659#endif 660 661 extern "C" void __once_proxy(void); 662 663 /// call_once 664 template<typename _Callable, typename... _Args> 665 void 666 call_once(once_flag& __once, _Callable&& __f, _Args&&... __args) 667 { 668 // _GLIBCXX_RESOLVE_LIB_DEFECTS 669 // 2442. call_once() shouldn't DECAY_COPY() 670 auto __callable = [&] { 671 std::__invoke(std::forward<_Callable>(__f), 672 std::forward<_Args>(__args)...); 673 }; 674#ifdef _GLIBCXX_HAVE_TLS 675 __once_callable = std::__addressof(__callable); // NOLINT: PR 82481 676 __once_call = []{ (*(decltype(__callable)*)__once_callable)(); }; 677#else 678 unique_lock<mutex> __functor_lock(__get_once_mutex()); 679 __once_functor = __callable; 680 __set_once_functor_lock_ptr(&__functor_lock); 681#endif 682 683 int __e = __gthread_once(&__once._M_once, &__once_proxy); 684 685#ifndef _GLIBCXX_HAVE_TLS 686 if (__functor_lock) 687 __set_once_functor_lock_ptr(0); 688#endif 689 690 if (__e) 691 __throw_system_error(__e); 692 } 693#endif // _GLIBCXX_HAS_GTHREADS 694 695 /// @} group mutexes 696_GLIBCXX_END_NAMESPACE_VERSION 697} // namespace 698 699#endif // C++11 700 701#endif // _GLIBCXX_MUTEX 702