Line data Source code
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 3680 : __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 3680 : 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 176153 : lock()
107 : {
108 176153 : int __e = __gthread_recursive_mutex_lock(&_M_mutex);
109 :
110 : // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
111 176176 : if (__e)
112 0 : __throw_system_error(__e);
113 176176 : }
114 :
115 : bool
116 78 : try_lock() noexcept
117 : {
118 : // XXX EINVAL, EAGAIN, EBUSY
119 78 : return !__gthread_recursive_mutex_trylock(&_M_mutex);
120 : }
121 :
122 : void
123 176257 : unlock()
124 : {
125 : // XXX EINVAL, EAGAIN, EBUSY
126 176257 : __gthread_recursive_mutex_unlock(&_M_mutex);
127 176259 : }
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 418 : __try_to_lock(_Lock& __l)
518 418 : { 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 418 : __do_try_lock(tuple<_Lock&...>& __locks, int& __idx)
546 : {
547 418 : __idx = _Idx;
548 418 : auto __lock = std::__try_to_lock(std::get<_Idx>(__locks));
549 418 : if (__lock.owns_lock())
550 : {
551 418 : __idx = -1;
552 418 : __lock.release();
553 : }
554 418 : }
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 418 : lock(_L1& __l1, _L2& __l2, _L3&... __l3)
592 : {
593 418 : while (true)
594 : {
595 : using __try_locker = __try_lock_impl<0, sizeof...(_L3) != 0>;
596 418 : unique_lock<_L1> __first(__l1);
597 : int __idx;
598 418 : auto __locks = std::tie(__l2, __l3...);
599 418 : __try_locker::__do_try_lock(__locks, __idx);
600 418 : if (__idx == -1)
601 : {
602 418 : __first.release();
603 836 : 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 340 : explicit scoped_lock(_MutexTypes&... __m) : _M_devices(std::tie(__m...))
620 340 : { 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 340 : ~scoped_lock()
627 680 : { 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 3030 : 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 2744 : _Prepare_execution(_Callable& __c)
708 : {
709 : // Store address in thread-local pointer:
710 2744 : __once_callable = std::__addressof(__c);
711 : // Trampoline function to invoke the closure via thread-local pointer:
712 12051 : __once_call = [] { (*static_cast<_Callable*>(__once_callable))(); };
713 2744 : }
714 :
715 2744 : ~_Prepare_execution()
716 : {
717 : // PR libstdc++/82481
718 2744 : __once_callable = nullptr;
719 2744 : __once_call = nullptr;
720 2744 : }
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 2744 : call_once(once_flag& __once, _Callable&& __f, _Args&&... __args)
773 : {
774 : // Closure type that runs the function
775 30626 : auto __callable = [&] {
776 9307 : std::__invoke(std::forward<_Callable>(__f),
777 9268 : std::forward<_Args>(__args)...);
778 : };
779 :
780 2744 : once_flag::_Prepare_execution __exec(__callable);
781 :
782 : // XXX pthread_once does not reset the flag if an exception is thrown.
783 2744 : if (int __e = __gthread_once(&__once._M_once, &__once_proxy))
784 0 : __throw_system_error(__e);
785 2744 : }
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
|