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   /// mutex
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   /// recursive_mutex
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   /// timed_mutex
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   /// recursive_timed_mutex
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   constexpr defer_lock_t        defer_lock { };
00364   constexpr try_to_lock_t       try_to_lock { };
00365   constexpr adopt_lock_t        adopt_lock { };
00366 
00367   /// @brief  Scoped lock idiom.
00368   // Acquire the mutex here with a constructor call, then release with
00369   // the destructor call in accordance with RAII style.
00370   template<typename _Mutex>
00371     class lock_guard
00372     {
00373     public:
00374       typedef _Mutex mutex_type;
00375 
00376       explicit lock_guard(mutex_type& __m) : _M_device(__m)
00377       { _M_device.lock(); }
00378 
00379       lock_guard(mutex_type& __m, adopt_lock_t) : _M_device(__m)
00380       { } // calling thread owns mutex
00381 
00382       ~lock_guard()
00383       { _M_device.unlock(); }
00384 
00385       lock_guard(const lock_guard&) = delete;
00386       lock_guard& operator=(const lock_guard&) = delete;
00387 
00388     private:
00389       mutex_type&  _M_device;
00390     };
00391 
00392   /// unique_lock
00393   template<typename _Mutex>
00394     class unique_lock
00395     {
00396     public:
00397       typedef _Mutex mutex_type;
00398 
00399       unique_lock() noexcept
00400       : _M_device(0), _M_owns(false)
00401       { }
00402 
00403       explicit unique_lock(mutex_type& __m)
00404       : _M_device(std::__addressof(__m)), _M_owns(false)
00405       {
00406         lock();
00407         _M_owns = true;
00408       }
00409 
00410       unique_lock(mutex_type& __m, defer_lock_t) noexcept
00411       : _M_device(std::__addressof(__m)), _M_owns(false)
00412       { }
00413 
00414       unique_lock(mutex_type& __m, try_to_lock_t)
00415       : _M_device(std::__addressof(__m)), _M_owns(_M_device->try_lock())
00416       { }
00417 
00418       unique_lock(mutex_type& __m, adopt_lock_t)
00419       : _M_device(std::__addressof(__m)), _M_owns(true)
00420       {
00421         // XXX calling thread owns mutex
00422       }
00423 
00424       template<typename _Clock, typename _Duration>
00425         unique_lock(mutex_type& __m,
00426                     const chrono::time_point<_Clock, _Duration>& __atime)
00427         : _M_device(std::__addressof(__m)),
00428           _M_owns(_M_device->try_lock_until(__atime))
00429         { }
00430 
00431       template<typename _Rep, typename _Period>
00432         unique_lock(mutex_type& __m,
00433                     const chrono::duration<_Rep, _Period>& __rtime)
00434         : _M_device(std::__addressof(__m)),
00435           _M_owns(_M_device->try_lock_for(__rtime))
00436         { }
00437 
00438       ~unique_lock()
00439       {
00440         if (_M_owns)
00441           unlock();
00442       }
00443 
00444       unique_lock(const unique_lock&) = delete;
00445       unique_lock& operator=(const unique_lock&) = delete;
00446 
00447       unique_lock(unique_lock&& __u) noexcept
00448       : _M_device(__u._M_device), _M_owns(__u._M_owns)
00449       {
00450         __u._M_device = 0;
00451         __u._M_owns = false;
00452       }
00453 
00454       unique_lock& operator=(unique_lock&& __u) noexcept
00455       {
00456         if(_M_owns)
00457           unlock();
00458 
00459         unique_lock(std::move(__u)).swap(*this);
00460 
00461         __u._M_device = 0;
00462         __u._M_owns = false;
00463 
00464         return *this;
00465       }
00466 
00467       void
00468       lock()
00469       {
00470         if (!_M_device)
00471           __throw_system_error(int(errc::operation_not_permitted));
00472         else if (_M_owns)
00473           __throw_system_error(int(errc::resource_deadlock_would_occur));
00474         else
00475           {
00476             _M_device->lock();
00477             _M_owns = true;
00478           }
00479       }
00480 
00481       bool
00482       try_lock()
00483       {
00484         if (!_M_device)
00485           __throw_system_error(int(errc::operation_not_permitted));
00486         else if (_M_owns)
00487           __throw_system_error(int(errc::resource_deadlock_would_occur));
00488         else
00489           {
00490             _M_owns = _M_device->try_lock();
00491             return _M_owns;
00492           }
00493       }
00494 
00495       template<typename _Clock, typename _Duration>
00496         bool
00497         try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
00498         {
00499           if (!_M_device)
00500             __throw_system_error(int(errc::operation_not_permitted));
00501           else if (_M_owns)
00502             __throw_system_error(int(errc::resource_deadlock_would_occur));
00503           else
00504             {
00505               _M_owns = _M_device->try_lock_until(__atime);
00506               return _M_owns;
00507             }
00508         }
00509 
00510       template<typename _Rep, typename _Period>
00511         bool
00512         try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
00513         {
00514           if (!_M_device)
00515             __throw_system_error(int(errc::operation_not_permitted));
00516           else if (_M_owns)
00517             __throw_system_error(int(errc::resource_deadlock_would_occur));
00518           else
00519             {
00520               _M_owns = _M_device->try_lock_for(__rtime);
00521               return _M_owns;
00522             }
00523          }
00524 
00525       void
00526       unlock()
00527       {
00528         if (!_M_owns)
00529           __throw_system_error(int(errc::operation_not_permitted));
00530         else if (_M_device)
00531           {
00532             _M_device->unlock();
00533             _M_owns = false;
00534           }
00535       }
00536 
00537       void
00538       swap(unique_lock& __u) noexcept
00539       {
00540         std::swap(_M_device, __u._M_device);
00541         std::swap(_M_owns, __u._M_owns);
00542       }
00543 
00544       mutex_type*
00545       release() noexcept
00546       {
00547         mutex_type* __ret = _M_device;
00548         _M_device = 0;
00549         _M_owns = false;
00550         return __ret;
00551       }
00552 
00553       bool
00554       owns_lock() const noexcept
00555       { return _M_owns; }
00556 
00557       explicit operator bool() const noexcept
00558       { return owns_lock(); }
00559 
00560       mutex_type*
00561       mutex() const noexcept
00562       { return _M_device; }
00563 
00564     private:
00565       mutex_type*       _M_device;
00566       bool              _M_owns; // XXX use atomic_bool
00567     };
00568 
00569   /// Swap overload for unique_lock objects.
00570   template<typename _Mutex>
00571     inline void
00572     swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) noexcept
00573     { __x.swap(__y); }
00574 
00575   template<typename _Lock>
00576     inline unique_lock<_Lock>
00577     __try_to_lock(_Lock& __l)
00578     { return unique_lock<_Lock>{__l, try_to_lock}; }
00579 
00580   template<int _Idx, bool _Continue = true>
00581     struct __try_lock_impl
00582     {
00583       template<typename... _Lock>
00584         static void
00585         __do_try_lock(tuple<_Lock&...>& __locks, int& __idx)
00586         {
00587           __idx = _Idx;
00588           auto __lock = std::__try_to_lock(std::get<_Idx>(__locks));
00589           if (__lock.owns_lock())
00590             {
00591               constexpr bool __cont = _Idx + 2 < sizeof...(_Lock);
00592               using __try_locker = __try_lock_impl<_Idx + 1, __cont>;
00593               __try_locker::__do_try_lock(__locks, __idx);
00594               if (__idx == -1)
00595                 __lock.release();
00596             }
00597         }
00598     };
00599 
00600   template<int _Idx>
00601     struct __try_lock_impl<_Idx, false>
00602     {
00603       template<typename... _Lock>
00604         static void
00605         __do_try_lock(tuple<_Lock&...>& __locks, int& __idx)
00606         {
00607           __idx = _Idx;
00608           auto __lock = std::__try_to_lock(std::get<_Idx>(__locks));
00609           if (__lock.owns_lock())
00610             {
00611               __idx = -1;
00612               __lock.release();
00613             }
00614         }
00615     };
00616 
00617   /** @brief Generic try_lock.
00618    *  @param __l1 Meets Mutex requirements (try_lock() may throw).
00619    *  @param __l2 Meets Mutex requirements (try_lock() may throw).
00620    *  @param __l3 Meets Mutex requirements (try_lock() may throw).
00621    *  @return Returns -1 if all try_lock() calls return true. Otherwise returns
00622    *          a 0-based index corresponding to the argument that returned false.
00623    *  @post Either all arguments are locked, or none will be.
00624    *
00625    *  Sequentially calls try_lock() on each argument.
00626    */
00627   template<typename _Lock1, typename _Lock2, typename... _Lock3>
00628     int
00629     try_lock(_Lock1& __l1, _Lock2& __l2, _Lock3&... __l3)
00630     {
00631       int __idx;
00632       auto __locks = std::tie(__l1, __l2, __l3...);
00633       __try_lock_impl<0>::__do_try_lock(__locks, __idx);
00634       return __idx;
00635     }
00636 
00637   /** @brief Generic lock.
00638    *  @param __l1 Meets Mutex requirements (try_lock() may throw).
00639    *  @param __l2 Meets Mutex requirements (try_lock() may throw).
00640    *  @param __l3 Meets Mutex requirements (try_lock() may throw).
00641    *  @throw An exception thrown by an argument's lock() or try_lock() member.
00642    *  @post All arguments are locked.
00643    *
00644    *  All arguments are locked via a sequence of calls to lock(), try_lock()
00645    *  and unlock().  If the call exits via an exception any locks that were
00646    *  obtained will be released.
00647    */
00648   template<typename _L1, typename _L2, typename... _L3>
00649     void
00650     lock(_L1& __l1, _L2& __l2, _L3&... __l3)
00651     {
00652       while (true)
00653         {
00654           using __try_locker = __try_lock_impl<0, sizeof...(_L3) != 0>;
00655           unique_lock<_L1> __first(__l1);
00656           int __idx;
00657           auto __locks = std::tie(__l2, __l3...);
00658           __try_locker::__do_try_lock(__locks, __idx);
00659           if (__idx == -1)
00660             {
00661               __first.release();
00662               return;
00663             }
00664         }
00665     }
00666 
00667 #ifdef _GLIBCXX_HAS_GTHREADS
00668   /// once_flag
00669   struct once_flag
00670   {
00671   private:
00672     typedef __gthread_once_t __native_type;
00673     __native_type  _M_once = __GTHREAD_ONCE_INIT;
00674 
00675   public:
00676     /// Constructor
00677     constexpr once_flag() noexcept = default;
00678 
00679     /// Deleted copy constructor
00680     once_flag(const once_flag&) = delete;
00681     /// Deleted assignment operator
00682     once_flag& operator=(const once_flag&) = delete;
00683 
00684     template<typename _Callable, typename... _Args>
00685       friend void
00686       call_once(once_flag& __once, _Callable&& __f, _Args&&... __args);
00687   };
00688 
00689 #ifdef _GLIBCXX_HAVE_TLS
00690   extern __thread void* __once_callable;
00691   extern __thread void (*__once_call)();
00692 
00693   template<typename _Callable>
00694     inline void
00695     __once_call_impl()
00696     {
00697       (*(_Callable*)__once_callable)();
00698     }
00699 #else
00700   extern function<void()> __once_functor;
00701 
00702   extern void
00703   __set_once_functor_lock_ptr(unique_lock<mutex>*);
00704 
00705   extern mutex&
00706   __get_once_mutex();
00707 #endif
00708 
00709   extern "C" void __once_proxy(void);
00710 
00711   /// call_once
00712   template<typename _Callable, typename... _Args>
00713     void
00714     call_once(once_flag& __once, _Callable&& __f, _Args&&... __args)
00715     {
00716 #ifdef _GLIBCXX_HAVE_TLS
00717       auto __bound_functor = std::__bind_simple(std::forward<_Callable>(__f),
00718           std::forward<_Args>(__args)...);
00719       __once_callable = std::__addressof(__bound_functor);
00720       __once_call = &__once_call_impl<decltype(__bound_functor)>;
00721 #else
00722       unique_lock<mutex> __functor_lock(__get_once_mutex());
00723       auto __callable = std::__bind_simple(std::forward<_Callable>(__f),
00724           std::forward<_Args>(__args)...);
00725       __once_functor = [&]() { __callable(); };
00726       __set_once_functor_lock_ptr(&__functor_lock);
00727 #endif
00728 
00729       int __e = __gthread_once(&__once._M_once, &__once_proxy);
00730 
00731 #ifndef _GLIBCXX_HAVE_TLS
00732       if (__functor_lock)
00733         __set_once_functor_lock_ptr(0);
00734 #endif
00735 
00736       if (__e)
00737         __throw_system_error(__e);
00738     }
00739 #endif // _GLIBCXX_HAS_GTHREADS
00740 
00741   // @} group mutexes
00742 _GLIBCXX_END_NAMESPACE_VERSION
00743 } // namespace
00744 #endif // _GLIBCXX_USE_C99_STDINT_TR1
00745 
00746 #endif // C++11
00747 
00748 #endif // _GLIBCXX_MUTEX