Line data Source code
1 : // <mutex> -*- C++ -*-
2 :
3 : // Copyright (C) 2003-2013 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 :
48 : #ifdef _GLIBCXX_USE_C99_STDINT_TR1
49 :
50 : namespace std _GLIBCXX_VISIBILITY(default)
51 : {
52 : _GLIBCXX_BEGIN_NAMESPACE_VERSION
53 :
54 : #ifdef _GLIBCXX_HAS_GTHREADS
55 : // Common base class for std::mutex and std::timed_mutex
56 : class __mutex_base
57 : {
58 : protected:
59 : typedef __gthread_mutex_t __native_type;
60 :
61 : #ifdef __GTHREAD_MUTEX_INIT
62 : __native_type _M_mutex = __GTHREAD_MUTEX_INIT;
63 :
64 18 : constexpr __mutex_base() noexcept = default;
65 : #else
66 : __native_type _M_mutex;
67 :
68 : __mutex_base() noexcept
69 : {
70 : // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
71 : __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex);
72 : }
73 :
74 : ~__mutex_base() noexcept { __gthread_mutex_destroy(&_M_mutex); }
75 : #endif
76 :
77 : __mutex_base(const __mutex_base&) = delete;
78 : __mutex_base& operator=(const __mutex_base&) = delete;
79 : };
80 :
81 : // Common base class for std::recursive_mutex and std::timed_recursive_mutex
82 : class __recursive_mutex_base
83 : {
84 : protected:
85 : typedef __gthread_recursive_mutex_t __native_type;
86 :
87 : __recursive_mutex_base(const __recursive_mutex_base&) = delete;
88 : __recursive_mutex_base& operator=(const __recursive_mutex_base&) = delete;
89 :
90 : #ifdef __GTHREAD_RECURSIVE_MUTEX_INIT
91 : __native_type _M_mutex = __GTHREAD_RECURSIVE_MUTEX_INIT;
92 :
93 : __recursive_mutex_base() = default;
94 : #else
95 : __native_type _M_mutex;
96 :
97 : __recursive_mutex_base()
98 : {
99 : // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
100 : __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
101 : }
102 :
103 : ~__recursive_mutex_base()
104 : { __gthread_recursive_mutex_destroy(&_M_mutex); }
105 : #endif
106 : };
107 :
108 : /**
109 : * @defgroup mutexes Mutexes
110 : * @ingroup concurrency
111 : *
112 : * Classes for mutex support.
113 : * @{
114 : */
115 :
116 : /// mutex
117 : class mutex : private __mutex_base
118 : {
119 : public:
120 : typedef __native_type* native_handle_type;
121 :
122 : #ifdef __GTHREAD_MUTEX_INIT
123 : constexpr
124 : #endif
125 18 : mutex() noexcept = default;
126 : ~mutex() = default;
127 :
128 : mutex(const mutex&) = delete;
129 : mutex& operator=(const mutex&) = delete;
130 :
131 : void
132 10152246 : lock()
133 : {
134 10152246 : int __e = __gthread_mutex_lock(&_M_mutex);
135 :
136 : // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
137 10236258 : if (__e)
138 0 : __throw_system_error(__e);
139 10236258 : }
140 :
141 : bool
142 : try_lock() noexcept
143 : {
144 : // XXX EINVAL, EAGAIN, EBUSY
145 : return !__gthread_mutex_trylock(&_M_mutex);
146 : }
147 :
148 : void
149 10237994 : unlock()
150 : {
151 : // XXX EINVAL, EAGAIN, EPERM
152 10237994 : __gthread_mutex_unlock(&_M_mutex);
153 10238305 : }
154 :
155 : native_handle_type
156 : native_handle()
157 : { return &_M_mutex; }
158 : };
159 :
160 : /// recursive_mutex
161 : class recursive_mutex : private __recursive_mutex_base
162 : {
163 : public:
164 : typedef __native_type* native_handle_type;
165 :
166 : recursive_mutex() = default;
167 : ~recursive_mutex() = default;
168 :
169 : recursive_mutex(const recursive_mutex&) = delete;
170 : recursive_mutex& operator=(const recursive_mutex&) = delete;
171 :
172 : void
173 : lock()
174 : {
175 : int __e = __gthread_recursive_mutex_lock(&_M_mutex);
176 :
177 : // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
178 : if (__e)
179 : __throw_system_error(__e);
180 : }
181 :
182 : bool
183 : try_lock() noexcept
184 : {
185 : // XXX EINVAL, EAGAIN, EBUSY
186 : return !__gthread_recursive_mutex_trylock(&_M_mutex);
187 : }
188 :
189 : void
190 : unlock()
191 : {
192 : // XXX EINVAL, EAGAIN, EBUSY
193 : __gthread_recursive_mutex_unlock(&_M_mutex);
194 : }
195 :
196 : native_handle_type
197 : native_handle()
198 : { return &_M_mutex; }
199 : };
200 :
201 : #if _GTHREAD_USE_MUTEX_TIMEDLOCK
202 : /// timed_mutex
203 : class timed_mutex : private __mutex_base
204 : {
205 : #ifdef _GLIBCXX_USE_CLOCK_MONOTONIC
206 : typedef chrono::steady_clock __clock_t;
207 : #else
208 : typedef chrono::high_resolution_clock __clock_t;
209 : #endif
210 :
211 : public:
212 : typedef __native_type* native_handle_type;
213 :
214 : timed_mutex() = default;
215 : ~timed_mutex() = default;
216 :
217 : timed_mutex(const timed_mutex&) = delete;
218 : timed_mutex& operator=(const timed_mutex&) = delete;
219 :
220 : void
221 : lock()
222 : {
223 : int __e = __gthread_mutex_lock(&_M_mutex);
224 :
225 : // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
226 : if (__e)
227 : __throw_system_error(__e);
228 : }
229 :
230 : bool
231 : try_lock() noexcept
232 : {
233 : // XXX EINVAL, EAGAIN, EBUSY
234 : return !__gthread_mutex_trylock(&_M_mutex);
235 : }
236 :
237 : template <class _Rep, class _Period>
238 : bool
239 : try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
240 : { return _M_try_lock_for(__rtime); }
241 :
242 : template <class _Clock, class _Duration>
243 : bool
244 : try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
245 : { return _M_try_lock_until(__atime); }
246 :
247 : void
248 : unlock()
249 : {
250 : // XXX EINVAL, EAGAIN, EBUSY
251 : __gthread_mutex_unlock(&_M_mutex);
252 : }
253 :
254 : native_handle_type
255 : native_handle()
256 : { return &_M_mutex; }
257 :
258 : private:
259 : template<typename _Rep, typename _Period>
260 : bool
261 : _M_try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
262 : {
263 : auto __rt = chrono::duration_cast<__clock_t::duration>(__rtime);
264 : if (ratio_greater<__clock_t::period, _Period>())
265 : ++__rt;
266 :
267 : return _M_try_lock_until(__clock_t::now() + __rt);
268 : }
269 :
270 : template<typename _Duration>
271 : bool
272 : _M_try_lock_until(const chrono::time_point<__clock_t,
273 : _Duration>& __atime)
274 : {
275 : chrono::time_point<__clock_t, chrono::seconds> __s =
276 : chrono::time_point_cast<chrono::seconds>(__atime);
277 :
278 : chrono::nanoseconds __ns =
279 : chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
280 :
281 : __gthread_time_t __ts = {
282 : static_cast<std::time_t>(__s.time_since_epoch().count()),
283 : static_cast<long>(__ns.count())
284 : };
285 :
286 : return !__gthread_mutex_timedlock(native_handle(), &__ts);
287 : }
288 :
289 : template<typename _Clock, typename _Duration>
290 : bool
291 : _M_try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
292 : { return _M_try_lock_for(__atime - _Clock::now()); }
293 : };
294 :
295 : /// recursive_timed_mutex
296 : class recursive_timed_mutex : private __recursive_mutex_base
297 : {
298 : #ifdef _GLIBCXX_USE_CLOCK_MONOTONIC
299 : typedef chrono::steady_clock __clock_t;
300 : #else
301 : typedef chrono::high_resolution_clock __clock_t;
302 : #endif
303 :
304 : public:
305 : typedef __native_type* native_handle_type;
306 :
307 : recursive_timed_mutex() = default;
308 : ~recursive_timed_mutex() = default;
309 :
310 : recursive_timed_mutex(const recursive_timed_mutex&) = delete;
311 : recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
312 :
313 : void
314 : lock()
315 : {
316 : int __e = __gthread_recursive_mutex_lock(&_M_mutex);
317 :
318 : // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
319 : if (__e)
320 : __throw_system_error(__e);
321 : }
322 :
323 : bool
324 : try_lock() noexcept
325 : {
326 : // XXX EINVAL, EAGAIN, EBUSY
327 : return !__gthread_recursive_mutex_trylock(&_M_mutex);
328 : }
329 :
330 : template <class _Rep, class _Period>
331 : bool
332 : try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
333 : { return _M_try_lock_for(__rtime); }
334 :
335 : template <class _Clock, class _Duration>
336 : bool
337 : try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
338 : { return _M_try_lock_until(__atime); }
339 :
340 : void
341 : unlock()
342 : {
343 : // XXX EINVAL, EAGAIN, EBUSY
344 : __gthread_recursive_mutex_unlock(&_M_mutex);
345 : }
346 :
347 : native_handle_type
348 : native_handle()
349 : { return &_M_mutex; }
350 :
351 : private:
352 : template<typename _Rep, typename _Period>
353 : bool
354 : _M_try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
355 : {
356 : auto __rt = chrono::duration_cast<__clock_t::duration>(__rtime);
357 : if (ratio_greater<__clock_t::period, _Period>())
358 : ++__rt;
359 :
360 : return _M_try_lock_until(__clock_t::now() + __rt);
361 : }
362 :
363 : template<typename _Duration>
364 : bool
365 : _M_try_lock_until(const chrono::time_point<__clock_t,
366 : _Duration>& __atime)
367 : {
368 : chrono::time_point<__clock_t, chrono::seconds> __s =
369 : chrono::time_point_cast<chrono::seconds>(__atime);
370 :
371 : chrono::nanoseconds __ns =
372 : chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
373 :
374 : __gthread_time_t __ts = {
375 : static_cast<std::time_t>(__s.time_since_epoch().count()),
376 : static_cast<long>(__ns.count())
377 : };
378 :
379 : return !__gthread_mutex_timedlock(native_handle(), &__ts);
380 : }
381 :
382 : template<typename _Clock, typename _Duration>
383 : bool
384 : _M_try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
385 : { return _M_try_lock_for(__atime - _Clock::now()); }
386 : };
387 : #endif
388 : #endif // _GLIBCXX_HAS_GTHREADS
389 :
390 : /// Do not acquire ownership of the mutex.
391 : struct defer_lock_t { };
392 :
393 : /// Try to acquire ownership of the mutex without blocking.
394 : struct try_to_lock_t { };
395 :
396 : /// Assume the calling thread has already obtained mutex ownership
397 : /// and manage it.
398 : struct adopt_lock_t { };
399 :
400 : constexpr defer_lock_t defer_lock { };
401 : constexpr try_to_lock_t try_to_lock { };
402 : constexpr adopt_lock_t adopt_lock { };
403 :
404 : /// @brief Scoped lock idiom.
405 : // Acquire the mutex here with a constructor call, then release with
406 : // the destructor call in accordance with RAII style.
407 : template<typename _Mutex>
408 : class lock_guard
409 : {
410 : public:
411 : typedef _Mutex mutex_type;
412 :
413 6771664 : explicit lock_guard(mutex_type& __m) : _M_device(__m)
414 6771664 : { _M_device.lock(); }
415 :
416 : lock_guard(mutex_type& __m, adopt_lock_t) : _M_device(__m)
417 : { } // calling thread owns mutex
418 :
419 6828853 : ~lock_guard()
420 6828853 : { _M_device.unlock(); }
421 :
422 : lock_guard(const lock_guard&) = delete;
423 : lock_guard& operator=(const lock_guard&) = delete;
424 :
425 : private:
426 : mutex_type& _M_device;
427 : };
428 :
429 : /// unique_lock
430 : template<typename _Mutex>
431 : class unique_lock
432 : {
433 : public:
434 : typedef _Mutex mutex_type;
435 :
436 : unique_lock() noexcept
437 : : _M_device(0), _M_owns(false)
438 : { }
439 :
440 3413693 : explicit unique_lock(mutex_type& __m)
441 3413693 : : _M_device(&__m), _M_owns(false)
442 : {
443 3413693 : lock();
444 3414970 : _M_owns = true;
445 3414970 : }
446 :
447 : unique_lock(mutex_type& __m, defer_lock_t) noexcept
448 : : _M_device(&__m), _M_owns(false)
449 : { }
450 :
451 : unique_lock(mutex_type& __m, try_to_lock_t)
452 : : _M_device(&__m), _M_owns(_M_device->try_lock())
453 : { }
454 :
455 : unique_lock(mutex_type& __m, adopt_lock_t)
456 : : _M_device(&__m), _M_owns(true)
457 : {
458 : // XXX calling thread owns mutex
459 : }
460 :
461 : template<typename _Clock, typename _Duration>
462 : unique_lock(mutex_type& __m,
463 : const chrono::time_point<_Clock, _Duration>& __atime)
464 : : _M_device(&__m), _M_owns(_M_device->try_lock_until(__atime))
465 : { }
466 :
467 : template<typename _Rep, typename _Period>
468 : unique_lock(mutex_type& __m,
469 : const chrono::duration<_Rep, _Period>& __rtime)
470 : : _M_device(&__m), _M_owns(_M_device->try_lock_for(__rtime))
471 : { }
472 :
473 3414629 : ~unique_lock()
474 : {
475 3414629 : if (_M_owns)
476 1956092 : unlock();
477 3414656 : }
478 :
479 : unique_lock(const unique_lock&) = delete;
480 : unique_lock& operator=(const unique_lock&) = delete;
481 :
482 : unique_lock(unique_lock&& __u) noexcept
483 : : _M_device(__u._M_device), _M_owns(__u._M_owns)
484 : {
485 : __u._M_device = 0;
486 : __u._M_owns = false;
487 : }
488 :
489 : unique_lock& operator=(unique_lock&& __u) noexcept
490 : {
491 : if(_M_owns)
492 : unlock();
493 :
494 : unique_lock(std::move(__u)).swap(*this);
495 :
496 : __u._M_device = 0;
497 : __u._M_owns = false;
498 :
499 : return *this;
500 : }
501 :
502 : void
503 3413198 : lock()
504 : {
505 3413198 : if (!_M_device)
506 0 : __throw_system_error(int(errc::operation_not_permitted));
507 3413198 : else if (_M_owns)
508 0 : __throw_system_error(int(errc::resource_deadlock_would_occur));
509 : else
510 : {
511 3413198 : _M_device->lock();
512 3414968 : _M_owns = true;
513 : }
514 3414968 : }
515 :
516 : bool
517 : try_lock()
518 : {
519 : if (!_M_device)
520 : __throw_system_error(int(errc::operation_not_permitted));
521 : else if (_M_owns)
522 : __throw_system_error(int(errc::resource_deadlock_would_occur));
523 : else
524 : {
525 : _M_owns = _M_device->try_lock();
526 : return _M_owns;
527 : }
528 : }
529 :
530 : template<typename _Clock, typename _Duration>
531 : bool
532 : try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
533 : {
534 : if (!_M_device)
535 : __throw_system_error(int(errc::operation_not_permitted));
536 : else if (_M_owns)
537 : __throw_system_error(int(errc::resource_deadlock_would_occur));
538 : else
539 : {
540 : _M_owns = _M_device->try_lock_until(__atime);
541 : return _M_owns;
542 : }
543 : }
544 :
545 : template<typename _Rep, typename _Period>
546 : bool
547 : try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
548 : {
549 : if (!_M_device)
550 : __throw_system_error(int(errc::operation_not_permitted));
551 : else if (_M_owns)
552 : __throw_system_error(int(errc::resource_deadlock_would_occur));
553 : else
554 : {
555 : _M_owns = _M_device->try_lock_for(__rtime);
556 : return _M_owns;
557 : }
558 : }
559 :
560 : void
561 3414657 : unlock()
562 : {
563 3414657 : if (!_M_owns)
564 0 : __throw_system_error(int(errc::operation_not_permitted));
565 3414657 : else if (_M_device)
566 : {
567 3414688 : _M_device->unlock();
568 3414732 : _M_owns = false;
569 : }
570 3414701 : }
571 :
572 : void
573 : swap(unique_lock& __u) noexcept
574 : {
575 : std::swap(_M_device, __u._M_device);
576 : std::swap(_M_owns, __u._M_owns);
577 : }
578 :
579 : mutex_type*
580 : release() noexcept
581 : {
582 : mutex_type* __ret = _M_device;
583 : _M_device = 0;
584 : _M_owns = false;
585 : return __ret;
586 : }
587 :
588 : bool
589 : owns_lock() const noexcept
590 : { return _M_owns; }
591 :
592 : explicit operator bool() const noexcept
593 : { return owns_lock(); }
594 :
595 : mutex_type*
596 : mutex() const noexcept
597 : { return _M_device; }
598 :
599 : private:
600 : mutex_type* _M_device;
601 : bool _M_owns; // XXX use atomic_bool
602 : };
603 :
604 : /// Partial specialization for unique_lock objects.
605 : template<typename _Mutex>
606 : inline void
607 : swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) noexcept
608 : { __x.swap(__y); }
609 :
610 : template<int _Idx>
611 : struct __unlock_impl
612 : {
613 : template<typename... _Lock>
614 : static void
615 : __do_unlock(tuple<_Lock&...>& __locks)
616 : {
617 : std::get<_Idx>(__locks).unlock();
618 : __unlock_impl<_Idx - 1>::__do_unlock(__locks);
619 : }
620 : };
621 :
622 : template<>
623 : struct __unlock_impl<-1>
624 : {
625 : template<typename... _Lock>
626 : static void
627 : __do_unlock(tuple<_Lock&...>&)
628 : { }
629 : };
630 :
631 : template<typename _Lock>
632 : unique_lock<_Lock>
633 : __try_to_lock(_Lock& __l)
634 : { return unique_lock<_Lock>(__l, try_to_lock); }
635 :
636 : template<int _Idx, bool _Continue = true>
637 : struct __try_lock_impl
638 : {
639 : template<typename... _Lock>
640 : static void
641 : __do_try_lock(tuple<_Lock&...>& __locks, int& __idx)
642 : {
643 : __idx = _Idx;
644 : auto __lock = __try_to_lock(std::get<_Idx>(__locks));
645 : if (__lock.owns_lock())
646 : {
647 : __try_lock_impl<_Idx + 1, _Idx + 2 < sizeof...(_Lock)>::
648 : __do_try_lock(__locks, __idx);
649 : if (__idx == -1)
650 : __lock.release();
651 : }
652 : }
653 : };
654 :
655 : template<int _Idx>
656 : struct __try_lock_impl<_Idx, false>
657 : {
658 : template<typename... _Lock>
659 : static void
660 : __do_try_lock(tuple<_Lock&...>& __locks, int& __idx)
661 : {
662 : __idx = _Idx;
663 : auto __lock = __try_to_lock(std::get<_Idx>(__locks));
664 : if (__lock.owns_lock())
665 : {
666 : __idx = -1;
667 : __lock.release();
668 : }
669 : }
670 : };
671 :
672 : /** @brief Generic try_lock.
673 : * @param __l1 Meets Mutex requirements (try_lock() may throw).
674 : * @param __l2 Meets Mutex requirements (try_lock() may throw).
675 : * @param __l3 Meets Mutex requirements (try_lock() may throw).
676 : * @return Returns -1 if all try_lock() calls return true. Otherwise returns
677 : * a 0-based index corresponding to the argument that returned false.
678 : * @post Either all arguments are locked, or none will be.
679 : *
680 : * Sequentially calls try_lock() on each argument.
681 : */
682 : template<typename _Lock1, typename _Lock2, typename... _Lock3>
683 : int
684 : try_lock(_Lock1& __l1, _Lock2& __l2, _Lock3&... __l3)
685 : {
686 : int __idx;
687 : auto __locks = std::tie(__l1, __l2, __l3...);
688 : __try
689 : { __try_lock_impl<0>::__do_try_lock(__locks, __idx); }
690 : __catch(...)
691 : { }
692 : return __idx;
693 : }
694 :
695 : /** @brief Generic lock.
696 : * @param __l1 Meets Mutex requirements (try_lock() may throw).
697 : * @param __l2 Meets Mutex requirements (try_lock() may throw).
698 : * @param __l3 Meets Mutex requirements (try_lock() may throw).
699 : * @throw An exception thrown by an argument's lock() or try_lock() member.
700 : * @post All arguments are locked.
701 : *
702 : * All arguments are locked via a sequence of calls to lock(), try_lock()
703 : * and unlock(). If the call exits via an exception any locks that were
704 : * obtained will be released.
705 : */
706 : template<typename _L1, typename _L2, typename ..._L3>
707 : void
708 : lock(_L1& __l1, _L2& __l2, _L3&... __l3)
709 : {
710 : while (true)
711 : {
712 : unique_lock<_L1> __first(__l1);
713 : int __idx;
714 : auto __locks = std::tie(__l2, __l3...);
715 : __try_lock_impl<0, sizeof...(_L3)>::__do_try_lock(__locks, __idx);
716 : if (__idx == -1)
717 : {
718 : __first.release();
719 : return;
720 : }
721 : }
722 : }
723 :
724 : #ifdef _GLIBCXX_HAS_GTHREADS
725 : /// once_flag
726 : struct once_flag
727 : {
728 : private:
729 : typedef __gthread_once_t __native_type;
730 : __native_type _M_once = __GTHREAD_ONCE_INIT;
731 :
732 : public:
733 : /// Constructor
734 : constexpr once_flag() noexcept = default;
735 :
736 : /// Deleted copy constructor
737 : once_flag(const once_flag&) = delete;
738 : /// Deleted assignment operator
739 : once_flag& operator=(const once_flag&) = delete;
740 :
741 : template<typename _Callable, typename... _Args>
742 : friend void
743 : call_once(once_flag& __once, _Callable&& __f, _Args&&... __args);
744 : };
745 :
746 : #ifdef _GLIBCXX_HAVE_TLS
747 : extern __thread void* __once_callable;
748 : extern __thread void (*__once_call)();
749 :
750 : template<typename _Callable>
751 : inline void
752 : __once_call_impl()
753 : {
754 : (*(_Callable*)__once_callable)();
755 : }
756 : #else
757 : extern function<void()> __once_functor;
758 :
759 : extern void
760 : __set_once_functor_lock_ptr(unique_lock<mutex>*);
761 :
762 : extern mutex&
763 : __get_once_mutex();
764 : #endif
765 :
766 : extern "C" void __once_proxy(void);
767 :
768 : /// call_once
769 : template<typename _Callable, typename... _Args>
770 : void
771 : call_once(once_flag& __once, _Callable&& __f, _Args&&... __args)
772 : {
773 : #ifdef _GLIBCXX_HAVE_TLS
774 : auto __bound_functor = std::__bind_simple(std::forward<_Callable>(__f),
775 : std::forward<_Args>(__args)...);
776 : __once_callable = &__bound_functor;
777 : __once_call = &__once_call_impl<decltype(__bound_functor)>;
778 : #else
779 : unique_lock<mutex> __functor_lock(__get_once_mutex());
780 : auto __callable = std::__bind_simple(std::forward<_Callable>(__f),
781 : std::forward<_Args>(__args)...);
782 : __once_functor = [&]() { __callable(); };
783 : __set_once_functor_lock_ptr(&__functor_lock);
784 : #endif
785 :
786 : int __e = __gthread_once(&(__once._M_once), &__once_proxy);
787 :
788 : #ifndef _GLIBCXX_HAVE_TLS
789 : if (__functor_lock)
790 : __set_once_functor_lock_ptr(0);
791 : #endif
792 :
793 : if (__e)
794 : __throw_system_error(__e);
795 : }
796 : #endif // _GLIBCXX_HAS_GTHREADS
797 :
798 : // @} group mutexes
799 : _GLIBCXX_END_NAMESPACE_VERSION
800 : } // namespace
801 : #endif // _GLIBCXX_USE_C99_STDINT_TR1
802 :
803 : #endif // C++11
804 :
805 : #endif // _GLIBCXX_MUTEX
|