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