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