3 // Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
4 // Free Software Foundation, Inc.
6 // This file is part of the GNU ISO C++ Library. This library is free
7 // software; you can redistribute it and/or modify it under the
8 // terms of the GNU General Public License as published by the
9 // Free Software Foundation; either version 2, or (at your option)
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this library; see the file COPYING. If not, write to
19 // the Free Software Foundation, 51 Franklin Street, Fifth Floor,
20 // Boston, MA 02110-1301, USA.
22 // As a special exception, you may use this file as part of a free software
23 // library without restriction. Specifically, if other files instantiate
24 // templates or use macros or inline functions from this file, or you compile
25 // this file and link it with other files to produce an executable, this
26 // file does not by itself cause the resulting executable to be covered by
27 // the GNU General Public License. This exception does not however
28 // invalidate any other reasons why the executable file might be covered by
29 // the GNU General Public License.
32 * This is a Standard C++ Library header.
35 #ifndef _GLIBCXX_MUTEX
36 #define _GLIBCXX_MUTEX 1
38 #pragma GCC system_header
40 #ifndef __GXX_EXPERIMENTAL_CXX0X__
41 # include <c++0x_warning.h>
48 #include <type_traits>
50 #include <system_error>
51 #include <bits/functexcept.h>
52 #include <bits/gthr.h>
53 #include <bits/move.h> // for std::swap
55 #if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)
62 typedef __gthread_mutex_t __native_type;
63 __native_type _M_mutex;
66 typedef __native_type* native_handle_type;
70 // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
71 #ifdef __GTHREAD_MUTEX_INIT
72 __native_type __tmp = __GTHREAD_MUTEX_INIT;
75 __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex);
79 mutex(const mutex&) = delete;
80 mutex& operator=(const mutex&) = delete;
85 int __e = __gthread_mutex_lock(&_M_mutex);
87 // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
89 __throw_system_error(__e);
95 // XXX EINVAL, EAGAIN, EBUSY
96 return !__gthread_mutex_trylock(&_M_mutex);
102 // XXX EINVAL, EAGAIN, EPERM
103 __gthread_mutex_unlock(&_M_mutex);
108 { return &_M_mutex; }
112 class recursive_mutex
114 typedef __gthread_recursive_mutex_t __native_type;
115 __native_type _M_mutex;
118 typedef __native_type* native_handle_type;
122 // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
123 #ifdef __GTHREAD_RECURSIVE_MUTEX_INIT
124 __native_type __tmp = __GTHREAD_RECURSIVE_MUTEX_INIT;
127 __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
131 recursive_mutex(const recursive_mutex&) = delete;
132 recursive_mutex& operator=(const recursive_mutex&) = delete;
137 int __e = __gthread_recursive_mutex_lock(&_M_mutex);
139 // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
141 __throw_system_error(__e);
147 // XXX EINVAL, EAGAIN, EBUSY
148 return !__gthread_recursive_mutex_trylock(&_M_mutex);
154 // XXX EINVAL, EAGAIN, EBUSY
155 __gthread_recursive_mutex_unlock(&_M_mutex);
160 { return &_M_mutex; }
166 typedef __gthread_mutex_t __native_type;
168 #ifdef _GLIBCXX_USE_CLOCK_MONOTONIC
169 typedef chrono::monotonic_clock __clock_t;
171 typedef chrono::high_resolution_clock __clock_t;
174 __native_type _M_mutex;
177 typedef __native_type* native_handle_type;
181 #ifdef __GTHREAD_MUTEX_INIT
182 __native_type __tmp = __GTHREAD_MUTEX_INIT;
185 __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex);
189 timed_mutex(const timed_mutex&) = delete;
190 timed_mutex& operator=(const timed_mutex&) = delete;
195 int __e = __gthread_mutex_lock(&_M_mutex);
197 // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
199 __throw_system_error(__e);
205 // XXX EINVAL, EAGAIN, EBUSY
206 return !__gthread_mutex_trylock(&_M_mutex);
209 template <class _Rep, class _Period>
211 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
212 { return __try_lock_for_impl(__rtime); }
214 template <class _Clock, class _Duration>
216 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
218 chrono::time_point<_Clock, chrono::seconds> __s =
219 chrono::time_point_cast<chrono::seconds>(__atime);
221 chrono::nanoseconds __ns =
222 chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
224 __gthread_time_t __ts = {
225 static_cast<std::time_t>(__s.time_since_epoch().count()),
226 static_cast<long>(__ns.count())
229 return !__gthread_mutex_timedlock(&_M_mutex, &__ts);
235 // XXX EINVAL, EAGAIN, EBUSY
236 __gthread_mutex_unlock(&_M_mutex);
241 { return &_M_mutex; }
244 template<typename _Rep, typename _Period>
246 ratio_less_equal<__clock_t::period, _Period>::value, bool>::type
247 __try_lock_for_impl(const chrono::duration<_Rep, _Period>& __rtime)
249 __clock_t::time_point __atime = __clock_t::now()
250 + chrono::duration_cast<__clock_t::duration>(__rtime);
252 return try_lock_until(__atime);
255 template <typename _Rep, typename _Period>
257 !ratio_less_equal<__clock_t::period, _Period>::value, bool>::type
258 __try_lock_for_impl(const chrono::duration<_Rep, _Period>& __rtime)
260 __clock_t::time_point __atime = __clock_t::now()
261 + ++chrono::duration_cast<__clock_t::duration>(__rtime);
263 return try_lock_until(__atime);
267 /// recursive_timed_mutex
268 class recursive_timed_mutex
270 typedef __gthread_recursive_mutex_t __native_type;
272 #ifdef _GLIBCXX_USE_CLOCK_MONOTONIC
273 typedef chrono::monotonic_clock __clock_t;
275 typedef chrono::high_resolution_clock __clock_t;
278 __native_type _M_mutex;
281 typedef __native_type* native_handle_type;
283 recursive_timed_mutex()
285 // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
286 #ifdef __GTHREAD_RECURSIVE_MUTEX_INIT
287 __native_type __tmp = __GTHREAD_RECURSIVE_MUTEX_INIT;
290 __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
294 recursive_timed_mutex(const recursive_timed_mutex&) = delete;
295 recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
300 int __e = __gthread_recursive_mutex_lock(&_M_mutex);
302 // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
304 __throw_system_error(__e);
310 // XXX EINVAL, EAGAIN, EBUSY
311 return !__gthread_recursive_mutex_trylock(&_M_mutex);
314 template <class _Rep, class _Period>
316 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
317 { return __try_lock_for_impl(__rtime); }
319 template <class _Clock, class _Duration>
321 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
323 chrono::time_point<_Clock, chrono::seconds> __s =
324 chrono::time_point_cast<chrono::seconds>(__atime);
326 chrono::nanoseconds __ns =
327 chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
329 __gthread_time_t __ts = {
330 static_cast<std::time_t>(__s.time_since_epoch().count()),
331 static_cast<long>(__ns.count())
334 return !__gthread_recursive_mutex_timedlock(&_M_mutex, &__ts);
340 // XXX EINVAL, EAGAIN, EBUSY
341 __gthread_recursive_mutex_unlock(&_M_mutex);
346 { return &_M_mutex; }
349 template<typename _Rep, typename _Period>
351 ratio_less_equal<__clock_t::period, _Period>::value, bool>::type
352 __try_lock_for_impl(const chrono::duration<_Rep, _Period>& __rtime)
354 __clock_t::time_point __atime = __clock_t::now()
355 + chrono::duration_cast<__clock_t::duration>(__rtime);
357 return try_lock_until(__atime);
360 template <typename _Rep, typename _Period>
362 !ratio_less_equal<__clock_t::period, _Period>::value, bool>::type
363 __try_lock_for_impl(const chrono::duration<_Rep, _Period>& __rtime)
365 __clock_t::time_point __atime = __clock_t::now()
366 + ++chrono::duration_cast<__clock_t::duration>(__rtime);
368 return try_lock_until(__atime);
372 /// Do not acquire ownership of the mutex.
373 struct defer_lock_t { };
375 /// Try to acquire ownership of the mutex without blocking.
376 struct try_to_lock_t { };
378 /// Assume the calling thread has already obtained mutex ownership
380 struct adopt_lock_t { };
382 extern const defer_lock_t defer_lock;
383 extern const try_to_lock_t try_to_lock;
384 extern const adopt_lock_t adopt_lock;
386 /// Thrown to indicate errors with lock operations.
387 class lock_error : public exception
391 what() const throw();
394 /// @brief Scoped lock idiom.
395 // Acquire the mutex here with a constructor call, then release with
396 // the destructor call in accordance with RAII style.
397 template<typename _Mutex>
401 typedef _Mutex mutex_type;
403 explicit lock_guard(mutex_type& __m) : _M_device(__m)
404 { _M_device.lock(); }
406 lock_guard(mutex_type& __m, adopt_lock_t __a) : _M_device(__m)
407 { _M_device.lock(); }
410 { _M_device.unlock(); }
412 lock_guard(const lock_guard&) = delete;
413 lock_guard& operator=(const lock_guard&) = delete;
416 mutex_type& _M_device;
420 template<typename _Mutex>
424 typedef _Mutex mutex_type;
427 : _M_device(0), _M_owns(false)
430 explicit unique_lock(mutex_type& __m)
431 : _M_device(&__m), _M_owns(false)
437 unique_lock(mutex_type& __m, defer_lock_t)
438 : _M_device(&__m), _M_owns(false)
441 unique_lock(mutex_type& __m, try_to_lock_t)
442 : _M_device(&__m), _M_owns(_M_device->try_lock())
445 unique_lock(mutex_type& __m, adopt_lock_t)
446 : _M_device(&__m), _M_owns(true)
448 // XXX calling thread owns mutex
451 template<typename _Clock, typename _Duration>
452 unique_lock(mutex_type& __m,
453 const chrono::time_point<_Clock, _Duration>& __atime)
454 : _M_device(&__m), _M_owns(_M_device->try_lock_until(__atime))
457 template<typename _Rep, typename _Period>
458 unique_lock(mutex_type& __m,
459 const chrono::duration<_Rep, _Period>& __rtime)
460 : _M_device(&__m), _M_owns(_M_device->try_lock_for(__rtime))
469 unique_lock(const unique_lock&) = delete;
470 unique_lock& operator=(const unique_lock&) = delete;
472 unique_lock(unique_lock&& __u)
473 : _M_device(__u._M_device), _M_owns(__u._M_owns)
479 unique_lock& operator=(unique_lock&& __u)
484 unique_lock(std::move(__u)).swap(*this);
496 __throw_system_error(int(errc::operation_not_permitted));
498 __throw_system_error(int(errc::resource_deadlock_would_occur));
510 __throw_system_error(int(errc::operation_not_permitted));
512 __throw_system_error(int(errc::resource_deadlock_would_occur));
515 _M_owns = _M_device->try_lock();
520 template<typename _Clock, typename _Duration>
522 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
525 __throw_system_error(int(errc::operation_not_permitted));
527 __throw_system_error(int(errc::resource_deadlock_would_occur));
530 _M_owns = _M_device->try_lock_until(__atime);
535 template<typename _Rep, typename _Period>
537 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
540 __throw_system_error(int(errc::operation_not_permitted));
542 __throw_system_error(int(errc::resource_deadlock_would_occur));
545 _M_owns = _M_device->try_lock_for(__rtime);
554 __throw_system_error(int(errc::operation_not_permitted));
563 swap(unique_lock&& __u)
565 std::swap(_M_device, __u._M_device);
566 std::swap(_M_owns, __u._M_owns);
572 mutex_type* __ret = _M_device;
582 /* explicit */ operator bool () const
583 { return owns_lock(); }
587 { return _M_device; }
590 mutex_type* _M_device;
591 bool _M_owns; // XXX use atomic_bool
594 template<typename _Mutex>
596 swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y)
599 template<typename _Mutex>
601 swap(unique_lock<_Mutex>&& __x, unique_lock<_Mutex>& __y)
604 template<typename _Mutex>
606 swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>&& __y)
612 template<typename... _Lock>
614 __do_unlock(tuple<_Lock&...>& __locks)
616 std::get<_Idx>(__locks).unlock();
617 __unlock_impl<_Idx - 1>::__do_unlock(__locks);
622 struct __unlock_impl<-1>
624 template<typename... _Lock>
626 __do_unlock(tuple<_Lock&...>&)
630 template<int _Idx, bool _Continue = true>
631 struct __try_lock_impl
633 template<typename... _Lock>
635 __do_try_lock(tuple<_Lock&...>& __locks)
637 if(std::get<_Idx>(__locks).try_lock())
639 return __try_lock_impl<_Idx + 1,
640 _Idx + 2 < sizeof...(_Lock)>::__do_try_lock(__locks);
644 __unlock_impl<_Idx>::__do_unlock(__locks);
651 struct __try_lock_impl<_Idx, false>
653 template<typename... _Lock>
655 __do_try_lock(tuple<_Lock&...>& __locks)
657 if(std::get<_Idx>(__locks).try_lock())
661 __unlock_impl<_Idx>::__do_unlock(__locks);
667 /** @brief Generic try_lock.
668 * @param __l1 Meets Mutex requirements (try_lock() may throw).
669 * @param __l2 Meets Mutex requirements (try_lock() may throw).
670 * @param __l3 Meets Mutex requirements (try_lock() may throw).
671 * @return Returns -1 if all try_lock() calls return true. Otherwise returns
672 * a 0-based index corresponding to the argument that returned false.
673 * @post Either all arguments are locked, or none will be.
675 * Sequentially calls try_lock() on each argument.
677 template<typename _Lock1, typename _Lock2, typename... _Lock3>
679 try_lock(_Lock1& __l1, _Lock2& __l2, _Lock3&... __l3)
681 tuple<_Lock1&, _Lock2&, _Lock3&...> __locks(__l1, __l2, __l3...);
682 return __try_lock_impl<0>::__do_try_lock(__locks);
685 template<typename _L1, typename _L2, typename ..._L3>
687 lock(_L1&, _L2&, _L3&...);
693 typedef __gthread_once_t __native_type;
694 __native_type _M_once;
699 __native_type __tmp = __GTHREAD_ONCE_INIT;
703 once_flag(const once_flag&) = delete;
704 once_flag& operator=(const once_flag&) = delete;
706 template<typename _Callable, typename... _Args>
708 call_once(once_flag& __once, _Callable __f, _Args&&... __args);
711 #ifdef _GLIBCXX_HAVE_TLS
712 extern __thread void* __once_callable;
713 extern __thread void (*__once_call)();
715 template<typename _Callable>
719 (*(_Callable*)__once_callable)();
722 extern function<void()> __once_functor;
724 extern unique_lock<mutex>&
725 __get_once_functor_lock();
728 extern "C" void __once_proxy();
730 template<typename _Callable, typename... _Args>
732 call_once(once_flag& __once, _Callable __f, _Args&&... __args)
734 #ifdef _GLIBCXX_HAVE_TLS
735 auto __bound_functor = bind(__f, __args...);
736 __once_callable = &__bound_functor;
737 __once_call = &__once_call_impl<decltype(__bound_functor)>;
739 unique_lock<mutex>& __functor_lock = __get_once_functor_lock();
740 __functor_lock.lock();
741 __once_functor = bind(__f, __args...);
744 int __e = __gthread_once(&(__once._M_once), &__once_proxy);
746 #ifndef _GLIBCXX_HAVE_TLS
748 __functor_lock.unlock();
752 __throw_system_error(__e);
756 #endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1
758 #endif // __GXX_EXPERIMENTAL_CXX0X__
760 #endif // _GLIBCXX_MUTEX