libstdc++
mutex
Go to the documentation of this file.
1 // <mutex> -*- C++ -*-
2 
3 // Copyright (C) 2003-2021 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 <system_error>
43 #include <bits/std_mutex.h>
44 #include <bits/unique_lock.h>
45 #if ! _GTHREAD_USE_MUTEX_TIMEDLOCK
46 # include <condition_variable>
47 # include <thread>
48 #endif
49 #include <ext/atomicity.h> // __gnu_cxx::__is_single_threaded
50 
51 #if defined _GLIBCXX_HAS_GTHREADS && ! defined _GLIBCXX_HAVE_TLS
52 # include <bits/std_function.h> // std::function
53 #endif
54 
55 namespace std _GLIBCXX_VISIBILITY(default)
56 {
57 _GLIBCXX_BEGIN_NAMESPACE_VERSION
58 
59  /**
60  * @addtogroup mutexes
61  * @{
62  */
63 
64 #ifdef _GLIBCXX_HAS_GTHREADS
65 
66  // Common base class for std::recursive_mutex and std::recursive_timed_mutex
67  class __recursive_mutex_base
68  {
69  protected:
70  typedef __gthread_recursive_mutex_t __native_type;
71 
72  __recursive_mutex_base(const __recursive_mutex_base&) = delete;
73  __recursive_mutex_base& operator=(const __recursive_mutex_base&) = delete;
74 
75 #ifdef __GTHREAD_RECURSIVE_MUTEX_INIT
76  __native_type _M_mutex = __GTHREAD_RECURSIVE_MUTEX_INIT;
77 
78  __recursive_mutex_base() = default;
79 #else
80  __native_type _M_mutex;
81 
82  __recursive_mutex_base()
83  {
84  // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
85  __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
86  }
87 
88  ~__recursive_mutex_base()
89  { __gthread_recursive_mutex_destroy(&_M_mutex); }
90 #endif
91  };
92 
93  /// The standard recursive mutex type.
94  class recursive_mutex : private __recursive_mutex_base
95  {
96  public:
97  typedef __native_type* native_handle_type;
98 
99  recursive_mutex() = default;
100  ~recursive_mutex() = default;
101 
102  recursive_mutex(const recursive_mutex&) = delete;
103  recursive_mutex& operator=(const recursive_mutex&) = delete;
104 
105  void
106  lock()
107  {
108  int __e = __gthread_recursive_mutex_lock(&_M_mutex);
109 
110  // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
111  if (__e)
112  __throw_system_error(__e);
113  }
114 
115  bool
116  try_lock() noexcept
117  {
118  // XXX EINVAL, EAGAIN, EBUSY
119  return !__gthread_recursive_mutex_trylock(&_M_mutex);
120  }
121 
122  void
123  unlock()
124  {
125  // XXX EINVAL, EAGAIN, EBUSY
126  __gthread_recursive_mutex_unlock(&_M_mutex);
127  }
128 
129  native_handle_type
130  native_handle() noexcept
131  { return &_M_mutex; }
132  };
133 
134 #if _GTHREAD_USE_MUTEX_TIMEDLOCK
135  template<typename _Derived>
136  class __timed_mutex_impl
137  {
138  protected:
139  template<typename _Rep, typename _Period>
140  bool
141  _M_try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
142  {
143 #if _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK
144  using __clock = chrono::steady_clock;
145 #else
146  using __clock = chrono::system_clock;
147 #endif
148 
149  auto __rt = chrono::duration_cast<__clock::duration>(__rtime);
151  ++__rt;
152  return _M_try_lock_until(__clock::now() + __rt);
153  }
154 
155  template<typename _Duration>
156  bool
157  _M_try_lock_until(const chrono::time_point<chrono::system_clock,
158  _Duration>& __atime)
159  {
160  auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
161  auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
162 
163  __gthread_time_t __ts = {
164  static_cast<std::time_t>(__s.time_since_epoch().count()),
165  static_cast<long>(__ns.count())
166  };
167 
168  return static_cast<_Derived*>(this)->_M_timedlock(__ts);
169  }
170 
171 #ifdef _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK
172  template<typename _Duration>
173  bool
174  _M_try_lock_until(const chrono::time_point<chrono::steady_clock,
175  _Duration>& __atime)
176  {
177  auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
178  auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
179 
180  __gthread_time_t __ts = {
181  static_cast<std::time_t>(__s.time_since_epoch().count()),
182  static_cast<long>(__ns.count())
183  };
184 
185  return static_cast<_Derived*>(this)->_M_clocklock(CLOCK_MONOTONIC,
186  __ts);
187  }
188 #endif
189 
190  template<typename _Clock, typename _Duration>
191  bool
192  _M_try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
193  {
194 #if __cplusplus > 201703L
195  static_assert(chrono::is_clock_v<_Clock>);
196 #endif
197  // The user-supplied clock may not tick at the same rate as
198  // steady_clock, so we must loop in order to guarantee that
199  // the timeout has expired before returning false.
200  auto __now = _Clock::now();
201  do {
202  auto __rtime = __atime - __now;
203  if (_M_try_lock_for(__rtime))
204  return true;
205  __now = _Clock::now();
206  } while (__atime > __now);
207  return false;
208  }
209  };
210 
211  /// The standard timed mutex type.
212  class timed_mutex
213  : private __mutex_base, public __timed_mutex_impl<timed_mutex>
214  {
215  public:
216  typedef __native_type* native_handle_type;
217 
218  timed_mutex() = default;
219  ~timed_mutex() = default;
220 
221  timed_mutex(const timed_mutex&) = delete;
222  timed_mutex& operator=(const timed_mutex&) = delete;
223 
224  void
225  lock()
226  {
227  int __e = __gthread_mutex_lock(&_M_mutex);
228 
229  // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
230  if (__e)
231  __throw_system_error(__e);
232  }
233 
234  bool
235  try_lock() noexcept
236  {
237  // XXX EINVAL, EAGAIN, EBUSY
238  return !__gthread_mutex_trylock(&_M_mutex);
239  }
240 
241  template <class _Rep, class _Period>
242  bool
243  try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
244  { return _M_try_lock_for(__rtime); }
245 
246  template <class _Clock, class _Duration>
247  bool
248  try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
249  { return _M_try_lock_until(__atime); }
250 
251  void
252  unlock()
253  {
254  // XXX EINVAL, EAGAIN, EBUSY
255  __gthread_mutex_unlock(&_M_mutex);
256  }
257 
258  native_handle_type
259  native_handle() noexcept
260  { return &_M_mutex; }
261 
262  private:
263  friend class __timed_mutex_impl<timed_mutex>;
264 
265  bool
266  _M_timedlock(const __gthread_time_t& __ts)
267  { return !__gthread_mutex_timedlock(&_M_mutex, &__ts); }
268 
269 #if _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK
270  bool
271  _M_clocklock(clockid_t clockid, const __gthread_time_t& __ts)
272  { return !pthread_mutex_clocklock(&_M_mutex, clockid, &__ts); }
273 #endif
274  };
275 
276  /// recursive_timed_mutex
277  class recursive_timed_mutex
278  : private __recursive_mutex_base,
279  public __timed_mutex_impl<recursive_timed_mutex>
280  {
281  public:
282  typedef __native_type* native_handle_type;
283 
284  recursive_timed_mutex() = default;
285  ~recursive_timed_mutex() = default;
286 
287  recursive_timed_mutex(const recursive_timed_mutex&) = delete;
288  recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
289 
290  void
291  lock()
292  {
293  int __e = __gthread_recursive_mutex_lock(&_M_mutex);
294 
295  // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
296  if (__e)
297  __throw_system_error(__e);
298  }
299 
300  bool
301  try_lock() noexcept
302  {
303  // XXX EINVAL, EAGAIN, EBUSY
304  return !__gthread_recursive_mutex_trylock(&_M_mutex);
305  }
306 
307  template <class _Rep, class _Period>
308  bool
309  try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
310  { return _M_try_lock_for(__rtime); }
311 
312  template <class _Clock, class _Duration>
313  bool
314  try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
315  { return _M_try_lock_until(__atime); }
316 
317  void
318  unlock()
319  {
320  // XXX EINVAL, EAGAIN, EBUSY
321  __gthread_recursive_mutex_unlock(&_M_mutex);
322  }
323 
324  native_handle_type
325  native_handle() noexcept
326  { return &_M_mutex; }
327 
328  private:
329  friend class __timed_mutex_impl<recursive_timed_mutex>;
330 
331  bool
332  _M_timedlock(const __gthread_time_t& __ts)
333  { return !__gthread_recursive_mutex_timedlock(&_M_mutex, &__ts); }
334 
335 #ifdef _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK
336  bool
337  _M_clocklock(clockid_t clockid, const __gthread_time_t& __ts)
338  { return !pthread_mutex_clocklock(&_M_mutex, clockid, &__ts); }
339 #endif
340  };
341 
342 #else // !_GTHREAD_USE_MUTEX_TIMEDLOCK
343 
344  /// timed_mutex
346  {
347  mutex _M_mut;
348  condition_variable _M_cv;
349  bool _M_locked = false;
350 
351  public:
352 
353  timed_mutex() = default;
354  ~timed_mutex() { __glibcxx_assert( !_M_locked ); }
355 
356  timed_mutex(const timed_mutex&) = delete;
357  timed_mutex& operator=(const timed_mutex&) = delete;
358 
359  void
360  lock()
361  {
362  unique_lock<mutex> __lk(_M_mut);
363  _M_cv.wait(__lk, [&]{ return !_M_locked; });
364  _M_locked = true;
365  }
366 
367  bool
368  try_lock()
369  {
370  lock_guard<mutex> __lk(_M_mut);
371  if (_M_locked)
372  return false;
373  _M_locked = true;
374  return true;
375  }
376 
377  template<typename _Rep, typename _Period>
378  bool
379  try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
380  {
381  unique_lock<mutex> __lk(_M_mut);
382  if (!_M_cv.wait_for(__lk, __rtime, [&]{ return !_M_locked; }))
383  return false;
384  _M_locked = true;
385  return true;
386  }
387 
388  template<typename _Clock, typename _Duration>
389  bool
390  try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
391  {
392  unique_lock<mutex> __lk(_M_mut);
393  if (!_M_cv.wait_until(__lk, __atime, [&]{ return !_M_locked; }))
394  return false;
395  _M_locked = true;
396  return true;
397  }
398 
399  void
400  unlock()
401  {
402  lock_guard<mutex> __lk(_M_mut);
403  __glibcxx_assert( _M_locked );
404  _M_locked = false;
405  _M_cv.notify_one();
406  }
407  };
408 
409  /// recursive_timed_mutex
411  {
412  mutex _M_mut;
413  condition_variable _M_cv;
414  thread::id _M_owner;
415  unsigned _M_count = 0;
416 
417  // Predicate type that tests whether the current thread can lock a mutex.
418  struct _Can_lock
419  {
420  // Returns true if the mutex is unlocked or is locked by _M_caller.
421  bool
422  operator()() const noexcept
423  { return _M_mx->_M_count == 0 || _M_mx->_M_owner == _M_caller; }
424 
425  const recursive_timed_mutex* _M_mx;
426  thread::id _M_caller;
427  };
428 
429  public:
430 
431  recursive_timed_mutex() = default;
432  ~recursive_timed_mutex() { __glibcxx_assert( _M_count == 0 ); }
433 
435  recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
436 
437  void
438  lock()
439  {
440  auto __id = this_thread::get_id();
441  _Can_lock __can_lock{this, __id};
442  unique_lock<mutex> __lk(_M_mut);
443  _M_cv.wait(__lk, __can_lock);
444  if (_M_count == -1u)
445  __throw_system_error(EAGAIN); // [thread.timedmutex.recursive]/3
446  _M_owner = __id;
447  ++_M_count;
448  }
449 
450  bool
451  try_lock()
452  {
453  auto __id = this_thread::get_id();
454  _Can_lock __can_lock{this, __id};
455  lock_guard<mutex> __lk(_M_mut);
456  if (!__can_lock())
457  return false;
458  if (_M_count == -1u)
459  return false;
460  _M_owner = __id;
461  ++_M_count;
462  return true;
463  }
464 
465  template<typename _Rep, typename _Period>
466  bool
467  try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
468  {
469  auto __id = this_thread::get_id();
470  _Can_lock __can_lock{this, __id};
471  unique_lock<mutex> __lk(_M_mut);
472  if (!_M_cv.wait_for(__lk, __rtime, __can_lock))
473  return false;
474  if (_M_count == -1u)
475  return false;
476  _M_owner = __id;
477  ++_M_count;
478  return true;
479  }
480 
481  template<typename _Clock, typename _Duration>
482  bool
483  try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
484  {
485  auto __id = this_thread::get_id();
486  _Can_lock __can_lock{this, __id};
487  unique_lock<mutex> __lk(_M_mut);
488  if (!_M_cv.wait_until(__lk, __atime, __can_lock))
489  return false;
490  if (_M_count == -1u)
491  return false;
492  _M_owner = __id;
493  ++_M_count;
494  return true;
495  }
496 
497  void
498  unlock()
499  {
500  lock_guard<mutex> __lk(_M_mut);
501  __glibcxx_assert( _M_owner == this_thread::get_id() );
502  __glibcxx_assert( _M_count > 0 );
503  if (--_M_count == 0)
504  {
505  _M_owner = {};
506  _M_cv.notify_one();
507  }
508  }
509  };
510 
511 #endif
512 #endif // _GLIBCXX_HAS_GTHREADS
513 
514  /// @cond undocumented
515  template<typename _Lock>
516  inline unique_lock<_Lock>
517  __try_to_lock(_Lock& __l)
518  { return unique_lock<_Lock>{__l, try_to_lock}; }
519 
520  template<int _Idx, bool _Continue = true>
521  struct __try_lock_impl
522  {
523  template<typename... _Lock>
524  static void
525  __do_try_lock(tuple<_Lock&...>& __locks, int& __idx)
526  {
527  __idx = _Idx;
528  auto __lock = std::__try_to_lock(std::get<_Idx>(__locks));
529  if (__lock.owns_lock())
530  {
531  constexpr bool __cont = _Idx + 2 < sizeof...(_Lock);
532  using __try_locker = __try_lock_impl<_Idx + 1, __cont>;
533  __try_locker::__do_try_lock(__locks, __idx);
534  if (__idx == -1)
535  __lock.release();
536  }
537  }
538  };
539 
540  template<int _Idx>
541  struct __try_lock_impl<_Idx, false>
542  {
543  template<typename... _Lock>
544  static void
545  __do_try_lock(tuple<_Lock&...>& __locks, int& __idx)
546  {
547  __idx = _Idx;
548  auto __lock = std::__try_to_lock(std::get<_Idx>(__locks));
549  if (__lock.owns_lock())
550  {
551  __idx = -1;
552  __lock.release();
553  }
554  }
555  };
556  /// @endcond
557 
558  /** @brief Generic try_lock.
559  * @param __l1 Meets Lockable requirements (try_lock() may throw).
560  * @param __l2 Meets Lockable requirements (try_lock() may throw).
561  * @param __l3 Meets Lockable requirements (try_lock() may throw).
562  * @return Returns -1 if all try_lock() calls return true. Otherwise returns
563  * a 0-based index corresponding to the argument that returned false.
564  * @post Either all arguments are locked, or none will be.
565  *
566  * Sequentially calls try_lock() on each argument.
567  */
568  template<typename _Lock1, typename _Lock2, typename... _Lock3>
569  int
570  try_lock(_Lock1& __l1, _Lock2& __l2, _Lock3&... __l3)
571  {
572  int __idx;
573  auto __locks = std::tie(__l1, __l2, __l3...);
574  __try_lock_impl<0>::__do_try_lock(__locks, __idx);
575  return __idx;
576  }
577 
578  /** @brief Generic lock.
579  * @param __l1 Meets Lockable requirements (try_lock() may throw).
580  * @param __l2 Meets Lockable requirements (try_lock() may throw).
581  * @param __l3 Meets Lockable requirements (try_lock() may throw).
582  * @throw An exception thrown by an argument's lock() or try_lock() member.
583  * @post All arguments are locked.
584  *
585  * All arguments are locked via a sequence of calls to lock(), try_lock()
586  * and unlock(). If the call exits via an exception any locks that were
587  * obtained will be released.
588  */
589  template<typename _L1, typename _L2, typename... _L3>
590  void
591  lock(_L1& __l1, _L2& __l2, _L3&... __l3)
592  {
593  while (true)
594  {
595  using __try_locker = __try_lock_impl<0, sizeof...(_L3) != 0>;
596  unique_lock<_L1> __first(__l1);
597  int __idx;
598  auto __locks = std::tie(__l2, __l3...);
599  __try_locker::__do_try_lock(__locks, __idx);
600  if (__idx == -1)
601  {
602  __first.release();
603  return;
604  }
605  }
606  }
607 
608 #if __cplusplus >= 201703L
609 #define __cpp_lib_scoped_lock 201703
610  /** @brief A scoped lock type for multiple lockable objects.
611  *
612  * A scoped_lock controls mutex ownership within a scope, releasing
613  * ownership in the destructor.
614  */
615  template<typename... _MutexTypes>
617  {
618  public:
619  explicit scoped_lock(_MutexTypes&... __m) : _M_devices(std::tie(__m...))
620  { std::lock(__m...); }
621 
622  explicit scoped_lock(adopt_lock_t, _MutexTypes&... __m) noexcept
623  : _M_devices(std::tie(__m...))
624  { } // calling thread owns mutex
625 
626  ~scoped_lock()
627  { std::apply([](auto&... __m) { (__m.unlock(), ...); }, _M_devices); }
628 
629  scoped_lock(const scoped_lock&) = delete;
630  scoped_lock& operator=(const scoped_lock&) = delete;
631 
632  private:
633  tuple<_MutexTypes&...> _M_devices;
634  };
635 
636  template<>
637  class scoped_lock<>
638  {
639  public:
640  explicit scoped_lock() = default;
641  explicit scoped_lock(adopt_lock_t) noexcept { }
642  ~scoped_lock() = default;
643 
644  scoped_lock(const scoped_lock&) = delete;
645  scoped_lock& operator=(const scoped_lock&) = delete;
646  };
647 
648  template<typename _Mutex>
649  class scoped_lock<_Mutex>
650  {
651  public:
652  using mutex_type = _Mutex;
653 
654  explicit scoped_lock(mutex_type& __m) : _M_device(__m)
655  { _M_device.lock(); }
656 
657  explicit scoped_lock(adopt_lock_t, mutex_type& __m) noexcept
658  : _M_device(__m)
659  { } // calling thread owns mutex
660 
661  ~scoped_lock()
662  { _M_device.unlock(); }
663 
664  scoped_lock(const scoped_lock&) = delete;
665  scoped_lock& operator=(const scoped_lock&) = delete;
666 
667  private:
668  mutex_type& _M_device;
669  };
670 #endif // C++17
671 
672 #ifdef _GLIBCXX_HAS_GTHREADS
673  /// Flag type used by std::call_once
674  struct once_flag
675  {
676  constexpr once_flag() noexcept = default;
677 
678  /// Deleted copy constructor
679  once_flag(const once_flag&) = delete;
680  /// Deleted assignment operator
681  once_flag& operator=(const once_flag&) = delete;
682 
683  private:
684  // For gthreads targets a pthread_once_t is used with pthread_once, but
685  // for most targets this doesn't work correctly for exceptional executions.
686  __gthread_once_t _M_once = __GTHREAD_ONCE_INIT;
687 
688  struct _Prepare_execution;
689 
690  template<typename _Callable, typename... _Args>
691  friend void
692  call_once(once_flag& __once, _Callable&& __f, _Args&&... __args);
693  };
694 
695  /// @cond undocumented
696 # ifdef _GLIBCXX_HAVE_TLS
697  // If TLS is available use thread-local state for the type-erased callable
698  // that is being run by std::call_once in the current thread.
699  extern __thread void* __once_callable;
700  extern __thread void (*__once_call)();
701 
702  // RAII type to set up state for pthread_once call.
703  struct once_flag::_Prepare_execution
704  {
705  template<typename _Callable>
706  explicit
707  _Prepare_execution(_Callable& __c)
708  {
709  // Store address in thread-local pointer:
710  __once_callable = std::__addressof(__c);
711  // Trampoline function to invoke the closure via thread-local pointer:
712  __once_call = [] { (*static_cast<_Callable*>(__once_callable))(); };
713  }
714 
715  ~_Prepare_execution()
716  {
717  // PR libstdc++/82481
718  __once_callable = nullptr;
719  __once_call = nullptr;
720  }
721 
722  _Prepare_execution(const _Prepare_execution&) = delete;
723  _Prepare_execution& operator=(const _Prepare_execution&) = delete;
724  };
725 
726 # else
727  // Without TLS use a global std::mutex and store the callable in a
728  // global std::function.
729  extern function<void()> __once_functor;
730 
731  extern void
732  __set_once_functor_lock_ptr(unique_lock<mutex>*);
733 
734  extern mutex&
735  __get_once_mutex();
736 
737  // RAII type to set up state for pthread_once call.
738  struct once_flag::_Prepare_execution
739  {
740  template<typename _Callable>
741  explicit
742  _Prepare_execution(_Callable& __c)
743  {
744  // Store the callable in the global std::function
745  __once_functor = __c;
746  __set_once_functor_lock_ptr(&_M_functor_lock);
747  }
748 
749  ~_Prepare_execution()
750  {
751  if (_M_functor_lock)
752  __set_once_functor_lock_ptr(nullptr);
753  }
754 
755  private:
756  // XXX This deadlocks if used recursively (PR 97949)
757  unique_lock<mutex> _M_functor_lock{__get_once_mutex()};
758 
759  _Prepare_execution(const _Prepare_execution&) = delete;
760  _Prepare_execution& operator=(const _Prepare_execution&) = delete;
761  };
762 # endif
763  /// @endcond
764 
765  // This function is passed to pthread_once by std::call_once.
766  // It runs __once_call() or __once_functor().
767  extern "C" void __once_proxy(void);
768 
769  /// Invoke a callable and synchronize with other calls using the same flag
770  template<typename _Callable, typename... _Args>
771  void
772  call_once(once_flag& __once, _Callable&& __f, _Args&&... __args)
773  {
774  // Closure type that runs the function
775  auto __callable = [&] {
776  std::__invoke(std::forward<_Callable>(__f),
777  std::forward<_Args>(__args)...);
778  };
779 
780  once_flag::_Prepare_execution __exec(__callable);
781 
782  // XXX pthread_once does not reset the flag if an exception is thrown.
783  if (int __e = __gthread_once(&__once._M_once, &__once_proxy))
784  __throw_system_error(__e);
785  }
786 
787 #else // _GLIBCXX_HAS_GTHREADS
788 
789  /// Flag type used by std::call_once
790  struct once_flag
791  {
792  constexpr once_flag() noexcept = default;
793 
794  /// Deleted copy constructor
795  once_flag(const once_flag&) = delete;
796  /// Deleted assignment operator
797  once_flag& operator=(const once_flag&) = delete;
798 
799  private:
800  // There are two different std::once_flag interfaces, abstracting four
801  // different implementations.
802  // The single-threaded interface uses the _M_activate() and _M_finish(bool)
803  // functions, which start and finish an active execution respectively.
804  // See [thread.once.callonce] in C++11 for the definition of
805  // active/passive/returning/exceptional executions.
806  enum _Bits : int { _Init = 0, _Active = 1, _Done = 2 };
807 
808  int _M_once = _Bits::_Init;
809 
810  // Check to see if all executions will be passive now.
811  bool
812  _M_passive() const noexcept;
813 
814  // Attempts to begin an active execution.
815  bool _M_activate();
816 
817  // Must be called to complete an active execution.
818  // The argument is true if the active execution was a returning execution,
819  // false if it was an exceptional execution.
820  void _M_finish(bool __returning) noexcept;
821 
822  // RAII helper to call _M_finish.
823  struct _Active_execution
824  {
825  explicit _Active_execution(once_flag& __flag) : _M_flag(__flag) { }
826 
827  ~_Active_execution() { _M_flag._M_finish(_M_returning); }
828 
829  _Active_execution(const _Active_execution&) = delete;
830  _Active_execution& operator=(const _Active_execution&) = delete;
831 
832  once_flag& _M_flag;
833  bool _M_returning = false;
834  };
835 
836  template<typename _Callable, typename... _Args>
837  friend void
838  call_once(once_flag& __once, _Callable&& __f, _Args&&... __args);
839  };
840 
841  // Inline definitions of std::once_flag members for single-threaded targets.
842 
843  inline bool
844  once_flag::_M_passive() const noexcept
845  { return _M_once == _Bits::_Done; }
846 
847  inline bool
848  once_flag::_M_activate()
849  {
850  if (_M_once == _Bits::_Init) [[__likely__]]
851  {
852  _M_once = _Bits::_Active;
853  return true;
854  }
855  else if (_M_passive()) // Caller should have checked this already.
856  return false;
857  else
858  __throw_system_error(EDEADLK);
859  }
860 
861  inline void
862  once_flag::_M_finish(bool __returning) noexcept
863  { _M_once = __returning ? _Bits::_Done : _Bits::_Init; }
864 
865  /// Invoke a callable and synchronize with other calls using the same flag
866  template<typename _Callable, typename... _Args>
867  inline void
868  call_once(once_flag& __once, _Callable&& __f, _Args&&... __args)
869  {
870  if (__once._M_passive())
871  return;
872  else if (__once._M_activate())
873  {
874  once_flag::_Active_execution __exec(__once);
875 
876  // _GLIBCXX_RESOLVE_LIB_DEFECTS
877  // 2442. call_once() shouldn't DECAY_COPY()
878  std::__invoke(std::forward<_Callable>(__f),
879  std::forward<_Args>(__args)...);
880 
881  // __f(__args...) did not throw
882  __exec._M_returning = true;
883  }
884  }
885 #endif // _GLIBCXX_HAS_GTHREADS
886 
887  /// @} group mutexes
888 _GLIBCXX_END_NAMESPACE_VERSION
889 } // namespace
890 
891 #endif // C++11
892 
893 #endif // _GLIBCXX_MUTEX
The standard recursive mutex type.
Definition: mutex:94
constexpr try_to_lock_t try_to_lock
Tag used to prevent a scoped lock from blocking if a mutex is locked.
Definition: std_mutex.h:212
constexpr enable_if< __is_duration< _ToDur >::value, time_point< _Clock, _ToDur > >::type time_point_cast(const time_point< _Clock, _Dur > &__t)
time_point_cast
Definition: chrono:936
constexpr tuple< _Elements &...> tie(_Elements &...__args) noexcept
tie
Definition: tuple:1735
ratio_greater
Definition: ratio:409
int try_lock(_Lock1 &__l1, _Lock2 &__l2, _Lock3 &...__l3)
Generic try_lock.
Definition: mutex:570
A scoped lock type for multiple lockable objects.
Definition: mutex:616
Flag type used by std::call_once.
Definition: mutex:674
The standard mutex type.
Definition: std_mutex.h:83
timed_mutex
Definition: mutex:345
once_flag & operator=(const once_flag &)=delete
Deleted assignment operator.
thread::id
Definition: std_thread.h:81
A simple scoped lock type.
Definition: std_mutex.h:223
duration< int64_t, nano > nanoseconds
nanoseconds
Definition: chrono:816
friend void call_once(once_flag &__once, _Callable &&__f, _Args &&...__args)
Invoke a callable and synchronize with other calls using the same flag.
Definition: mutex:772
condition_variable
thread::id get_id() noexcept
this_thread::get_id
Definition: std_thread.h:307
duration
Definition: chrono:71
A movable scoped lock type.
Definition: unique_lock.h:57
void lock(_L1 &__l1, _L2 &__l2, _L3 &...__l3)
Generic lock.
Definition: mutex:591
time_point
Definition: chrono:74
duration< int64_t > seconds
seconds
Definition: chrono:825
constexpr __enable_if_is_duration< _ToDur > duration_cast(const duration< _Rep, _Period > &__d)
duration_cast
Definition: chrono:254
Assume the calling thread has already obtained mutex ownership and manage it.
Definition: std_mutex.h:206
recursive_timed_mutex
Definition: mutex:410
Primary class template, tuple.
Definition: tuple:57
constexpr _Tp * __addressof(_Tp &__r) noexcept
Same as C++11 std::addressof.
Definition: move.h:49
void call_once(once_flag &__once, _Callable &&__f, _Args &&...__args)
Invoke a callable and synchronize with other calls using the same flag.
Definition: mutex:772
auto_ptr & operator=(auto_ptr &__a)
auto_ptr assignment operator.
Definition: auto_ptr.h:128