Line data Source code
1 : // <mutex> -*- C++ -*-
2 :
3 : // Copyright (C) 2003-2018 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 : #if ! _GTHREAD_USE_MUTEX_TIMEDLOCK
45 : # include <condition_variable>
46 : # include <thread>
47 : #endif
48 : #ifndef _GLIBCXX_HAVE_TLS
49 : # include <bits/std_function.h>
50 : #endif
51 :
52 : #ifdef _GLIBCXX_USE_C99_STDINT_TR1
53 :
54 : namespace std _GLIBCXX_VISIBILITY(default)
55 : {
56 : _GLIBCXX_BEGIN_NAMESPACE_VERSION
57 :
58 : /**
59 : * @ingroup mutexes
60 : * @{
61 : */
62 :
63 : #ifdef _GLIBCXX_HAS_GTHREADS
64 :
65 : // Common base class for std::recursive_mutex and std::recursive_timed_mutex
66 : class __recursive_mutex_base
67 : {
68 : protected:
69 : typedef __gthread_recursive_mutex_t __native_type;
70 :
71 : __recursive_mutex_base(const __recursive_mutex_base&) = delete;
72 : __recursive_mutex_base& operator=(const __recursive_mutex_base&) = delete;
73 :
74 : #ifdef __GTHREAD_RECURSIVE_MUTEX_INIT
75 : __native_type _M_mutex = __GTHREAD_RECURSIVE_MUTEX_INIT;
76 :
77 : __recursive_mutex_base() = default;
78 : #else
79 : __native_type _M_mutex;
80 :
81 : __recursive_mutex_base()
82 : {
83 : // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
84 : __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
85 : }
86 :
87 : ~__recursive_mutex_base()
88 : { __gthread_recursive_mutex_destroy(&_M_mutex); }
89 : #endif
90 : };
91 :
92 : /// The standard recursive mutex type.
93 : class recursive_mutex : private __recursive_mutex_base
94 : {
95 : public:
96 : typedef __native_type* native_handle_type;
97 :
98 : recursive_mutex() = default;
99 : ~recursive_mutex() = default;
100 :
101 : recursive_mutex(const recursive_mutex&) = delete;
102 : recursive_mutex& operator=(const recursive_mutex&) = delete;
103 :
104 : void
105 : lock()
106 : {
107 : int __e = __gthread_recursive_mutex_lock(&_M_mutex);
108 :
109 : // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
110 : if (__e)
111 : __throw_system_error(__e);
112 : }
113 :
114 : bool
115 : try_lock() noexcept
116 : {
117 : // XXX EINVAL, EAGAIN, EBUSY
118 : return !__gthread_recursive_mutex_trylock(&_M_mutex);
119 : }
120 :
121 : void
122 : unlock()
123 : {
124 : // XXX EINVAL, EAGAIN, EBUSY
125 : __gthread_recursive_mutex_unlock(&_M_mutex);
126 : }
127 :
128 : native_handle_type
129 : native_handle() noexcept
130 : { return &_M_mutex; }
131 : };
132 :
133 : #if _GTHREAD_USE_MUTEX_TIMEDLOCK
134 : template<typename _Derived>
135 : class __timed_mutex_impl
136 : {
137 : protected:
138 : typedef chrono::high_resolution_clock __clock_t;
139 :
140 : template<typename _Rep, typename _Period>
141 : bool
142 : _M_try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
143 : {
144 : using chrono::steady_clock;
145 : auto __rt = chrono::duration_cast<steady_clock::duration>(__rtime);
146 : if (ratio_greater<steady_clock::period, _Period>())
147 : ++__rt;
148 : return _M_try_lock_until(steady_clock::now() + __rt);
149 : }
150 :
151 : template<typename _Duration>
152 : bool
153 : _M_try_lock_until(const chrono::time_point<__clock_t,
154 : _Duration>& __atime)
155 : {
156 : auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
157 : auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
158 :
159 : __gthread_time_t __ts = {
160 : static_cast<std::time_t>(__s.time_since_epoch().count()),
161 : static_cast<long>(__ns.count())
162 : };
163 :
164 : return static_cast<_Derived*>(this)->_M_timedlock(__ts);
165 : }
166 :
167 : template<typename _Clock, typename _Duration>
168 : bool
169 : _M_try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
170 : {
171 : auto __rtime = __atime - _Clock::now();
172 : return _M_try_lock_until(__clock_t::now() + __rtime);
173 : }
174 : };
175 :
176 : /// The standard timed mutex type.
177 : class timed_mutex
178 : : private __mutex_base, public __timed_mutex_impl<timed_mutex>
179 : {
180 : public:
181 : typedef __native_type* native_handle_type;
182 :
183 : timed_mutex() = default;
184 : ~timed_mutex() = default;
185 :
186 : timed_mutex(const timed_mutex&) = delete;
187 : timed_mutex& operator=(const timed_mutex&) = delete;
188 :
189 : void
190 : lock()
191 : {
192 : int __e = __gthread_mutex_lock(&_M_mutex);
193 :
194 : // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
195 : if (__e)
196 : __throw_system_error(__e);
197 : }
198 :
199 : bool
200 : try_lock() noexcept
201 : {
202 : // XXX EINVAL, EAGAIN, EBUSY
203 : return !__gthread_mutex_trylock(&_M_mutex);
204 : }
205 :
206 : template <class _Rep, class _Period>
207 : bool
208 : try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
209 : { return _M_try_lock_for(__rtime); }
210 :
211 : template <class _Clock, class _Duration>
212 : bool
213 : try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
214 : { return _M_try_lock_until(__atime); }
215 :
216 : void
217 : unlock()
218 : {
219 : // XXX EINVAL, EAGAIN, EBUSY
220 : __gthread_mutex_unlock(&_M_mutex);
221 : }
222 :
223 : native_handle_type
224 : native_handle() noexcept
225 : { return &_M_mutex; }
226 :
227 : private:
228 : friend class __timed_mutex_impl<timed_mutex>;
229 :
230 : bool
231 : _M_timedlock(const __gthread_time_t& __ts)
232 : { return !__gthread_mutex_timedlock(&_M_mutex, &__ts); }
233 : };
234 :
235 : /// recursive_timed_mutex
236 : class recursive_timed_mutex
237 : : private __recursive_mutex_base,
238 : public __timed_mutex_impl<recursive_timed_mutex>
239 : {
240 : public:
241 : typedef __native_type* native_handle_type;
242 :
243 : recursive_timed_mutex() = default;
244 : ~recursive_timed_mutex() = default;
245 :
246 : recursive_timed_mutex(const recursive_timed_mutex&) = delete;
247 : recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
248 :
249 : void
250 : lock()
251 : {
252 : int __e = __gthread_recursive_mutex_lock(&_M_mutex);
253 :
254 : // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
255 : if (__e)
256 : __throw_system_error(__e);
257 : }
258 :
259 : bool
260 : try_lock() noexcept
261 : {
262 : // XXX EINVAL, EAGAIN, EBUSY
263 : return !__gthread_recursive_mutex_trylock(&_M_mutex);
264 : }
265 :
266 : template <class _Rep, class _Period>
267 : bool
268 : try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
269 : { return _M_try_lock_for(__rtime); }
270 :
271 : template <class _Clock, class _Duration>
272 : bool
273 : try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
274 : { return _M_try_lock_until(__atime); }
275 :
276 : void
277 : unlock()
278 : {
279 : // XXX EINVAL, EAGAIN, EBUSY
280 : __gthread_recursive_mutex_unlock(&_M_mutex);
281 : }
282 :
283 : native_handle_type
284 : native_handle() noexcept
285 : { return &_M_mutex; }
286 :
287 : private:
288 : friend class __timed_mutex_impl<recursive_timed_mutex>;
289 :
290 : bool
291 : _M_timedlock(const __gthread_time_t& __ts)
292 : { return !__gthread_recursive_mutex_timedlock(&_M_mutex, &__ts); }
293 : };
294 :
295 : #else // !_GTHREAD_USE_MUTEX_TIMEDLOCK
296 :
297 : /// timed_mutex
298 : class timed_mutex
299 : {
300 : mutex _M_mut;
301 : condition_variable _M_cv;
302 : bool _M_locked = false;
303 :
304 : public:
305 :
306 : timed_mutex() = default;
307 : ~timed_mutex() { __glibcxx_assert( !_M_locked ); }
308 :
309 : timed_mutex(const timed_mutex&) = delete;
310 : timed_mutex& operator=(const timed_mutex&) = delete;
311 :
312 : void
313 : lock()
314 : {
315 : unique_lock<mutex> __lk(_M_mut);
316 : _M_cv.wait(__lk, [&]{ return !_M_locked; });
317 : _M_locked = true;
318 : }
319 :
320 : bool
321 : try_lock()
322 : {
323 : lock_guard<mutex> __lk(_M_mut);
324 : if (_M_locked)
325 : return false;
326 : _M_locked = true;
327 : return true;
328 : }
329 :
330 : template<typename _Rep, typename _Period>
331 : bool
332 : try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
333 : {
334 : unique_lock<mutex> __lk(_M_mut);
335 : if (!_M_cv.wait_for(__lk, __rtime, [&]{ return !_M_locked; }))
336 : return false;
337 : _M_locked = true;
338 : return true;
339 : }
340 :
341 : template<typename _Clock, typename _Duration>
342 : bool
343 : try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
344 : {
345 : unique_lock<mutex> __lk(_M_mut);
346 : if (!_M_cv.wait_until(__lk, __atime, [&]{ return !_M_locked; }))
347 : return false;
348 : _M_locked = true;
349 : return true;
350 : }
351 :
352 : void
353 : unlock()
354 : {
355 : lock_guard<mutex> __lk(_M_mut);
356 : __glibcxx_assert( _M_locked );
357 : _M_locked = false;
358 : _M_cv.notify_one();
359 : }
360 : };
361 :
362 : /// recursive_timed_mutex
363 : class recursive_timed_mutex
364 : {
365 : mutex _M_mut;
366 : condition_variable _M_cv;
367 : thread::id _M_owner;
368 : unsigned _M_count = 0;
369 :
370 : // Predicate type that tests whether the current thread can lock a mutex.
371 : struct _Can_lock
372 : {
373 : // Returns true if the mutex is unlocked or is locked by _M_caller.
374 : bool
375 : operator()() const noexcept
376 : { return _M_mx->_M_count == 0 || _M_mx->_M_owner == _M_caller; }
377 :
378 : const recursive_timed_mutex* _M_mx;
379 : thread::id _M_caller;
380 : };
381 :
382 : public:
383 :
384 : recursive_timed_mutex() = default;
385 : ~recursive_timed_mutex() { __glibcxx_assert( _M_count == 0 ); }
386 :
387 : recursive_timed_mutex(const recursive_timed_mutex&) = delete;
388 : recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
389 :
390 : void
391 : lock()
392 : {
393 : auto __id = this_thread::get_id();
394 : _Can_lock __can_lock{this, __id};
395 : unique_lock<mutex> __lk(_M_mut);
396 : _M_cv.wait(__lk, __can_lock);
397 : if (_M_count == -1u)
398 : __throw_system_error(EAGAIN); // [thread.timedmutex.recursive]/3
399 : _M_owner = __id;
400 : ++_M_count;
401 : }
402 :
403 : bool
404 : try_lock()
405 : {
406 : auto __id = this_thread::get_id();
407 : _Can_lock __can_lock{this, __id};
408 : lock_guard<mutex> __lk(_M_mut);
409 : if (!__can_lock())
410 : return false;
411 : if (_M_count == -1u)
412 : return false;
413 : _M_owner = __id;
414 : ++_M_count;
415 : return true;
416 : }
417 :
418 : template<typename _Rep, typename _Period>
419 : bool
420 : try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
421 : {
422 : auto __id = this_thread::get_id();
423 : _Can_lock __can_lock{this, __id};
424 : unique_lock<mutex> __lk(_M_mut);
425 : if (!_M_cv.wait_for(__lk, __rtime, __can_lock))
426 : return false;
427 : if (_M_count == -1u)
428 : return false;
429 : _M_owner = __id;
430 : ++_M_count;
431 : return true;
432 : }
433 :
434 : template<typename _Clock, typename _Duration>
435 : bool
436 : try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
437 : {
438 : auto __id = this_thread::get_id();
439 : _Can_lock __can_lock{this, __id};
440 : unique_lock<mutex> __lk(_M_mut);
441 : if (!_M_cv.wait_until(__lk, __atime, __can_lock))
442 : return false;
443 : if (_M_count == -1u)
444 : return false;
445 : _M_owner = __id;
446 : ++_M_count;
447 : return true;
448 : }
449 :
450 : void
451 : unlock()
452 : {
453 : lock_guard<mutex> __lk(_M_mut);
454 : __glibcxx_assert( _M_owner == this_thread::get_id() );
455 : __glibcxx_assert( _M_count > 0 );
456 : if (--_M_count == 0)
457 : {
458 : _M_owner = {};
459 : _M_cv.notify_one();
460 : }
461 : }
462 : };
463 :
464 : #endif
465 : #endif // _GLIBCXX_HAS_GTHREADS
466 :
467 : template<typename _Lock>
468 : inline unique_lock<_Lock>
469 : __try_to_lock(_Lock& __l)
470 : { return unique_lock<_Lock>{__l, try_to_lock}; }
471 :
472 : template<int _Idx, bool _Continue = true>
473 : struct __try_lock_impl
474 : {
475 : template<typename... _Lock>
476 : static void
477 : __do_try_lock(tuple<_Lock&...>& __locks, int& __idx)
478 : {
479 : __idx = _Idx;
480 : auto __lock = std::__try_to_lock(std::get<_Idx>(__locks));
481 : if (__lock.owns_lock())
482 : {
483 : constexpr bool __cont = _Idx + 2 < sizeof...(_Lock);
484 : using __try_locker = __try_lock_impl<_Idx + 1, __cont>;
485 : __try_locker::__do_try_lock(__locks, __idx);
486 : if (__idx == -1)
487 : __lock.release();
488 : }
489 : }
490 : };
491 :
492 : template<int _Idx>
493 : struct __try_lock_impl<_Idx, false>
494 : {
495 : template<typename... _Lock>
496 : static void
497 : __do_try_lock(tuple<_Lock&...>& __locks, int& __idx)
498 : {
499 : __idx = _Idx;
500 : auto __lock = std::__try_to_lock(std::get<_Idx>(__locks));
501 : if (__lock.owns_lock())
502 : {
503 : __idx = -1;
504 : __lock.release();
505 : }
506 : }
507 : };
508 :
509 : /** @brief Generic try_lock.
510 : * @param __l1 Meets Lockable requirements (try_lock() may throw).
511 : * @param __l2 Meets Lockable requirements (try_lock() may throw).
512 : * @param __l3 Meets Lockable requirements (try_lock() may throw).
513 : * @return Returns -1 if all try_lock() calls return true. Otherwise returns
514 : * a 0-based index corresponding to the argument that returned false.
515 : * @post Either all arguments are locked, or none will be.
516 : *
517 : * Sequentially calls try_lock() on each argument.
518 : */
519 : template<typename _Lock1, typename _Lock2, typename... _Lock3>
520 : int
521 : try_lock(_Lock1& __l1, _Lock2& __l2, _Lock3&... __l3)
522 : {
523 : int __idx;
524 : auto __locks = std::tie(__l1, __l2, __l3...);
525 : __try_lock_impl<0>::__do_try_lock(__locks, __idx);
526 : return __idx;
527 : }
528 :
529 : /** @brief Generic lock.
530 : * @param __l1 Meets Lockable requirements (try_lock() may throw).
531 : * @param __l2 Meets Lockable requirements (try_lock() may throw).
532 : * @param __l3 Meets Lockable requirements (try_lock() may throw).
533 : * @throw An exception thrown by an argument's lock() or try_lock() member.
534 : * @post All arguments are locked.
535 : *
536 : * All arguments are locked via a sequence of calls to lock(), try_lock()
537 : * and unlock(). If the call exits via an exception any locks that were
538 : * obtained will be released.
539 : */
540 : template<typename _L1, typename _L2, typename... _L3>
541 : void
542 : lock(_L1& __l1, _L2& __l2, _L3&... __l3)
543 : {
544 : while (true)
545 : {
546 : using __try_locker = __try_lock_impl<0, sizeof...(_L3) != 0>;
547 : unique_lock<_L1> __first(__l1);
548 : int __idx;
549 : auto __locks = std::tie(__l2, __l3...);
550 : __try_locker::__do_try_lock(__locks, __idx);
551 : if (__idx == -1)
552 : {
553 : __first.release();
554 : return;
555 : }
556 : }
557 : }
558 :
559 : #if __cplusplus >= 201703L
560 : #define __cpp_lib_scoped_lock 201703
561 : /** @brief A scoped lock type for multiple lockable objects.
562 : *
563 : * A scoped_lock controls mutex ownership within a scope, releasing
564 : * ownership in the destructor.
565 : */
566 : template<typename... _MutexTypes>
567 : class scoped_lock
568 : {
569 : public:
570 : explicit scoped_lock(_MutexTypes&... __m) : _M_devices(std::tie(__m...))
571 : { std::lock(__m...); }
572 :
573 : explicit scoped_lock(adopt_lock_t, _MutexTypes&... __m) noexcept
574 : : _M_devices(std::tie(__m...))
575 : { } // calling thread owns mutex
576 :
577 : ~scoped_lock()
578 : {
579 : std::apply([](_MutexTypes&... __m) {
580 : char __i[] __attribute__((__unused__)) = { (__m.unlock(), 0)... };
581 : }, _M_devices);
582 : }
583 :
584 : scoped_lock(const scoped_lock&) = delete;
585 : scoped_lock& operator=(const scoped_lock&) = delete;
586 :
587 : private:
588 : tuple<_MutexTypes&...> _M_devices;
589 : };
590 :
591 : template<>
592 : class scoped_lock<>
593 : {
594 : public:
595 : explicit scoped_lock() = default;
596 : explicit scoped_lock(adopt_lock_t) noexcept { }
597 : ~scoped_lock() = default;
598 :
599 : scoped_lock(const scoped_lock&) = delete;
600 : scoped_lock& operator=(const scoped_lock&) = delete;
601 : };
602 :
603 : template<typename _Mutex>
604 : class scoped_lock<_Mutex>
605 : {
606 : public:
607 : using mutex_type = _Mutex;
608 :
609 : explicit scoped_lock(mutex_type& __m) : _M_device(__m)
610 : { _M_device.lock(); }
611 :
612 : explicit scoped_lock(adopt_lock_t, mutex_type& __m) noexcept
613 : : _M_device(__m)
614 : { } // calling thread owns mutex
615 :
616 : ~scoped_lock()
617 : { _M_device.unlock(); }
618 :
619 : scoped_lock(const scoped_lock&) = delete;
620 : scoped_lock& operator=(const scoped_lock&) = delete;
621 :
622 : private:
623 : mutex_type& _M_device;
624 : };
625 : #endif // C++17
626 :
627 : #ifdef _GLIBCXX_HAS_GTHREADS
628 : /// once_flag
629 : struct once_flag
630 : {
631 : private:
632 : typedef __gthread_once_t __native_type;
633 : __native_type _M_once = __GTHREAD_ONCE_INIT;
634 :
635 : public:
636 : /// Constructor
637 83 : constexpr once_flag() noexcept = default;
638 :
639 : /// Deleted copy constructor
640 : once_flag(const once_flag&) = delete;
641 : /// Deleted assignment operator
642 : once_flag& operator=(const once_flag&) = delete;
643 :
644 : template<typename _Callable, typename... _Args>
645 : friend void
646 : call_once(once_flag& __once, _Callable&& __f, _Args&&... __args);
647 : };
648 :
649 : #ifdef _GLIBCXX_HAVE_TLS
650 : extern __thread void* __once_callable;
651 : extern __thread void (*__once_call)();
652 : #else
653 : extern function<void()> __once_functor;
654 :
655 : extern void
656 : __set_once_functor_lock_ptr(unique_lock<mutex>*);
657 :
658 : extern mutex&
659 : __get_once_mutex();
660 : #endif
661 :
662 : extern "C" void __once_proxy(void);
663 :
664 : /// call_once
665 : template<typename _Callable, typename... _Args>
666 : void
667 83 : call_once(once_flag& __once, _Callable&& __f, _Args&&... __args)
668 : {
669 : // _GLIBCXX_RESOLVE_LIB_DEFECTS
670 : // 2442. call_once() shouldn't DECAY_COPY()
671 249 : auto __callable = [&] {
672 83 : std::__invoke(std::forward<_Callable>(__f),
673 83 : std::forward<_Args>(__args)...);
674 : };
675 : #ifdef _GLIBCXX_HAVE_TLS
676 83 : __once_callable = std::__addressof(__callable);
677 166 : __once_call = []{ (*(decltype(__callable)*)__once_callable)(); };
678 : #else
679 : unique_lock<mutex> __functor_lock(__get_once_mutex());
680 : __once_functor = __callable;
681 : __set_once_functor_lock_ptr(&__functor_lock);
682 : #endif
683 :
684 83 : int __e = __gthread_once(&__once._M_once, &__once_proxy);
685 :
686 : #ifndef _GLIBCXX_HAVE_TLS
687 : if (__functor_lock)
688 : __set_once_functor_lock_ptr(0);
689 : #endif
690 :
691 : #ifdef __clang_analyzer__
692 : // PR libstdc++/82481
693 : __once_callable = nullptr;
694 : __once_call = nullptr;
695 : #endif
696 :
697 83 : if (__e)
698 0 : __throw_system_error(__e);
699 83 : }
700 : #endif // _GLIBCXX_HAS_GTHREADS
701 :
702 : // @} group mutexes
703 : _GLIBCXX_END_NAMESPACE_VERSION
704 : } // namespace
705 : #endif // _GLIBCXX_USE_C99_STDINT_TR1
706 :
707 : #endif // C++11
708 :
709 : #endif // _GLIBCXX_MUTEX
|