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