Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. // <mutex> -*- C++ -*-
  2.  
  3. // Copyright (C) 2003-2015 Free Software Foundation, Inc.
  4. //
  5. // This file is part of the GNU ISO C++ Library.  This library is free
  6. // software; you can redistribute it and/or modify it under the
  7. // terms of the GNU General Public License as published by the
  8. // Free Software Foundation; either version 3, or (at your option)
  9. // any later version.
  10.  
  11. // This library is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. // GNU General Public License for more details.
  15.  
  16. // Under Section 7 of GPL version 3, you are granted additional
  17. // permissions described in the GCC Runtime Library Exception, version
  18. // 3.1, as published by the Free Software Foundation.
  19.  
  20. // You should have received a copy of the GNU General Public License and
  21. // a copy of the GCC Runtime Library Exception along with this program;
  22. // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
  23. // <http://www.gnu.org/licenses/>.
  24.  
  25. /** @file include/mutex
  26.  *  This is a Standard C++ Library header.
  27.  */
  28.  
  29. #ifndef _GLIBCXX_MUTEX
  30. #define _GLIBCXX_MUTEX 1
  31.  
  32. #pragma GCC system_header
  33.  
  34. #if __cplusplus < 201103L
  35. # include <bits/c++0x_warning.h>
  36. #else
  37.  
  38. #include <tuple>
  39. #include <chrono>
  40. #include <exception>
  41. #include <type_traits>
  42. #include <functional>
  43. #include <system_error>
  44. #include <bits/functexcept.h>
  45. #include <bits/gthr.h>
  46. #include <bits/move.h> // for std::swap
  47. #include <bits/cxxabi_forced.h>
  48.  
  49. #ifdef _GLIBCXX_USE_C99_STDINT_TR1
  50.  
  51. namespace std _GLIBCXX_VISIBILITY(default)
  52. {
  53. _GLIBCXX_BEGIN_NAMESPACE_VERSION
  54.  
  55. #ifdef _GLIBCXX_HAS_GTHREADS
  56.   // Common base class for std::mutex and std::timed_mutex
  57.   class __mutex_base
  58.   {
  59.   protected:
  60.     typedef __gthread_mutex_t                   __native_type;
  61.  
  62. #ifdef __GTHREAD_MUTEX_INIT
  63.     __native_type  _M_mutex = __GTHREAD_MUTEX_INIT;
  64.  
  65.     constexpr __mutex_base() noexcept = default;
  66. #else
  67.     __native_type  _M_mutex;
  68.  
  69.     __mutex_base() noexcept
  70.     {
  71.       // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
  72.       __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex);
  73.     }
  74.  
  75.     ~__mutex_base() noexcept { __gthread_mutex_destroy(&_M_mutex); }
  76. #endif
  77.  
  78.     __mutex_base(const __mutex_base&) = delete;
  79.     __mutex_base& operator=(const __mutex_base&) = delete;
  80.   };
  81.  
  82.   // Common base class for std::recursive_mutex and std::recursive_timed_mutex
  83.   class __recursive_mutex_base
  84.   {
  85.   protected:
  86.     typedef __gthread_recursive_mutex_t         __native_type;
  87.  
  88.     __recursive_mutex_base(const __recursive_mutex_base&) = delete;
  89.     __recursive_mutex_base& operator=(const __recursive_mutex_base&) = delete;
  90.  
  91. #ifdef __GTHREAD_RECURSIVE_MUTEX_INIT
  92.     __native_type  _M_mutex = __GTHREAD_RECURSIVE_MUTEX_INIT;
  93.  
  94.     __recursive_mutex_base() = default;
  95. #else
  96.     __native_type  _M_mutex;
  97.  
  98.     __recursive_mutex_base()
  99.     {
  100.       // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
  101.       __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
  102.     }
  103.  
  104.     ~__recursive_mutex_base()
  105.     { __gthread_recursive_mutex_destroy(&_M_mutex); }
  106. #endif
  107.   };
  108.  
  109.   /**
  110.    * @defgroup mutexes Mutexes
  111.    * @ingroup concurrency
  112.    *
  113.    * Classes for mutex support.
  114.    * @{
  115.    */
  116.  
  117.   /// The standard mutex type.
  118.   class mutex : private __mutex_base
  119.   {
  120.   public:
  121.     typedef __native_type*                      native_handle_type;
  122.  
  123. #ifdef __GTHREAD_MUTEX_INIT
  124.     constexpr
  125. #endif
  126.     mutex() noexcept = default;
  127.     ~mutex() = default;
  128.  
  129.     mutex(const mutex&) = delete;
  130.     mutex& operator=(const mutex&) = delete;
  131.  
  132.     void
  133.     lock()
  134.     {
  135.       int __e = __gthread_mutex_lock(&_M_mutex);
  136.  
  137.       // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
  138.       if (__e)
  139.         __throw_system_error(__e);
  140.     }
  141.  
  142.     bool
  143.     try_lock() noexcept
  144.     {
  145.       // XXX EINVAL, EAGAIN, EBUSY
  146.       return !__gthread_mutex_trylock(&_M_mutex);
  147.     }
  148.  
  149.     void
  150.     unlock()
  151.     {
  152.       // XXX EINVAL, EAGAIN, EPERM
  153.       __gthread_mutex_unlock(&_M_mutex);
  154.     }
  155.  
  156.     native_handle_type
  157.     native_handle()
  158.     { return &_M_mutex; }
  159.   };
  160.  
  161.   /// The standard recursive mutex type.
  162.   class recursive_mutex : private __recursive_mutex_base
  163.   {
  164.   public:
  165.     typedef __native_type*                      native_handle_type;
  166.  
  167.     recursive_mutex() = default;
  168.     ~recursive_mutex() = default;
  169.  
  170.     recursive_mutex(const recursive_mutex&) = delete;
  171.     recursive_mutex& operator=(const recursive_mutex&) = delete;
  172.  
  173.     void
  174.     lock()
  175.     {
  176.       int __e = __gthread_recursive_mutex_lock(&_M_mutex);
  177.  
  178.       // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
  179.       if (__e)
  180.         __throw_system_error(__e);
  181.     }
  182.  
  183.     bool
  184.     try_lock() noexcept
  185.     {
  186.       // XXX EINVAL, EAGAIN, EBUSY
  187.       return !__gthread_recursive_mutex_trylock(&_M_mutex);
  188.     }
  189.  
  190.     void
  191.     unlock()
  192.     {
  193.       // XXX EINVAL, EAGAIN, EBUSY
  194.       __gthread_recursive_mutex_unlock(&_M_mutex);
  195.     }
  196.  
  197.     native_handle_type
  198.     native_handle()
  199.     { return &_M_mutex; }
  200.   };
  201.  
  202. #if _GTHREAD_USE_MUTEX_TIMEDLOCK
  203.   template<typename _Derived>
  204.     class __timed_mutex_impl
  205.     {
  206.     protected:
  207.       typedef chrono::high_resolution_clock     __clock_t;
  208.  
  209.       template<typename _Rep, typename _Period>
  210.         bool
  211.         _M_try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
  212.         {
  213.           using chrono::steady_clock;
  214.           auto __rt = chrono::duration_cast<steady_clock::duration>(__rtime);
  215.           if (ratio_greater<steady_clock::period, _Period>())
  216.             ++__rt;
  217.           return _M_try_lock_until(steady_clock::now() + __rt);
  218.         }
  219.  
  220.       template<typename _Duration>
  221.         bool
  222.         _M_try_lock_until(const chrono::time_point<__clock_t,
  223.                                                    _Duration>& __atime)
  224.         {
  225.           auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
  226.           auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
  227.  
  228.           __gthread_time_t __ts = {
  229.             static_cast<std::time_t>(__s.time_since_epoch().count()),
  230.             static_cast<long>(__ns.count())
  231.           };
  232.  
  233.           auto __mutex = static_cast<_Derived*>(this)->native_handle();
  234.           return !__gthread_mutex_timedlock(__mutex, &__ts);
  235.         }
  236.  
  237.       template<typename _Clock, typename _Duration>
  238.         bool
  239.         _M_try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
  240.         {
  241.           auto __rtime = __atime - _Clock::now();
  242.           return _M_try_lock_until(__clock_t::now() + __rtime);
  243.         }
  244.     };
  245.  
  246.   /// The standard timed mutex type.
  247.   class timed_mutex
  248.   : private __mutex_base, public __timed_mutex_impl<timed_mutex>
  249.   {
  250.   public:
  251.     typedef __native_type*                      native_handle_type;
  252.  
  253.     timed_mutex() = default;
  254.     ~timed_mutex() = default;
  255.  
  256.     timed_mutex(const timed_mutex&) = delete;
  257.     timed_mutex& operator=(const timed_mutex&) = delete;
  258.  
  259.     void
  260.     lock()
  261.     {
  262.       int __e = __gthread_mutex_lock(&_M_mutex);
  263.  
  264.       // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
  265.       if (__e)
  266.         __throw_system_error(__e);
  267.     }
  268.  
  269.     bool
  270.     try_lock() noexcept
  271.     {
  272.       // XXX EINVAL, EAGAIN, EBUSY
  273.       return !__gthread_mutex_trylock(&_M_mutex);
  274.     }
  275.  
  276.     template <class _Rep, class _Period>
  277.       bool
  278.       try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
  279.       { return _M_try_lock_for(__rtime); }
  280.  
  281.     template <class _Clock, class _Duration>
  282.       bool
  283.       try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
  284.       { return _M_try_lock_until(__atime); }
  285.  
  286.     void
  287.     unlock()
  288.     {
  289.       // XXX EINVAL, EAGAIN, EBUSY
  290.       __gthread_mutex_unlock(&_M_mutex);
  291.     }
  292.  
  293.     native_handle_type
  294.     native_handle()
  295.     { return &_M_mutex; }
  296.   };
  297.  
  298.   /// The standard recursive timed mutex type.
  299.   class recursive_timed_mutex
  300.   : private __recursive_mutex_base,
  301.     public __timed_mutex_impl<recursive_timed_mutex>
  302.   {
  303.   public:
  304.     typedef __native_type*                      native_handle_type;
  305.  
  306.     recursive_timed_mutex() = default;
  307.     ~recursive_timed_mutex() = default;
  308.  
  309.     recursive_timed_mutex(const recursive_timed_mutex&) = delete;
  310.     recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
  311.  
  312.     void
  313.     lock()
  314.     {
  315.       int __e = __gthread_recursive_mutex_lock(&_M_mutex);
  316.  
  317.       // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
  318.       if (__e)
  319.         __throw_system_error(__e);
  320.     }
  321.  
  322.     bool
  323.     try_lock() noexcept
  324.     {
  325.       // XXX EINVAL, EAGAIN, EBUSY
  326.       return !__gthread_recursive_mutex_trylock(&_M_mutex);
  327.     }
  328.  
  329.     template <class _Rep, class _Period>
  330.       bool
  331.       try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
  332.       { return _M_try_lock_for(__rtime); }
  333.  
  334.     template <class _Clock, class _Duration>
  335.       bool
  336.       try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
  337.       { return _M_try_lock_until(__atime); }
  338.  
  339.     void
  340.     unlock()
  341.     {
  342.       // XXX EINVAL, EAGAIN, EBUSY
  343.       __gthread_recursive_mutex_unlock(&_M_mutex);
  344.     }
  345.  
  346.     native_handle_type
  347.     native_handle()
  348.     { return &_M_mutex; }
  349.   };
  350. #endif
  351. #endif // _GLIBCXX_HAS_GTHREADS
  352.  
  353.   /// Do not acquire ownership of the mutex.
  354.   struct defer_lock_t { };
  355.  
  356.   /// Try to acquire ownership of the mutex without blocking.
  357.   struct try_to_lock_t { };
  358.  
  359.   /// Assume the calling thread has already obtained mutex ownership
  360.   /// and manage it.
  361.   struct adopt_lock_t { };
  362.  
  363.   /// Tag used to prevent a scoped lock from acquiring ownership of a mutex.
  364.   constexpr defer_lock_t        defer_lock { };
  365.  
  366.   /// Tag used to prevent a scoped lock from blocking if a mutex is locked.
  367.   constexpr try_to_lock_t       try_to_lock { };
  368.  
  369.   /// Tag used to make a scoped lock take ownership of a locked mutex.
  370.   constexpr adopt_lock_t        adopt_lock { };
  371.  
  372.   /** @brief A movable scoped lock type.
  373.    *
  374.    * A unique_lock controls mutex ownership within a scope. Ownership of the
  375.    * mutex can be delayed until after construction and can be transferred
  376.    * to another unique_lock by move construction or move assignment. If a
  377.    * mutex lock is owned when the destructor runs ownership will be released.
  378.    */
  379.   template<typename _Mutex>
  380.     class lock_guard
  381.     {
  382.     public:
  383.       typedef _Mutex mutex_type;
  384.  
  385.       explicit lock_guard(mutex_type& __m) : _M_device(__m)
  386.       { _M_device.lock(); }
  387.  
  388.       lock_guard(mutex_type& __m, adopt_lock_t) : _M_device(__m)
  389.       { } // calling thread owns mutex
  390.  
  391.       ~lock_guard()
  392.       { _M_device.unlock(); }
  393.  
  394.       lock_guard(const lock_guard&) = delete;
  395.       lock_guard& operator=(const lock_guard&) = delete;
  396.  
  397.     private:
  398.       mutex_type&  _M_device;
  399.     };
  400.  
  401.   /// unique_lock
  402.   template<typename _Mutex>
  403.     class unique_lock
  404.     {
  405.     public:
  406.       typedef _Mutex mutex_type;
  407.  
  408.       unique_lock() noexcept
  409.       : _M_device(0), _M_owns(false)
  410.       { }
  411.  
  412.       explicit unique_lock(mutex_type& __m)
  413.       : _M_device(std::__addressof(__m)), _M_owns(false)
  414.       {
  415.         lock();
  416.         _M_owns = true;
  417.       }
  418.  
  419.       unique_lock(mutex_type& __m, defer_lock_t) noexcept
  420.       : _M_device(std::__addressof(__m)), _M_owns(false)
  421.       { }
  422.  
  423.       unique_lock(mutex_type& __m, try_to_lock_t)
  424.       : _M_device(std::__addressof(__m)), _M_owns(_M_device->try_lock())
  425.       { }
  426.  
  427.       unique_lock(mutex_type& __m, adopt_lock_t)
  428.       : _M_device(std::__addressof(__m)), _M_owns(true)
  429.       {
  430.         // XXX calling thread owns mutex
  431.       }
  432.  
  433.       template<typename _Clock, typename _Duration>
  434.         unique_lock(mutex_type& __m,
  435.                     const chrono::time_point<_Clock, _Duration>& __atime)
  436.         : _M_device(std::__addressof(__m)),
  437.           _M_owns(_M_device->try_lock_until(__atime))
  438.         { }
  439.  
  440.       template<typename _Rep, typename _Period>
  441.         unique_lock(mutex_type& __m,
  442.                     const chrono::duration<_Rep, _Period>& __rtime)
  443.         : _M_device(std::__addressof(__m)),
  444.           _M_owns(_M_device->try_lock_for(__rtime))
  445.         { }
  446.  
  447.       ~unique_lock()
  448.       {
  449.         if (_M_owns)
  450.           unlock();
  451.       }
  452.  
  453.       unique_lock(const unique_lock&) = delete;
  454.       unique_lock& operator=(const unique_lock&) = delete;
  455.  
  456.       unique_lock(unique_lock&& __u) noexcept
  457.       : _M_device(__u._M_device), _M_owns(__u._M_owns)
  458.       {
  459.         __u._M_device = 0;
  460.         __u._M_owns = false;
  461.       }
  462.  
  463.       unique_lock& operator=(unique_lock&& __u) noexcept
  464.       {
  465.         if(_M_owns)
  466.           unlock();
  467.  
  468.         unique_lock(std::move(__u)).swap(*this);
  469.  
  470.         __u._M_device = 0;
  471.         __u._M_owns = false;
  472.  
  473.         return *this;
  474.       }
  475.  
  476.       void
  477.       lock()
  478.       {
  479.         if (!_M_device)
  480.           __throw_system_error(int(errc::operation_not_permitted));
  481.         else if (_M_owns)
  482.           __throw_system_error(int(errc::resource_deadlock_would_occur));
  483.         else
  484.           {
  485.             _M_device->lock();
  486.             _M_owns = true;
  487.           }
  488.       }
  489.  
  490.       bool
  491.       try_lock()
  492.       {
  493.         if (!_M_device)
  494.           __throw_system_error(int(errc::operation_not_permitted));
  495.         else if (_M_owns)
  496.           __throw_system_error(int(errc::resource_deadlock_would_occur));
  497.         else
  498.           {
  499.             _M_owns = _M_device->try_lock();
  500.             return _M_owns;
  501.           }
  502.       }
  503.  
  504.       template<typename _Clock, typename _Duration>
  505.         bool
  506.         try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
  507.         {
  508.           if (!_M_device)
  509.             __throw_system_error(int(errc::operation_not_permitted));
  510.           else if (_M_owns)
  511.             __throw_system_error(int(errc::resource_deadlock_would_occur));
  512.           else
  513.             {
  514.               _M_owns = _M_device->try_lock_until(__atime);
  515.               return _M_owns;
  516.             }
  517.         }
  518.  
  519.       template<typename _Rep, typename _Period>
  520.         bool
  521.         try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
  522.         {
  523.           if (!_M_device)
  524.             __throw_system_error(int(errc::operation_not_permitted));
  525.           else if (_M_owns)
  526.             __throw_system_error(int(errc::resource_deadlock_would_occur));
  527.           else
  528.             {
  529.               _M_owns = _M_device->try_lock_for(__rtime);
  530.               return _M_owns;
  531.             }
  532.          }
  533.  
  534.       void
  535.       unlock()
  536.       {
  537.         if (!_M_owns)
  538.           __throw_system_error(int(errc::operation_not_permitted));
  539.         else if (_M_device)
  540.           {
  541.             _M_device->unlock();
  542.             _M_owns = false;
  543.           }
  544.       }
  545.  
  546.       void
  547.       swap(unique_lock& __u) noexcept
  548.       {
  549.         std::swap(_M_device, __u._M_device);
  550.         std::swap(_M_owns, __u._M_owns);
  551.       }
  552.  
  553.       mutex_type*
  554.       release() noexcept
  555.       {
  556.         mutex_type* __ret = _M_device;
  557.         _M_device = 0;
  558.         _M_owns = false;
  559.         return __ret;
  560.       }
  561.  
  562.       bool
  563.       owns_lock() const noexcept
  564.       { return _M_owns; }
  565.  
  566.       explicit operator bool() const noexcept
  567.       { return owns_lock(); }
  568.  
  569.       mutex_type*
  570.       mutex() const noexcept
  571.       { return _M_device; }
  572.  
  573.     private:
  574.       mutex_type*       _M_device;
  575.       bool              _M_owns; // XXX use atomic_bool
  576.     };
  577.  
  578.   /// Swap overload for unique_lock objects.
  579.   template<typename _Mutex>
  580.     inline void
  581.     swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) noexcept
  582.     { __x.swap(__y); }
  583.  
  584.   template<typename _Lock>
  585.     inline unique_lock<_Lock>
  586.     __try_to_lock(_Lock& __l)
  587.     { return unique_lock<_Lock>{__l, try_to_lock}; }
  588.  
  589.   template<int _Idx, bool _Continue = true>
  590.     struct __try_lock_impl
  591.     {
  592.       template<typename... _Lock>
  593.         static void
  594.         __do_try_lock(tuple<_Lock&...>& __locks, int& __idx)
  595.         {
  596.           __idx = _Idx;
  597.           auto __lock = std::__try_to_lock(std::get<_Idx>(__locks));
  598.           if (__lock.owns_lock())
  599.             {
  600.               constexpr bool __cont = _Idx + 2 < sizeof...(_Lock);
  601.               using __try_locker = __try_lock_impl<_Idx + 1, __cont>;
  602.               __try_locker::__do_try_lock(__locks, __idx);
  603.               if (__idx == -1)
  604.                 __lock.release();
  605.             }
  606.         }
  607.     };
  608.  
  609.   template<int _Idx>
  610.     struct __try_lock_impl<_Idx, false>
  611.     {
  612.       template<typename... _Lock>
  613.         static void
  614.         __do_try_lock(tuple<_Lock&...>& __locks, int& __idx)
  615.         {
  616.           __idx = _Idx;
  617.           auto __lock = std::__try_to_lock(std::get<_Idx>(__locks));
  618.           if (__lock.owns_lock())
  619.             {
  620.               __idx = -1;
  621.               __lock.release();
  622.             }
  623.         }
  624.     };
  625.  
  626.   /** @brief Generic try_lock.
  627.    *  @param __l1 Meets Mutex requirements (try_lock() may throw).
  628.    *  @param __l2 Meets Mutex requirements (try_lock() may throw).
  629.    *  @param __l3 Meets Mutex requirements (try_lock() may throw).
  630.    *  @return Returns -1 if all try_lock() calls return true. Otherwise returns
  631.    *          a 0-based index corresponding to the argument that returned false.
  632.    *  @post Either all arguments are locked, or none will be.
  633.    *
  634.    *  Sequentially calls try_lock() on each argument.
  635.    */
  636.   template<typename _Lock1, typename _Lock2, typename... _Lock3>
  637.     int
  638.     try_lock(_Lock1& __l1, _Lock2& __l2, _Lock3&... __l3)
  639.     {
  640.       int __idx;
  641.       auto __locks = std::tie(__l1, __l2, __l3...);
  642.       __try_lock_impl<0>::__do_try_lock(__locks, __idx);
  643.       return __idx;
  644.     }
  645.  
  646.   /** @brief Generic lock.
  647.    *  @param __l1 Meets Mutex requirements (try_lock() may throw).
  648.    *  @param __l2 Meets Mutex requirements (try_lock() may throw).
  649.    *  @param __l3 Meets Mutex requirements (try_lock() may throw).
  650.    *  @throw An exception thrown by an argument's lock() or try_lock() member.
  651.    *  @post All arguments are locked.
  652.    *
  653.    *  All arguments are locked via a sequence of calls to lock(), try_lock()
  654.    *  and unlock().  If the call exits via an exception any locks that were
  655.    *  obtained will be released.
  656.    */
  657.   template<typename _L1, typename _L2, typename... _L3>
  658.     void
  659.     lock(_L1& __l1, _L2& __l2, _L3&... __l3)
  660.     {
  661.       while (true)
  662.         {
  663.           using __try_locker = __try_lock_impl<0, sizeof...(_L3) != 0>;
  664.           unique_lock<_L1> __first(__l1);
  665.           int __idx;
  666.           auto __locks = std::tie(__l2, __l3...);
  667.           __try_locker::__do_try_lock(__locks, __idx);
  668.           if (__idx == -1)
  669.             {
  670.               __first.release();
  671.               return;
  672.             }
  673.         }
  674.     }
  675.  
  676. #ifdef _GLIBCXX_HAS_GTHREADS
  677.   /// once_flag
  678.   struct once_flag
  679.   {
  680.   private:
  681.     typedef __gthread_once_t __native_type;
  682.     __native_type  _M_once = __GTHREAD_ONCE_INIT;
  683.  
  684.   public:
  685.     /// Constructor
  686.     constexpr once_flag() noexcept = default;
  687.  
  688.     /// Deleted copy constructor
  689.     once_flag(const once_flag&) = delete;
  690.     /// Deleted assignment operator
  691.     once_flag& operator=(const once_flag&) = delete;
  692.  
  693.     template<typename _Callable, typename... _Args>
  694.       friend void
  695.       call_once(once_flag& __once, _Callable&& __f, _Args&&... __args);
  696.   };
  697.  
  698. #ifdef _GLIBCXX_HAVE_TLS
  699.   extern __thread void* __once_callable;
  700.   extern __thread void (*__once_call)();
  701.  
  702.   template<typename _Callable>
  703.     inline void
  704.     __once_call_impl()
  705.     {
  706.       (*(_Callable*)__once_callable)();
  707.     }
  708. #else
  709.   extern function<void()> __once_functor;
  710.  
  711.   extern void
  712.   __set_once_functor_lock_ptr(unique_lock<mutex>*);
  713.  
  714.   extern mutex&
  715.   __get_once_mutex();
  716. #endif
  717.  
  718.   extern "C" void __once_proxy(void);
  719.  
  720.   /// call_once
  721.   template<typename _Callable, typename... _Args>
  722.     void
  723.     call_once(once_flag& __once, _Callable&& __f, _Args&&... __args)
  724.     {
  725. #ifdef _GLIBCXX_HAVE_TLS
  726.       auto __bound_functor = std::__bind_simple(std::forward<_Callable>(__f),
  727.           std::forward<_Args>(__args)...);
  728.       __once_callable = std::__addressof(__bound_functor);
  729.       __once_call = &__once_call_impl<decltype(__bound_functor)>;
  730. #else
  731.       unique_lock<mutex> __functor_lock(__get_once_mutex());
  732.       auto __callable = std::__bind_simple(std::forward<_Callable>(__f),
  733.           std::forward<_Args>(__args)...);
  734.       __once_functor = [&]() { __callable(); };
  735.       __set_once_functor_lock_ptr(&__functor_lock);
  736. #endif
  737.  
  738.       int __e = __gthread_once(&__once._M_once, &__once_proxy);
  739.  
  740. #ifndef _GLIBCXX_HAVE_TLS
  741.       if (__functor_lock)
  742.         __set_once_functor_lock_ptr(0);
  743. #endif
  744.  
  745.       if (__e)
  746.         __throw_system_error(__e);
  747.     }
  748. #endif // _GLIBCXX_HAS_GTHREADS
  749.  
  750.   // @} group mutexes
  751. _GLIBCXX_END_NAMESPACE_VERSION
  752. } // namespace
  753. #endif // _GLIBCXX_USE_C99_STDINT_TR1
  754.  
  755. #endif // C++11
  756.  
  757. #endif // _GLIBCXX_MUTEX
  758.