1 // <mutex> -*- C++ -*- 2 3 // Copyright (C) 2003-2013 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 <functional> 43 #include <system_error> 44 #include <bits/functexcept.h> 45 #include <bits/gthr.h> 46 #include <bits/move.h> // for std::swap 47 48 #ifdef _GLIBCXX_USE_C99_STDINT_TR1 49 50 namespace std _GLIBCXX_VISIBILITY(default) 51 { 52 _GLIBCXX_BEGIN_NAMESPACE_VERSION 53 54 #ifdef _GLIBCXX_HAS_GTHREADS 55 // Common base class for std::mutex and std::timed_mutex 56 class __mutex_base 57 { 58 protected: 59 typedef __gthread_mutex_t __native_type; 60 61 #ifdef __GTHREAD_MUTEX_INIT 62 __native_type _M_mutex = __GTHREAD_MUTEX_INIT; 63 64 constexpr __mutex_base() noexcept = default; 65 #else 66 __native_type _M_mutex; 67 68 __mutex_base() noexcept 69 { 70 // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may) 71 __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex); 72 } 73 74 ~__mutex_base() noexcept { __gthread_mutex_destroy(&_M_mutex); } 75 #endif 76 77 __mutex_base(const __mutex_base&) = delete; 78 __mutex_base& operator=(const __mutex_base&) = delete; 79 }; 80 81 // Common base class for std::recursive_mutex and std::timed_recursive_mutex 82 class __recursive_mutex_base 83 { 84 protected: 85 typedef __gthread_recursive_mutex_t __native_type; 86 87 __recursive_mutex_base(const __recursive_mutex_base&) = delete; 88 __recursive_mutex_base& operator=(const __recursive_mutex_base&) = delete; 89 90 #ifdef __GTHREAD_RECURSIVE_MUTEX_INIT 91 __native_type _M_mutex = __GTHREAD_RECURSIVE_MUTEX_INIT; 92 93 __recursive_mutex_base() = default; 94 #else 95 __native_type _M_mutex; 96 97 __recursive_mutex_base() 98 { 99 // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may) 100 __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex); 101 } 102 103 ~__recursive_mutex_base() 104 { __gthread_recursive_mutex_destroy(&_M_mutex); } 105 #endif 106 }; 107 108 /** 109 * @defgroup mutexes Mutexes 110 * @ingroup concurrency 111 * 112 * Classes for mutex support. 113 * @{ 114 */ 115 116 /// mutex 117 class mutex : private __mutex_base 118 { 119 public: 120 typedef __native_type* native_handle_type; 121 122 #ifdef __GTHREAD_MUTEX_INIT 123 constexpr 124 #endif 125 mutex() noexcept = default; 126 ~mutex() = default; 127 128 mutex(const mutex&) = delete; 129 mutex& operator=(const mutex&) = delete; 130 131 void 132 lock() 133 { 134 int __e = __gthread_mutex_lock(&_M_mutex); 135 136 // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) 137 if (__e) 138 __throw_system_error(__e); 139 } 140 141 bool 142 try_lock() noexcept 143 { 144 // XXX EINVAL, EAGAIN, EBUSY 145 return !__gthread_mutex_trylock(&_M_mutex); 146 } 147 148 void 149 unlock() 150 { 151 // XXX EINVAL, EAGAIN, EPERM 152 __gthread_mutex_unlock(&_M_mutex); 153 } 154 155 native_handle_type 156 native_handle() 157 { return &_M_mutex; } 158 }; 159 160 /// recursive_mutex 161 class recursive_mutex : private __recursive_mutex_base 162 { 163 public: 164 typedef __native_type* native_handle_type; 165 166 recursive_mutex() = default; 167 ~recursive_mutex() = default; 168 169 recursive_mutex(const recursive_mutex&) = delete; 170 recursive_mutex& operator=(const recursive_mutex&) = delete; 171 172 void 173 lock() 174 { 175 int __e = __gthread_recursive_mutex_lock(&_M_mutex); 176 177 // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) 178 if (__e) 179 __throw_system_error(__e); 180 } 181 182 bool 183 try_lock() noexcept 184 { 185 // XXX EINVAL, EAGAIN, EBUSY 186 return !__gthread_recursive_mutex_trylock(&_M_mutex); 187 } 188 189 void 190 unlock() 191 { 192 // XXX EINVAL, EAGAIN, EBUSY 193 __gthread_recursive_mutex_unlock(&_M_mutex); 194 } 195 196 native_handle_type 197 native_handle() 198 { return &_M_mutex; } 199 }; 200 201 #if _GTHREAD_USE_MUTEX_TIMEDLOCK 202 /// timed_mutex 203 class timed_mutex : private __mutex_base 204 { 205 #ifdef _GLIBCXX_USE_CLOCK_MONOTONIC 206 typedef chrono::steady_clock __clock_t; 207 #else 208 typedef chrono::high_resolution_clock __clock_t; 209 #endif 210 211 public: 212 typedef __native_type* native_handle_type; 213 214 timed_mutex() = default; 215 ~timed_mutex() = default; 216 217 timed_mutex(const timed_mutex&) = delete; 218 timed_mutex& operator=(const timed_mutex&) = delete; 219 220 void 221 lock() 222 { 223 int __e = __gthread_mutex_lock(&_M_mutex); 224 225 // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) 226 if (__e) 227 __throw_system_error(__e); 228 } 229 230 bool 231 try_lock() noexcept 232 { 233 // XXX EINVAL, EAGAIN, EBUSY 234 return !__gthread_mutex_trylock(&_M_mutex); 235 } 236 237 template <class _Rep, class _Period> 238 bool 239 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 240 { return _M_try_lock_for(__rtime); } 241 242 template <class _Clock, class _Duration> 243 bool 244 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 245 { return _M_try_lock_until(__atime); } 246 247 void 248 unlock() 249 { 250 // XXX EINVAL, EAGAIN, EBUSY 251 __gthread_mutex_unlock(&_M_mutex); 252 } 253 254 native_handle_type 255 native_handle() 256 { return &_M_mutex; } 257 258 private: 259 template<typename _Rep, typename _Period> 260 bool 261 _M_try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 262 { 263 auto __rt = chrono::duration_cast<__clock_t::duration>(__rtime); 264 if (ratio_greater<__clock_t::period, _Period>()) 265 ++__rt; 266 267 return _M_try_lock_until(__clock_t::now() + __rt); 268 } 269 270 template<typename _Duration> 271 bool 272 _M_try_lock_until(const chrono::time_point<__clock_t, 273 _Duration>& __atime) 274 { 275 chrono::time_point<__clock_t, chrono::seconds> __s = 276 chrono::time_point_cast<chrono::seconds>(__atime); 277 278 chrono::nanoseconds __ns = 279 chrono::duration_cast<chrono::nanoseconds>(__atime - __s); 280 281 __gthread_time_t __ts = { 282 static_cast<std::time_t>(__s.time_since_epoch().count()), 283 static_cast<long>(__ns.count()) 284 }; 285 286 return !__gthread_mutex_timedlock(native_handle(), &__ts); 287 } 288 289 template<typename _Clock, typename _Duration> 290 bool 291 _M_try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 292 { return _M_try_lock_for(__atime - _Clock::now()); } 293 }; 294 295 /// recursive_timed_mutex 296 class recursive_timed_mutex : private __recursive_mutex_base 297 { 298 #ifdef _GLIBCXX_USE_CLOCK_MONOTONIC 299 typedef chrono::steady_clock __clock_t; 300 #else 301 typedef chrono::high_resolution_clock __clock_t; 302 #endif 303 304 public: 305 typedef __native_type* native_handle_type; 306 307 recursive_timed_mutex() = default; 308 ~recursive_timed_mutex() = default; 309 310 recursive_timed_mutex(const recursive_timed_mutex&) = delete; 311 recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; 312 313 void 314 lock() 315 { 316 int __e = __gthread_recursive_mutex_lock(&_M_mutex); 317 318 // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may) 319 if (__e) 320 __throw_system_error(__e); 321 } 322 323 bool 324 try_lock() noexcept 325 { 326 // XXX EINVAL, EAGAIN, EBUSY 327 return !__gthread_recursive_mutex_trylock(&_M_mutex); 328 } 329 330 template <class _Rep, class _Period> 331 bool 332 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 333 { return _M_try_lock_for(__rtime); } 334 335 template <class _Clock, class _Duration> 336 bool 337 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 338 { return _M_try_lock_until(__atime); } 339 340 void 341 unlock() 342 { 343 // XXX EINVAL, EAGAIN, EBUSY 344 __gthread_recursive_mutex_unlock(&_M_mutex); 345 } 346 347 native_handle_type 348 native_handle() 349 { return &_M_mutex; } 350 351 private: 352 template<typename _Rep, typename _Period> 353 bool 354 _M_try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 355 { 356 auto __rt = chrono::duration_cast<__clock_t::duration>(__rtime); 357 if (ratio_greater<__clock_t::period, _Period>()) 358 ++__rt; 359 360 return _M_try_lock_until(__clock_t::now() + __rt); 361 } 362 363 template<typename _Duration> 364 bool 365 _M_try_lock_until(const chrono::time_point<__clock_t, 366 _Duration>& __atime) 367 { 368 chrono::time_point<__clock_t, chrono::seconds> __s = 369 chrono::time_point_cast<chrono::seconds>(__atime); 370 371 chrono::nanoseconds __ns = 372 chrono::duration_cast<chrono::nanoseconds>(__atime - __s); 373 374 __gthread_time_t __ts = { 375 static_cast<std::time_t>(__s.time_since_epoch().count()), 376 static_cast<long>(__ns.count()) 377 }; 378 379 return !__gthread_mutex_timedlock(native_handle(), &__ts); 380 } 381 382 template<typename _Clock, typename _Duration> 383 bool 384 _M_try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 385 { return _M_try_lock_for(__atime - _Clock::now()); } 386 }; 387 #endif 388 #endif // _GLIBCXX_HAS_GTHREADS 389 390 /// Do not acquire ownership of the mutex. 391 struct defer_lock_t { }; 392 393 /// Try to acquire ownership of the mutex without blocking. 394 struct try_to_lock_t { }; 395 396 /// Assume the calling thread has already obtained mutex ownership 397 /// and manage it. 398 struct adopt_lock_t { }; 399 400 constexpr defer_lock_t defer_lock { }; 401 constexpr try_to_lock_t try_to_lock { }; 402 constexpr adopt_lock_t adopt_lock { }; 403 404 /// @brief Scoped lock idiom. 405 // Acquire the mutex here with a constructor call, then release with 406 // the destructor call in accordance with RAII style. 407 template<typename _Mutex> 408 class lock_guard 409 { 410 public: 411 typedef _Mutex mutex_type; 412 413 explicit lock_guard(mutex_type& __m) : _M_device(__m) 414 { _M_device.lock(); } 415 416 lock_guard(mutex_type& __m, adopt_lock_t) : _M_device(__m) 417 { } // calling thread owns mutex 418 419 ~lock_guard() 420 { _M_device.unlock(); } 421 422 lock_guard(const lock_guard&) = delete; 423 lock_guard& operator=(const lock_guard&) = delete; 424 425 private: 426 mutex_type& _M_device; 427 }; 428 429 /// unique_lock 430 template<typename _Mutex> 431 class unique_lock 432 { 433 public: 434 typedef _Mutex mutex_type; 435 436 unique_lock() noexcept 437 : _M_device(0), _M_owns(false) 438 { } 439 440 explicit unique_lock(mutex_type& __m) 441 : _M_device(&__m), _M_owns(false) 442 { 443 lock(); 444 _M_owns = true; 445 } 446 447 unique_lock(mutex_type& __m, defer_lock_t) noexcept 448 : _M_device(&__m), _M_owns(false) 449 { } 450 451 unique_lock(mutex_type& __m, try_to_lock_t) 452 : _M_device(&__m), _M_owns(_M_device->try_lock()) 453 { } 454 455 unique_lock(mutex_type& __m, adopt_lock_t) 456 : _M_device(&__m), _M_owns(true) 457 { 458 // XXX calling thread owns mutex 459 } 460 461 template<typename _Clock, typename _Duration> 462 unique_lock(mutex_type& __m, 463 const chrono::time_point<_Clock, _Duration>& __atime) 464 : _M_device(&__m), _M_owns(_M_device->try_lock_until(__atime)) 465 { } 466 467 template<typename _Rep, typename _Period> 468 unique_lock(mutex_type& __m, 469 const chrono::duration<_Rep, _Period>& __rtime) 470 : _M_device(&__m), _M_owns(_M_device->try_lock_for(__rtime)) 471 { } 472 473 ~unique_lock() 474 { 475 if (_M_owns) 476 unlock(); 477 } 478 479 unique_lock(const unique_lock&) = delete; 480 unique_lock& operator=(const unique_lock&) = delete; 481 482 unique_lock(unique_lock&& __u) noexcept 483 : _M_device(__u._M_device), _M_owns(__u._M_owns) 484 { 485 __u._M_device = 0; 486 __u._M_owns = false; 487 } 488 489 unique_lock& operator=(unique_lock&& __u) noexcept 490 { 491 if(_M_owns) 492 unlock(); 493 494 unique_lock(std::move(__u)).swap(*this); 495 496 __u._M_device = 0; 497 __u._M_owns = false; 498 499 return *this; 500 } 501 502 void 503 lock() 504 { 505 if (!_M_device) 506 __throw_system_error(int(errc::operation_not_permitted)); 507 else if (_M_owns) 508 __throw_system_error(int(errc::resource_deadlock_would_occur)); 509 else 510 { 511 _M_device->lock(); 512 _M_owns = true; 513 } 514 } 515 516 bool 517 try_lock() 518 { 519 if (!_M_device) 520 __throw_system_error(int(errc::operation_not_permitted)); 521 else if (_M_owns) 522 __throw_system_error(int(errc::resource_deadlock_would_occur)); 523 else 524 { 525 _M_owns = _M_device->try_lock(); 526 return _M_owns; 527 } 528 } 529 530 template<typename _Clock, typename _Duration> 531 bool 532 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) 533 { 534 if (!_M_device) 535 __throw_system_error(int(errc::operation_not_permitted)); 536 else if (_M_owns) 537 __throw_system_error(int(errc::resource_deadlock_would_occur)); 538 else 539 { 540 _M_owns = _M_device->try_lock_until(__atime); 541 return _M_owns; 542 } 543 } 544 545 template<typename _Rep, typename _Period> 546 bool 547 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) 548 { 549 if (!_M_device) 550 __throw_system_error(int(errc::operation_not_permitted)); 551 else if (_M_owns) 552 __throw_system_error(int(errc::resource_deadlock_would_occur)); 553 else 554 { 555 _M_owns = _M_device->try_lock_for(__rtime); 556 return _M_owns; 557 } 558 } 559 560 void 561 unlock() 562 { 563 if (!_M_owns) 564 __throw_system_error(int(errc::operation_not_permitted)); 565 else if (_M_device) 566 { 567 _M_device->unlock(); 568 _M_owns = false; 569 } 570 } 571 572 void 573 swap(unique_lock& __u) noexcept 574 { 575 std::swap(_M_device, __u._M_device); 576 std::swap(_M_owns, __u._M_owns); 577 } 578 579 mutex_type* 580 release() noexcept 581 { 582 mutex_type* __ret = _M_device; 583 _M_device = 0; 584 _M_owns = false; 585 return __ret; 586 } 587 588 bool 589 owns_lock() const noexcept 590 { return _M_owns; } 591 592 explicit operator bool() const noexcept 593 { return owns_lock(); } 594 595 mutex_type* 596 mutex() const noexcept 597 { return _M_device; } 598 599 private: 600 mutex_type* _M_device; 601 bool _M_owns; // XXX use atomic_bool 602 }; 603 604 /// Partial specialization for unique_lock objects. 605 template<typename _Mutex> 606 inline void 607 swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) noexcept 608 { __x.swap(__y); } 609 610 template<int _Idx> 611 struct __unlock_impl 612 { 613 template<typename... _Lock> 614 static void 615 __do_unlock(tuple<_Lock&...>& __locks) 616 { 617 std::get<_Idx>(__locks).unlock(); 618 __unlock_impl<_Idx - 1>::__do_unlock(__locks); 619 } 620 }; 621 622 template<> 623 struct __unlock_impl<-1> 624 { 625 template<typename... _Lock> 626 static void 627 __do_unlock(tuple<_Lock&...>&) 628 { } 629 }; 630 631 template<typename _Lock> 632 unique_lock<_Lock> 633 __try_to_lock(_Lock& __l) 634 { return unique_lock<_Lock>(__l, try_to_lock); } 635 636 template<int _Idx, bool _Continue = true> 637 struct __try_lock_impl 638 { 639 template<typename... _Lock> 640 static void 641 __do_try_lock(tuple<_Lock&...>& __locks, int& __idx) 642 { 643 __idx = _Idx; 644 auto __lock = __try_to_lock(std::get<_Idx>(__locks)); 645 if (__lock.owns_lock()) 646 { 647 __try_lock_impl<_Idx + 1, _Idx + 2 < sizeof...(_Lock)>:: 648 __do_try_lock(__locks, __idx); 649 if (__idx == -1) 650 __lock.release(); 651 } 652 } 653 }; 654 655 template<int _Idx> 656 struct __try_lock_impl<_Idx, false> 657 { 658 template<typename... _Lock> 659 static void 660 __do_try_lock(tuple<_Lock&...>& __locks, int& __idx) 661 { 662 __idx = _Idx; 663 auto __lock = __try_to_lock(std::get<_Idx>(__locks)); 664 if (__lock.owns_lock()) 665 { 666 __idx = -1; 667 __lock.release(); 668 } 669 } 670 }; 671 672 /** @brief Generic try_lock. 673 * @param __l1 Meets Mutex requirements (try_lock() may throw). 674 * @param __l2 Meets Mutex requirements (try_lock() may throw). 675 * @param __l3 Meets Mutex requirements (try_lock() may throw). 676 * @return Returns -1 if all try_lock() calls return true. Otherwise returns 677 * a 0-based index corresponding to the argument that returned false. 678 * @post Either all arguments are locked, or none will be. 679 * 680 * Sequentially calls try_lock() on each argument. 681 */ 682 template<typename _Lock1, typename _Lock2, typename... _Lock3> 683 int 684 try_lock(_Lock1& __l1, _Lock2& __l2, _Lock3&... __l3) 685 { 686 int __idx; 687 auto __locks = std::tie(__l1, __l2, __l3...); 688 __try 689 { __try_lock_impl<0>::__do_try_lock(__locks, __idx); } 690 __catch(...) 691 { } 692 return __idx; 693 } 694 695 /** @brief Generic lock. 696 * @param __l1 Meets Mutex requirements (try_lock() may throw). 697 * @param __l2 Meets Mutex requirements (try_lock() may throw). 698 * @param __l3 Meets Mutex requirements (try_lock() may throw). 699 * @throw An exception thrown by an argument's lock() or try_lock() member. 700 * @post All arguments are locked. 701 * 702 * All arguments are locked via a sequence of calls to lock(), try_lock() 703 * and unlock(). If the call exits via an exception any locks that were 704 * obtained will be released. 705 */ 706 template<typename _L1, typename _L2, typename ..._L3> 707 void 708 lock(_L1& __l1, _L2& __l2, _L3&... __l3) 709 { 710 while (true) 711 { 712 unique_lock<_L1> __first(__l1); 713 int __idx; 714 auto __locks = std::tie(__l2, __l3...); 715 __try_lock_impl<0, sizeof...(_L3)>::__do_try_lock(__locks, __idx); 716 if (__idx == -1) 717 { 718 __first.release(); 719 return; 720 } 721 } 722 } 723 724 #ifdef _GLIBCXX_HAS_GTHREADS 725 /// once_flag 726 struct once_flag 727 { 728 private: 729 typedef __gthread_once_t __native_type; 730 __native_type _M_once = __GTHREAD_ONCE_INIT; 731 732 public: 733 /// Constructor 734 constexpr once_flag() noexcept = default; 735 736 /// Deleted copy constructor 737 once_flag(const once_flag&) = delete; 738 /// Deleted assignment operator 739 once_flag& operator=(const once_flag&) = delete; 740 741 template<typename _Callable, typename... _Args> 742 friend void 743 call_once(once_flag& __once, _Callable&& __f, _Args&&... __args); 744 }; 745 746 #ifdef _GLIBCXX_HAVE_TLS 747 extern __thread void* __once_callable; 748 extern __thread void (*__once_call)(); 749 750 template<typename _Callable> 751 inline void 752 __once_call_impl() 753 { 754 (*(_Callable*)__once_callable)(); 755 } 756 #else 757 extern function<void()> __once_functor; 758 759 extern void 760 __set_once_functor_lock_ptr(unique_lock<mutex>*); 761 762 extern mutex& 763 __get_once_mutex(); 764 #endif 765 766 extern "C" void __once_proxy(void); 767 768 /// call_once 769 template<typename _Callable, typename... _Args> 770 void 771 call_once(once_flag& __once, _Callable&& __f, _Args&&... __args) 772 { 773 #ifdef _GLIBCXX_HAVE_TLS 774 auto __bound_functor = std::__bind_simple(std::forward<_Callable>(__f), 775 std::forward<_Args>(__args)...); 776 __once_callable = &__bound_functor; 777 __once_call = &__once_call_impl<decltype(__bound_functor)>; 778 #else 779 unique_lock<mutex> __functor_lock(__get_once_mutex()); 780 auto __callable = std::__bind_simple(std::forward<_Callable>(__f), 781 std::forward<_Args>(__args)...); 782 __once_functor = [&]() { __callable(); }; 783 __set_once_functor_lock_ptr(&__functor_lock); 784 #endif 785 786 int __e = __gthread_once(&(__once._M_once), &__once_proxy); 787 788 #ifndef _GLIBCXX_HAVE_TLS 789 if (__functor_lock) 790 __set_once_functor_lock_ptr(0); 791 #endif 792 793 if (__e) 794 __throw_system_error(__e); 795 } 796 #endif // _GLIBCXX_HAS_GTHREADS 797 798 // @} group mutexes 799 _GLIBCXX_END_NAMESPACE_VERSION 800 } // namespace 801 #endif // _GLIBCXX_USE_C99_STDINT_TR1 802 803 #endif // C++11 804 805 #endif // _GLIBCXX_MUTEX 806