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);
150  if (ratio_greater<__clock::period, _Period>())
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
345  class 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
410  class 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 
434  recursive_timed_mutex(const recursive_timed_mutex&) = delete;
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>
616  class scoped_lock
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  /// Flag type used by std::call_once
673  struct once_flag
674  {
675  constexpr once_flag() noexcept = default;
676 
677  /// Deleted copy constructor
678  once_flag(const once_flag&) = delete;
679  /// Deleted assignment operator
680  once_flag& operator=(const once_flag&) = delete;
681 
682  private:
683  // There are two different std::once_flag interfaces, abstracting four
684  // different implementations.
685  // The preferred interface uses the _M_activate() and _M_finish(bool)
686  // member functions (introduced in GCC 11), which start and finish an
687  // active execution respectively. See [thread.once.callonce] in C++11
688  // for the definition of active/passive/returning/exceptional executions.
689  // This interface is supported for Linux (using atomics and futexes) and
690  // for single-threaded targets with no gthreads support.
691  // For other targets a pthread_once_t is used with pthread_once, but that
692  // doesn't work correctly for exceptional executions. That interface
693  // uses an object of type _Prepare_execution and a lambda expression.
694 #if defined _GLIBCXX_HAVE_LINUX_FUTEX || ! defined _GLIBCXX_HAS_GTHREADS
695  enum _Bits : int { _Init = 0, _Active = 1, _Done = 2 };
696 
697  int _M_once = _Bits::_Init;
698 
699  // Non-blocking check to see if all executions will be passive now.
700  bool
701  _M_passive() const noexcept;
702 
703  // Attempts to begin an active execution. Blocks until it either:
704  // - returns true if an active execution has started on this thread, or
705  // - returns false if a returning execution happens on another thread.
706  bool _M_activate();
707 
708  // Must be called to complete an active execution.
709  // The argument is true if the active execution was a returning execution,
710  // false if it was an exceptional execution.
711  void _M_finish(bool __returning) noexcept;
712 
713  // RAII helper to call _M_finish.
714  struct _Active_execution
715  {
716  explicit _Active_execution(once_flag& __flag) : _M_flag(__flag) { }
717 
718  ~_Active_execution() { _M_flag._M_finish(_M_returning); }
719 
720  _Active_execution(const _Active_execution&) = delete;
721  _Active_execution& operator=(const _Active_execution&) = delete;
722 
723  once_flag& _M_flag;
724  bool _M_returning = false;
725  };
726 #else
727  __gthread_once_t _M_once = __GTHREAD_ONCE_INIT;
728 
729  struct _Prepare_execution;
730 #endif // ! GTHREADS
731 
732  template<typename _Callable, typename... _Args>
733  friend void
734  call_once(once_flag& __once, _Callable&& __f, _Args&&... __args);
735  };
736 
737 #if ! defined _GLIBCXX_HAS_GTHREADS
738  // Inline definitions of std::once_flag members for single-threaded targets.
739 
740  inline bool
741  once_flag::_M_passive() const noexcept
742  { return _M_once == _Bits::_Done; }
743 
744  inline bool
745  once_flag::_M_activate()
746  {
747  if (_M_once == _Bits::_Init) [[__likely__]]
748  {
749  _M_once = _Bits::_Active;
750  return true;
751  }
752  else if (_M_passive()) // Caller should have checked this already.
753  return false;
754  else
755  __throw_system_error(EDEADLK);
756  }
757 
758  inline void
759  once_flag::_M_finish(bool __returning) noexcept
760  { _M_once = __returning ? _Bits::_Done : _Bits::_Init; }
761 
762 #elif defined _GLIBCXX_HAVE_LINUX_FUTEX
763 
764  // Define this inline to make passive executions fast.
765  inline bool
766  once_flag::_M_passive() const noexcept
767  {
768  if (__gnu_cxx::__is_single_threaded())
769  return _M_once == _Bits::_Done;
770  else
771  return __atomic_load_n(&_M_once, __ATOMIC_ACQUIRE) == _Bits::_Done;
772  }
773 
774 #else // GTHREADS && ! FUTEX
775 
776  /// @cond undocumented
777 # ifdef _GLIBCXX_HAVE_TLS
778  // If TLS is available use thread-local state for the type-erased callable
779  // that is being run by std::call_once in the current thread.
780  extern __thread void* __once_callable;
781  extern __thread void (*__once_call)();
782 # else
783  // Without TLS use a global std::mutex and store the callable in a
784  // global std::function.
785  extern function<void()> __once_functor;
786 
787  extern void
788  __set_once_functor_lock_ptr(unique_lock<mutex>*);
789 
790  extern mutex&
791  __get_once_mutex();
792 # endif
793 
794  // This function is passed to pthread_once by std::call_once.
795  // It runs __once_call() or __once_functor().
796  extern "C" void __once_proxy(void);
797 
798  // RAII type to set up state for pthread_once call.
799  struct once_flag::_Prepare_execution
800  {
801 #ifdef _GLIBCXX_HAVE_TLS
802  template<typename _Callable>
803  explicit
804  _Prepare_execution(_Callable& __c)
805  {
806  // Store address in thread-local pointer:
807  __once_callable = std::__addressof(__c);
808  // Trampoline function to invoke the closure via thread-local pointer:
809  __once_call = [] { (*static_cast<_Callable*>(__once_callable))(); };
810  }
811 
812  ~_Prepare_execution()
813  {
814  // PR libstdc++/82481
815  __once_callable = nullptr;
816  __once_call = nullptr;
817  }
818 #else // ! TLS
819  template<typename _Callable>
820  explicit
821  _Prepare_execution(_Callable& __c)
822  {
823  // Store the callable in the global std::function
824  __once_functor = __c;
825  __set_once_functor_lock_ptr(&_M_functor_lock);
826  }
827 
828  ~_Prepare_execution()
829  {
830  if (_M_functor_lock)
831  __set_once_functor_lock_ptr(nullptr);
832  }
833 
834  private:
835  unique_lock<mutex> _M_functor_lock{__get_once_mutex()};
836 #endif // ! TLS
837 
838  _Prepare_execution(const _Prepare_execution&) = delete;
839  _Prepare_execution& operator=(const _Prepare_execution&) = delete;
840  };
841  /// @endcond
842 #endif
843 
844  /// Invoke a callable and synchronize with other calls using the same flag
845  template<typename _Callable, typename... _Args>
846  void
847  call_once(once_flag& __once, _Callable&& __f, _Args&&... __args)
848  {
849 #if defined _GLIBCXX_HAVE_LINUX_FUTEX || ! defined _GLIBCXX_HAS_GTHREADS
850  if (__once._M_passive())
851  return;
852  else if (__once._M_activate())
853  {
854  once_flag::_Active_execution __exec(__once);
855 
856  // _GLIBCXX_RESOLVE_LIB_DEFECTS
857  // 2442. call_once() shouldn't DECAY_COPY()
858  std::__invoke(std::forward<_Callable>(__f),
859  std::forward<_Args>(__args)...);
860 
861  // __f(__args...) did not throw
862  __exec._M_returning = true;
863  }
864 #else
865  // Closure type that runs the function
866  auto __callable = [&] {
867  std::__invoke(std::forward<_Callable>(__f),
868  std::forward<_Args>(__args)...);
869  };
870 
871  once_flag::_Prepare_execution __exec(__callable);
872 
873  // XXX pthread_once does not reset the flag if an exception is thrown.
874  if (int __e = __gthread_once(&__once._M_once, &__once_proxy))
875  __throw_system_error(__e);
876 #endif
877  }
878 
879  // @} group mutexes
880 _GLIBCXX_END_NAMESPACE_VERSION
881 } // namespace
882 
883 #endif // C++11
884 
885 #endif // _GLIBCXX_MUTEX