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