libstdc++
mutex
Go to the documentation of this file.
00001 // <mutex> -*- C++ -*-
00002 
00003 // Copyright (C) 2003-2015 Free Software Foundation, Inc.
00004 //
00005 // This file is part of the GNU ISO C++ Library.  This library is free
00006 // software; you can redistribute it and/or modify it under the
00007 // terms of the GNU General Public License as published by the
00008 // Free Software Foundation; either version 3, or (at your option)
00009 // any later version.
00010 
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 // GNU General Public License for more details.
00015 
00016 // Under Section 7 of GPL version 3, you are granted additional
00017 // permissions described in the GCC Runtime Library Exception, version
00018 // 3.1, as published by the Free Software Foundation.
00019 
00020 // You should have received a copy of the GNU General Public License and
00021 // a copy of the GCC Runtime Library Exception along with this program;
00022 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
00023 // <http://www.gnu.org/licenses/>.
00024 
00025 /** @file include/mutex
00026  *  This is a Standard C++ Library header.
00027  */
00028 
00029 #ifndef _GLIBCXX_MUTEX
00030 #define _GLIBCXX_MUTEX 1
00031 
00032 #pragma GCC system_header
00033 
00034 #if __cplusplus < 201103L
00035 # include <bits/c++0x_warning.h>
00036 #else
00037 
00038 #include <tuple>
00039 #include <chrono>
00040 #include <exception>
00041 #include <type_traits>
00042 #include <functional>
00043 #include <system_error>
00044 #include <bits/functexcept.h>
00045 #include <bits/gthr.h>
00046 #include <bits/move.h> // for std::swap
00047 #include <bits/cxxabi_forced.h>
00048 
00049 #ifdef _GLIBCXX_USE_C99_STDINT_TR1
00050 
00051 namespace std _GLIBCXX_VISIBILITY(default)
00052 {
00053 _GLIBCXX_BEGIN_NAMESPACE_VERSION
00054 
00055 #ifdef _GLIBCXX_HAS_GTHREADS
00056   // Common base class for std::mutex and std::timed_mutex
00057   class __mutex_base
00058   {
00059   protected:
00060     typedef __gthread_mutex_t                   __native_type;
00061 
00062 #ifdef __GTHREAD_MUTEX_INIT
00063     __native_type  _M_mutex = __GTHREAD_MUTEX_INIT;
00064 
00065     constexpr __mutex_base() noexcept = default;
00066 #else
00067     __native_type  _M_mutex;
00068 
00069     __mutex_base() noexcept
00070     {
00071       // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
00072       __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex);
00073     }
00074 
00075     ~__mutex_base() noexcept { __gthread_mutex_destroy(&_M_mutex); }
00076 #endif
00077 
00078     __mutex_base(const __mutex_base&) = delete;
00079     __mutex_base& operator=(const __mutex_base&) = delete;
00080   };
00081 
00082   // Common base class for std::recursive_mutex and std::recursive_timed_mutex
00083   class __recursive_mutex_base
00084   {
00085   protected:
00086     typedef __gthread_recursive_mutex_t         __native_type;
00087 
00088     __recursive_mutex_base(const __recursive_mutex_base&) = delete;
00089     __recursive_mutex_base& operator=(const __recursive_mutex_base&) = delete;
00090 
00091 #ifdef __GTHREAD_RECURSIVE_MUTEX_INIT
00092     __native_type  _M_mutex = __GTHREAD_RECURSIVE_MUTEX_INIT;
00093 
00094     __recursive_mutex_base() = default;
00095 #else
00096     __native_type  _M_mutex;
00097 
00098     __recursive_mutex_base()
00099     {
00100       // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
00101       __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
00102     }
00103 
00104     ~__recursive_mutex_base()
00105     { __gthread_recursive_mutex_destroy(&_M_mutex); }
00106 #endif
00107   };
00108 
00109   /**
00110    * @defgroup mutexes Mutexes
00111    * @ingroup concurrency
00112    *
00113    * Classes for mutex support.
00114    * @{
00115    */
00116 
00117   /// The standard mutex type.
00118   class mutex : private __mutex_base
00119   {
00120   public:
00121     typedef __native_type*                      native_handle_type;
00122 
00123 #ifdef __GTHREAD_MUTEX_INIT
00124     constexpr
00125 #endif
00126     mutex() noexcept = default;
00127     ~mutex() = default;
00128 
00129     mutex(const mutex&) = delete;
00130     mutex& operator=(const mutex&) = delete;
00131 
00132     void
00133     lock()
00134     {
00135       int __e = __gthread_mutex_lock(&_M_mutex);
00136 
00137       // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
00138       if (__e)
00139         __throw_system_error(__e);
00140     }
00141 
00142     bool
00143     try_lock() noexcept
00144     {
00145       // XXX EINVAL, EAGAIN, EBUSY
00146       return !__gthread_mutex_trylock(&_M_mutex);
00147     }
00148 
00149     void
00150     unlock()
00151     {
00152       // XXX EINVAL, EAGAIN, EPERM
00153       __gthread_mutex_unlock(&_M_mutex);
00154     }
00155 
00156     native_handle_type
00157     native_handle()
00158     { return &_M_mutex; }
00159   };
00160 
00161   /// The standard recursive mutex type.
00162   class recursive_mutex : private __recursive_mutex_base
00163   {
00164   public:
00165     typedef __native_type*                      native_handle_type;
00166 
00167     recursive_mutex() = default;
00168     ~recursive_mutex() = default;
00169 
00170     recursive_mutex(const recursive_mutex&) = delete;
00171     recursive_mutex& operator=(const recursive_mutex&) = delete;
00172 
00173     void
00174     lock()
00175     {
00176       int __e = __gthread_recursive_mutex_lock(&_M_mutex);
00177 
00178       // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
00179       if (__e)
00180         __throw_system_error(__e);
00181     }
00182 
00183     bool
00184     try_lock() noexcept
00185     {
00186       // XXX EINVAL, EAGAIN, EBUSY
00187       return !__gthread_recursive_mutex_trylock(&_M_mutex);
00188     }
00189 
00190     void
00191     unlock()
00192     {
00193       // XXX EINVAL, EAGAIN, EBUSY
00194       __gthread_recursive_mutex_unlock(&_M_mutex);
00195     }
00196 
00197     native_handle_type
00198     native_handle()
00199     { return &_M_mutex; }
00200   };
00201 
00202 #if _GTHREAD_USE_MUTEX_TIMEDLOCK
00203   template<typename _Derived>
00204     class __timed_mutex_impl
00205     {
00206     protected:
00207       typedef chrono::high_resolution_clock     __clock_t;
00208 
00209       template<typename _Rep, typename _Period>
00210         bool
00211         _M_try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
00212         {
00213           using chrono::steady_clock;
00214           auto __rt = chrono::duration_cast<steady_clock::duration>(__rtime);
00215           if (ratio_greater<steady_clock::period, _Period>())
00216             ++__rt;
00217           return _M_try_lock_until(steady_clock::now() + __rt);
00218         }
00219 
00220       template<typename _Duration>
00221         bool
00222         _M_try_lock_until(const chrono::time_point<__clock_t,
00223                                                    _Duration>& __atime)
00224         {
00225           auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
00226           auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
00227 
00228           __gthread_time_t __ts = {
00229             static_cast<std::time_t>(__s.time_since_epoch().count()),
00230             static_cast<long>(__ns.count())
00231           };
00232 
00233           auto __mutex = static_cast<_Derived*>(this)->native_handle();
00234           return !__gthread_mutex_timedlock(__mutex, &__ts);
00235         }
00236 
00237       template<typename _Clock, typename _Duration>
00238         bool
00239         _M_try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
00240         {
00241           auto __rtime = __atime - _Clock::now();
00242           return _M_try_lock_until(__clock_t::now() + __rtime);
00243         }
00244     };
00245 
00246   /// The standard timed mutex type.
00247   class timed_mutex
00248   : private __mutex_base, public __timed_mutex_impl<timed_mutex>
00249   {
00250   public:
00251     typedef __native_type*                      native_handle_type;
00252 
00253     timed_mutex() = default;
00254     ~timed_mutex() = default;
00255 
00256     timed_mutex(const timed_mutex&) = delete;
00257     timed_mutex& operator=(const timed_mutex&) = delete;
00258 
00259     void
00260     lock()
00261     {
00262       int __e = __gthread_mutex_lock(&_M_mutex);
00263 
00264       // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
00265       if (__e)
00266         __throw_system_error(__e);
00267     }
00268 
00269     bool
00270     try_lock() noexcept
00271     {
00272       // XXX EINVAL, EAGAIN, EBUSY
00273       return !__gthread_mutex_trylock(&_M_mutex);
00274     }
00275 
00276     template <class _Rep, class _Period>
00277       bool
00278       try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
00279       { return _M_try_lock_for(__rtime); }
00280 
00281     template <class _Clock, class _Duration>
00282       bool
00283       try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
00284       { return _M_try_lock_until(__atime); }
00285 
00286     void
00287     unlock()
00288     {
00289       // XXX EINVAL, EAGAIN, EBUSY
00290       __gthread_mutex_unlock(&_M_mutex);
00291     }
00292 
00293     native_handle_type
00294     native_handle()
00295     { return &_M_mutex; }
00296   };
00297 
00298   /// The standard recursive timed mutex type.
00299   class recursive_timed_mutex
00300   : private __recursive_mutex_base,
00301     public __timed_mutex_impl<recursive_timed_mutex>
00302   {
00303   public:
00304     typedef __native_type*                      native_handle_type;
00305 
00306     recursive_timed_mutex() = default;
00307     ~recursive_timed_mutex() = default;
00308 
00309     recursive_timed_mutex(const recursive_timed_mutex&) = delete;
00310     recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
00311 
00312     void
00313     lock()
00314     {
00315       int __e = __gthread_recursive_mutex_lock(&_M_mutex);
00316 
00317       // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
00318       if (__e)
00319         __throw_system_error(__e);
00320     }
00321 
00322     bool
00323     try_lock() noexcept
00324     {
00325       // XXX EINVAL, EAGAIN, EBUSY
00326       return !__gthread_recursive_mutex_trylock(&_M_mutex);
00327     }
00328 
00329     template <class _Rep, class _Period>
00330       bool
00331       try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
00332       { return _M_try_lock_for(__rtime); }
00333 
00334     template <class _Clock, class _Duration>
00335       bool
00336       try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
00337       { return _M_try_lock_until(__atime); }
00338 
00339     void
00340     unlock()
00341     {
00342       // XXX EINVAL, EAGAIN, EBUSY
00343       __gthread_recursive_mutex_unlock(&_M_mutex);
00344     }
00345 
00346     native_handle_type
00347     native_handle()
00348     { return &_M_mutex; }
00349   };
00350 #endif
00351 #endif // _GLIBCXX_HAS_GTHREADS
00352 
00353   /// Do not acquire ownership of the mutex.
00354   struct defer_lock_t { };
00355 
00356   /// Try to acquire ownership of the mutex without blocking.
00357   struct try_to_lock_t { };
00358 
00359   /// Assume the calling thread has already obtained mutex ownership
00360   /// and manage it.
00361   struct adopt_lock_t { };
00362 
00363   /// Tag used to prevent a scoped lock from acquiring ownership of a mutex.
00364   constexpr defer_lock_t        defer_lock { };
00365 
00366   /// Tag used to prevent a scoped lock from blocking if a mutex is locked.
00367   constexpr try_to_lock_t       try_to_lock { };
00368 
00369   /// Tag used to make a scoped lock take ownership of a locked mutex.
00370   constexpr adopt_lock_t        adopt_lock { };
00371 
00372   /** @brief A movable scoped lock type.
00373    *
00374    * A unique_lock controls mutex ownership within a scope. Ownership of the
00375    * mutex can be delayed until after construction and can be transferred
00376    * to another unique_lock by move construction or move assignment. If a
00377    * mutex lock is owned when the destructor runs ownership will be released.
00378    */
00379   template<typename _Mutex>
00380     class lock_guard
00381     {
00382     public:
00383       typedef _Mutex mutex_type;
00384 
00385       explicit lock_guard(mutex_type& __m) : _M_device(__m)
00386       { _M_device.lock(); }
00387 
00388       lock_guard(mutex_type& __m, adopt_lock_t) : _M_device(__m)
00389       { } // calling thread owns mutex
00390 
00391       ~lock_guard()
00392       { _M_device.unlock(); }
00393 
00394       lock_guard(const lock_guard&) = delete;
00395       lock_guard& operator=(const lock_guard&) = delete;
00396 
00397     private:
00398       mutex_type&  _M_device;
00399     };
00400 
00401   /// unique_lock
00402   template<typename _Mutex>
00403     class unique_lock
00404     {
00405     public:
00406       typedef _Mutex mutex_type;
00407 
00408       unique_lock() noexcept
00409       : _M_device(0), _M_owns(false)
00410       { }
00411 
00412       explicit unique_lock(mutex_type& __m)
00413       : _M_device(std::__addressof(__m)), _M_owns(false)
00414       {
00415         lock();
00416         _M_owns = true;
00417       }
00418 
00419       unique_lock(mutex_type& __m, defer_lock_t) noexcept
00420       : _M_device(std::__addressof(__m)), _M_owns(false)
00421       { }
00422 
00423       unique_lock(mutex_type& __m, try_to_lock_t)
00424       : _M_device(std::__addressof(__m)), _M_owns(_M_device->try_lock())
00425       { }
00426 
00427       unique_lock(mutex_type& __m, adopt_lock_t)
00428       : _M_device(std::__addressof(__m)), _M_owns(true)
00429       {
00430         // XXX calling thread owns mutex
00431       }
00432 
00433       template<typename _Clock, typename _Duration>
00434         unique_lock(mutex_type& __m,
00435                     const chrono::time_point<_Clock, _Duration>& __atime)
00436         : _M_device(std::__addressof(__m)),
00437           _M_owns(_M_device->try_lock_until(__atime))
00438         { }
00439 
00440       template<typename _Rep, typename _Period>
00441         unique_lock(mutex_type& __m,
00442                     const chrono::duration<_Rep, _Period>& __rtime)
00443         : _M_device(std::__addressof(__m)),
00444           _M_owns(_M_device->try_lock_for(__rtime))
00445         { }
00446 
00447       ~unique_lock()
00448       {
00449         if (_M_owns)
00450           unlock();
00451       }
00452 
00453       unique_lock(const unique_lock&) = delete;
00454       unique_lock& operator=(const unique_lock&) = delete;
00455 
00456       unique_lock(unique_lock&& __u) noexcept
00457       : _M_device(__u._M_device), _M_owns(__u._M_owns)
00458       {
00459         __u._M_device = 0;
00460         __u._M_owns = false;
00461       }
00462 
00463       unique_lock& operator=(unique_lock&& __u) noexcept
00464       {
00465         if(_M_owns)
00466           unlock();
00467 
00468         unique_lock(std::move(__u)).swap(*this);
00469 
00470         __u._M_device = 0;
00471         __u._M_owns = false;
00472 
00473         return *this;
00474       }
00475 
00476       void
00477       lock()
00478       {
00479         if (!_M_device)
00480           __throw_system_error(int(errc::operation_not_permitted));
00481         else if (_M_owns)
00482           __throw_system_error(int(errc::resource_deadlock_would_occur));
00483         else
00484           {
00485             _M_device->lock();
00486             _M_owns = true;
00487           }
00488       }
00489 
00490       bool
00491       try_lock()
00492       {
00493         if (!_M_device)
00494           __throw_system_error(int(errc::operation_not_permitted));
00495         else if (_M_owns)
00496           __throw_system_error(int(errc::resource_deadlock_would_occur));
00497         else
00498           {
00499             _M_owns = _M_device->try_lock();
00500             return _M_owns;
00501           }
00502       }
00503 
00504       template<typename _Clock, typename _Duration>
00505         bool
00506         try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
00507         {
00508           if (!_M_device)
00509             __throw_system_error(int(errc::operation_not_permitted));
00510           else if (_M_owns)
00511             __throw_system_error(int(errc::resource_deadlock_would_occur));
00512           else
00513             {
00514               _M_owns = _M_device->try_lock_until(__atime);
00515               return _M_owns;
00516             }
00517         }
00518 
00519       template<typename _Rep, typename _Period>
00520         bool
00521         try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
00522         {
00523           if (!_M_device)
00524             __throw_system_error(int(errc::operation_not_permitted));
00525           else if (_M_owns)
00526             __throw_system_error(int(errc::resource_deadlock_would_occur));
00527           else
00528             {
00529               _M_owns = _M_device->try_lock_for(__rtime);
00530               return _M_owns;
00531             }
00532          }
00533 
00534       void
00535       unlock()
00536       {
00537         if (!_M_owns)
00538           __throw_system_error(int(errc::operation_not_permitted));
00539         else if (_M_device)
00540           {
00541             _M_device->unlock();
00542             _M_owns = false;
00543           }
00544       }
00545 
00546       void
00547       swap(unique_lock& __u) noexcept
00548       {
00549         std::swap(_M_device, __u._M_device);
00550         std::swap(_M_owns, __u._M_owns);
00551       }
00552 
00553       mutex_type*
00554       release() noexcept
00555       {
00556         mutex_type* __ret = _M_device;
00557         _M_device = 0;
00558         _M_owns = false;
00559         return __ret;
00560       }
00561 
00562       bool
00563       owns_lock() const noexcept
00564       { return _M_owns; }
00565 
00566       explicit operator bool() const noexcept
00567       { return owns_lock(); }
00568 
00569       mutex_type*
00570       mutex() const noexcept
00571       { return _M_device; }
00572 
00573     private:
00574       mutex_type*       _M_device;
00575       bool              _M_owns; // XXX use atomic_bool
00576     };
00577 
00578   /// Swap overload for unique_lock objects.
00579   template<typename _Mutex>
00580     inline void
00581     swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) noexcept
00582     { __x.swap(__y); }
00583 
00584   template<typename _Lock>
00585     inline unique_lock<_Lock>
00586     __try_to_lock(_Lock& __l)
00587     { return unique_lock<_Lock>{__l, try_to_lock}; }
00588 
00589   template<int _Idx, bool _Continue = true>
00590     struct __try_lock_impl
00591     {
00592       template<typename... _Lock>
00593         static void
00594         __do_try_lock(tuple<_Lock&...>& __locks, int& __idx)
00595         {
00596           __idx = _Idx;
00597           auto __lock = std::__try_to_lock(std::get<_Idx>(__locks));
00598           if (__lock.owns_lock())
00599             {
00600               constexpr bool __cont = _Idx + 2 < sizeof...(_Lock);
00601               using __try_locker = __try_lock_impl<_Idx + 1, __cont>;
00602               __try_locker::__do_try_lock(__locks, __idx);
00603               if (__idx == -1)
00604                 __lock.release();
00605             }
00606         }
00607     };
00608 
00609   template<int _Idx>
00610     struct __try_lock_impl<_Idx, false>
00611     {
00612       template<typename... _Lock>
00613         static void
00614         __do_try_lock(tuple<_Lock&...>& __locks, int& __idx)
00615         {
00616           __idx = _Idx;
00617           auto __lock = std::__try_to_lock(std::get<_Idx>(__locks));
00618           if (__lock.owns_lock())
00619             {
00620               __idx = -1;
00621               __lock.release();
00622             }
00623         }
00624     };
00625 
00626   /** @brief Generic try_lock.
00627    *  @param __l1 Meets Mutex requirements (try_lock() may throw).
00628    *  @param __l2 Meets Mutex requirements (try_lock() may throw).
00629    *  @param __l3 Meets Mutex requirements (try_lock() may throw).
00630    *  @return Returns -1 if all try_lock() calls return true. Otherwise returns
00631    *          a 0-based index corresponding to the argument that returned false.
00632    *  @post Either all arguments are locked, or none will be.
00633    *
00634    *  Sequentially calls try_lock() on each argument.
00635    */
00636   template<typename _Lock1, typename _Lock2, typename... _Lock3>
00637     int
00638     try_lock(_Lock1& __l1, _Lock2& __l2, _Lock3&... __l3)
00639     {
00640       int __idx;
00641       auto __locks = std::tie(__l1, __l2, __l3...);
00642       __try_lock_impl<0>::__do_try_lock(__locks, __idx);
00643       return __idx;
00644     }
00645 
00646   /** @brief Generic lock.
00647    *  @param __l1 Meets Mutex requirements (try_lock() may throw).
00648    *  @param __l2 Meets Mutex requirements (try_lock() may throw).
00649    *  @param __l3 Meets Mutex requirements (try_lock() may throw).
00650    *  @throw An exception thrown by an argument's lock() or try_lock() member.
00651    *  @post All arguments are locked.
00652    *
00653    *  All arguments are locked via a sequence of calls to lock(), try_lock()
00654    *  and unlock().  If the call exits via an exception any locks that were
00655    *  obtained will be released.
00656    */
00657   template<typename _L1, typename _L2, typename... _L3>
00658     void
00659     lock(_L1& __l1, _L2& __l2, _L3&... __l3)
00660     {
00661       while (true)
00662         {
00663           using __try_locker = __try_lock_impl<0, sizeof...(_L3) != 0>;
00664           unique_lock<_L1> __first(__l1);
00665           int __idx;
00666           auto __locks = std::tie(__l2, __l3...);
00667           __try_locker::__do_try_lock(__locks, __idx);
00668           if (__idx == -1)
00669             {
00670               __first.release();
00671               return;
00672             }
00673         }
00674     }
00675 
00676 #ifdef _GLIBCXX_HAS_GTHREADS
00677   /// once_flag
00678   struct once_flag
00679   {
00680   private:
00681     typedef __gthread_once_t __native_type;
00682     __native_type  _M_once = __GTHREAD_ONCE_INIT;
00683 
00684   public:
00685     /// Constructor
00686     constexpr once_flag() noexcept = default;
00687 
00688     /// Deleted copy constructor
00689     once_flag(const once_flag&) = delete;
00690     /// Deleted assignment operator
00691     once_flag& operator=(const once_flag&) = delete;
00692 
00693     template<typename _Callable, typename... _Args>
00694       friend void
00695       call_once(once_flag& __once, _Callable&& __f, _Args&&... __args);
00696   };
00697 
00698 #ifdef _GLIBCXX_HAVE_TLS
00699   extern __thread void* __once_callable;
00700   extern __thread void (*__once_call)();
00701 
00702   template<typename _Callable>
00703     inline void
00704     __once_call_impl()
00705     {
00706       (*(_Callable*)__once_callable)();
00707     }
00708 #else
00709   extern function<void()> __once_functor;
00710 
00711   extern void
00712   __set_once_functor_lock_ptr(unique_lock<mutex>*);
00713 
00714   extern mutex&
00715   __get_once_mutex();
00716 #endif
00717 
00718   extern "C" void __once_proxy(void);
00719 
00720   /// call_once
00721   template<typename _Callable, typename... _Args>
00722     void
00723     call_once(once_flag& __once, _Callable&& __f, _Args&&... __args)
00724     {
00725 #ifdef _GLIBCXX_HAVE_TLS
00726       auto __bound_functor = std::__bind_simple(std::forward<_Callable>(__f),
00727           std::forward<_Args>(__args)...);
00728       __once_callable = std::__addressof(__bound_functor);
00729       __once_call = &__once_call_impl<decltype(__bound_functor)>;
00730 #else
00731       unique_lock<mutex> __functor_lock(__get_once_mutex());
00732       auto __callable = std::__bind_simple(std::forward<_Callable>(__f),
00733           std::forward<_Args>(__args)...);
00734       __once_functor = [&]() { __callable(); };
00735       __set_once_functor_lock_ptr(&__functor_lock);
00736 #endif
00737 
00738       int __e = __gthread_once(&__once._M_once, &__once_proxy);
00739 
00740 #ifndef _GLIBCXX_HAVE_TLS
00741       if (__functor_lock)
00742         __set_once_functor_lock_ptr(0);
00743 #endif
00744 
00745       if (__e)
00746         __throw_system_error(__e);
00747     }
00748 #endif // _GLIBCXX_HAS_GTHREADS
00749 
00750   // @} group mutexes
00751 _GLIBCXX_END_NAMESPACE_VERSION
00752 } // namespace
00753 #endif // _GLIBCXX_USE_C99_STDINT_TR1
00754 
00755 #endif // C++11
00756 
00757 #endif // _GLIBCXX_MUTEX