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