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