3 // Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008
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)
63 typedef __gthread_mutex_t* native_handle_type;
67 // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
68 #ifdef __GTHREAD_MUTEX_INIT
69 __gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT;
72 __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex);
76 mutex(const mutex&) = delete;
77 mutex& operator=(const mutex&) = delete;
82 int __e = __gthread_mutex_lock(&_M_mutex);
84 // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
86 __throw_system_error(__e);
92 // XXX EINVAL, EAGAIN, EBUSY
93 return !__gthread_mutex_trylock(&_M_mutex);
99 // XXX EINVAL, EAGAIN, EPERM
100 __gthread_mutex_unlock(&_M_mutex);
105 { return &_M_mutex; }
108 __gthread_mutex_t _M_mutex;
112 class recursive_mutex
115 typedef __gthread_recursive_mutex_t* native_handle_type;
119 // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
120 #ifdef __GTHREAD_RECURSIVE_MUTEX_INIT
121 __gthread_recursive_mutex_t __tmp = __GTHREAD_RECURSIVE_MUTEX_INIT;
124 __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
128 recursive_mutex(const recursive_mutex&) = delete;
129 recursive_mutex& operator=(const recursive_mutex&) = delete;
134 int __e = __gthread_recursive_mutex_lock(&_M_mutex);
136 // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
138 __throw_system_error(__e);
144 // XXX EINVAL, EAGAIN, EBUSY
145 return !__gthread_recursive_mutex_trylock(&_M_mutex);
151 // XXX EINVAL, EAGAIN, EBUSY
152 __gthread_recursive_mutex_unlock(&_M_mutex);
157 { return &_M_mutex; }
160 __gthread_recursive_mutex_t _M_mutex;
167 typedef __gthread_mutex_t* native_handle_type;
171 #ifdef __GTHREAD_MUTEX_INIT
172 __gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT;
175 __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex);
179 timed_mutex(const timed_mutex&) = delete;
180 timed_mutex& operator=(const timed_mutex&) = delete;
185 int __e = __gthread_mutex_lock(&_M_mutex);
187 // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
189 __throw_system_error(__e);
195 // XXX EINVAL, EAGAIN, EBUSY
196 return !__gthread_mutex_trylock(&_M_mutex);
199 template <class _Rep, class _Period>
201 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
202 { return __try_lock_for_impl(__rtime); }
204 template <class _Clock, class _Duration>
206 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
208 chrono::time_point<_Clock, chrono::seconds> __s =
209 chrono::time_point_cast<chrono::seconds>(__atime);
211 chrono::nanoseconds __ns =
212 chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
214 __gthread_time_t __ts = {
215 static_cast<std::time_t>(__s.time_since_epoch().count()),
216 static_cast<long>(__ns.count())
219 return !__gthread_mutex_timedlock(&_M_mutex, &__ts);
225 // XXX EINVAL, EAGAIN, EBUSY
226 __gthread_mutex_unlock(&_M_mutex);
231 { return &_M_mutex; }
234 __gthread_mutex_t _M_mutex;
236 #ifdef _GLIBCXX_USE_CLOCK_MONOTONIC
237 typedef chrono::monotonic_clock __clock_t;
239 typedef chrono::high_resolution_clock __clock_t;
242 template<typename _Rep, typename _Period>
244 ratio_less_equal<__clock_t::period, _Period>::value, bool>::type
245 __try_lock_for_impl(const chrono::duration<_Rep, _Period>& __rtime)
247 __clock_t::time_point __atime = __clock_t::now()
248 + chrono::duration_cast<__clock_t::duration>(__rtime);
250 return try_lock_until(__atime);
253 template <typename _Rep, typename _Period>
255 !ratio_less_equal<__clock_t::period, _Period>::value, bool>::type
256 __try_lock_for_impl(const chrono::duration<_Rep, _Period>& __rtime)
258 __clock_t::time_point __atime = __clock_t::now()
259 + ++chrono::duration_cast<__clock_t::duration>(__rtime);
261 return try_lock_until(__atime);
265 /// recursive_timed_mutex
266 class recursive_timed_mutex
269 typedef __gthread_recursive_mutex_t* native_handle_type;
271 recursive_timed_mutex()
273 // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
274 #ifdef __GTHREAD_RECURSIVE_MUTEX_INIT
275 __gthread_recursive_mutex_t __tmp = __GTHREAD_RECURSIVE_MUTEX_INIT;
278 __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
282 recursive_timed_mutex(const recursive_timed_mutex&) = delete;
283 recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
288 int __e = __gthread_recursive_mutex_lock(&_M_mutex);
290 // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
292 __throw_system_error(__e);
298 // XXX EINVAL, EAGAIN, EBUSY
299 return !__gthread_recursive_mutex_trylock(&_M_mutex);
302 template <class _Rep, class _Period>
304 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
305 { return __try_lock_for_impl(__rtime); }
307 template <class _Clock, class _Duration>
309 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
311 chrono::time_point<_Clock, chrono::seconds> __s =
312 chrono::time_point_cast<chrono::seconds>(__atime);
314 chrono::nanoseconds __ns =
315 chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
317 __gthread_time_t __ts = {
318 static_cast<std::time_t>(__s.time_since_epoch().count()),
319 static_cast<long>(__ns.count())
322 return !__gthread_recursive_mutex_timedlock(&_M_mutex, &__ts);
328 // XXX EINVAL, EAGAIN, EBUSY
329 __gthread_recursive_mutex_unlock(&_M_mutex);
334 { return &_M_mutex; }
337 __gthread_recursive_mutex_t _M_mutex;
339 #ifdef _GLIBCXX_USE_CLOCK_MONOTONIC
340 typedef chrono::monotonic_clock __clock_t;
342 typedef chrono::high_resolution_clock __clock_t;
345 template<typename _Rep, typename _Period>
347 ratio_less_equal<__clock_t::period, _Period>::value, bool>::type
348 __try_lock_for_impl(const chrono::duration<_Rep, _Period>& __rtime)
350 __clock_t::time_point __atime = __clock_t::now()
351 + chrono::duration_cast<__clock_t::duration>(__rtime);
353 return try_lock_until(__atime);
356 template <typename _Rep, typename _Period>
358 !ratio_less_equal<__clock_t::period, _Period>::value, bool>::type
359 __try_lock_for_impl(const chrono::duration<_Rep, _Period>& __rtime)
361 __clock_t::time_point __atime = __clock_t::now()
362 + ++chrono::duration_cast<__clock_t::duration>(__rtime);
364 return try_lock_until(__atime);
368 /// Do not acquire ownership of the mutex.
369 struct defer_lock_t { };
371 /// Try to acquire ownership of the mutex without blocking.
372 struct try_to_lock_t { };
374 /// Assume the calling thread has already obtained mutex ownership
376 struct adopt_lock_t { };
378 extern const defer_lock_t defer_lock;
379 extern const try_to_lock_t try_to_lock;
380 extern const adopt_lock_t adopt_lock;
382 /// Thrown to indicate errors with lock operations.
383 class lock_error : public exception
387 what() const throw();
390 /// @brief Scoped lock idiom.
391 // Acquire the mutex here with a constructor call, then release with
392 // the destructor call in accordance with RAII style.
393 template<typename _Mutex>
397 typedef _Mutex mutex_type;
399 explicit lock_guard(mutex_type& __m) : _M_device(__m)
400 { _M_device.lock(); }
402 lock_guard(mutex_type& __m, adopt_lock_t __a) : _M_device(__m)
403 { _M_device.lock(); }
406 { _M_device.unlock(); }
408 lock_guard(const lock_guard&) = delete;
409 lock_guard& operator=(const lock_guard&) = delete;
412 mutex_type& _M_device;
416 template<typename _Mutex>
420 typedef _Mutex mutex_type;
423 : _M_device(0), _M_owns(false)
426 explicit unique_lock(mutex_type& __m)
427 : _M_device(&__m), _M_owns(false)
433 unique_lock(mutex_type& __m, defer_lock_t)
434 : _M_device(&__m), _M_owns(false)
437 unique_lock(mutex_type& __m, try_to_lock_t)
438 : _M_device(&__m), _M_owns(_M_device->try_lock())
441 unique_lock(mutex_type& __m, adopt_lock_t)
442 : _M_device(&__m), _M_owns(true)
444 // XXX calling thread owns mutex
447 template<typename _Clock, typename _Duration>
448 unique_lock(mutex_type& __m,
449 const chrono::time_point<_Clock, _Duration>& __atime)
450 : _M_device(&__m), _M_owns(_M_device->try_lock_until(__atime))
453 template<typename _Rep, typename _Period>
454 unique_lock(mutex_type& __m,
455 const chrono::duration<_Rep, _Period>& __rtime)
456 : _M_device(&__m), _M_owns(_M_device->try_lock_for(__rtime))
465 unique_lock(const unique_lock&) = delete;
466 unique_lock& operator=(const unique_lock&) = delete;
468 unique_lock(unique_lock&& __u)
469 : _M_device(__u._M_device), _M_owns(__u._M_owns)
475 unique_lock& operator=(unique_lock&& __u)
480 unique_lock(std::move(__u)).swap(*this);
492 __throw_system_error(posix_error::operation_not_permitted);
494 __throw_system_error(posix_error::resource_deadlock_would_occur);
506 __throw_system_error(posix_error::operation_not_permitted);
508 __throw_system_error(posix_error::resource_deadlock_would_occur);
511 _M_owns = _M_device->try_lock();
516 template<typename _Clock, typename _Duration>
518 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
521 __throw_system_error(posix_error::operation_not_permitted);
523 __throw_system_error(posix_error::resource_deadlock_would_occur);
526 _M_owns = _M_device->try_lock_until(__atime);
531 template<typename _Rep, typename _Period>
533 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
536 __throw_system_error(posix_error::operation_not_permitted);
538 __throw_system_error(posix_error::resource_deadlock_would_occur);
541 _M_owns = _M_device->try_lock_for(__rtime);
550 __throw_system_error(posix_error::operation_not_permitted);
559 swap(unique_lock&& __u)
561 std::swap(_M_device, __u._M_device);
562 std::swap(_M_owns, __u._M_owns);
568 mutex_type* __ret = _M_device;
578 /* explicit */ operator bool () const
579 { return owns_lock(); }
583 { return _M_device; }
586 mutex_type* _M_device;
587 bool _M_owns; // XXX use atomic_bool
590 template<typename _Mutex>
592 swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y)
595 template<typename _Mutex>
597 swap(unique_lock<_Mutex>&& __x, unique_lock<_Mutex>& __y)
600 template<typename _Mutex>
602 swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>&& __y)
608 template<typename... _Lock>
610 __do_unlock(tuple<_Lock&...>& __locks)
612 std::get<_Idx>(__locks).unlock();
613 __unlock_impl<_Idx - 1>::__do_unlock(__locks);
618 struct __unlock_impl<-1>
620 template<typename... _Lock>
622 __do_unlock(tuple<_Lock&...>&)
626 template<int _Idx, bool _Continue = true>
627 struct __try_lock_impl
629 template<typename... _Lock>
631 __do_try_lock(tuple<_Lock&...>& __locks)
633 if(std::get<_Idx>(__locks).try_lock())
635 return __try_lock_impl<_Idx + 1,
636 _Idx + 2 < sizeof...(_Lock)>::__do_try_lock(__locks);
640 __unlock_impl<_Idx>::__do_unlock(__locks);
647 struct __try_lock_impl<_Idx, false>
649 template<typename... _Lock>
651 __do_try_lock(tuple<_Lock&...>& __locks)
653 if(std::get<_Idx>(__locks).try_lock())
657 __unlock_impl<_Idx>::__do_unlock(__locks);
663 /** @brief Generic try_lock.
664 * @param __l1 Meets Mutex requirements (try_lock() may throw).
665 * @param __l2 Meets Mutex requirements (try_lock() may throw).
666 * @param __l3 Meets Mutex requirements (try_lock() may throw).
667 * @return Returns -1 if all try_lock() calls return true. Otherwise returns
668 * a 0-based index corresponding to the argument that returned false.
669 * @post Either all arguments are locked, or none will be.
671 * Sequentially calls try_lock() on each argument.
673 template<typename _Lock1, typename _Lock2, typename... _Lock3>
675 try_lock(_Lock1& __l1, _Lock2& __l2, _Lock3&... __l3)
677 tuple<_Lock1&, _Lock2&, _Lock3&...> __locks(__l1, __l2, __l3...);
678 return __try_lock_impl<0>::__do_try_lock(__locks);
681 template<typename _L1, typename _L2, typename ..._L3>
683 lock(_L1&, _L2&, _L3&...);
688 typedef __gthread_once_t __native_type;
692 __gthread_once_t __tmp = __GTHREAD_ONCE_INIT;
696 once_flag(const once_flag&) = delete;
697 once_flag& operator=(const once_flag&) = delete;
699 template<typename _Callable, typename... _Args>
701 call_once(once_flag& __once, _Callable __f, _Args&&... __args);
704 __native_type _M_once;
707 #ifdef _GLIBCXX_HAVE_TLS
708 extern __thread void* __once_callable;
709 extern __thread void (*__once_call)();
711 template<typename _Callable>
712 void __once_call_impl()
714 (*(_Callable*)__once_callable)();
717 extern function<void()> __once_functor;
718 extern unique_lock<mutex> __once_functor_lock;
721 extern "C" void __once_proxy();
723 template<typename _Callable, typename... _Args>
725 call_once(once_flag& __once, _Callable __f, _Args&&... __args)
727 #ifdef _GLIBCXX_HAVE_TLS
728 auto __bound_functor = bind(__f, __args...);
729 __once_callable = &__bound_functor;
730 __once_call = &__once_call_impl<decltype(__bound_functor)>;
732 __once_functor_lock.lock();
733 __once_functor = bind(__f, __args...);
736 int __e = __gthread_once(&(__once._M_once), &__once_proxy);
738 #ifndef _GLIBCXX_HAVE_TLS
739 if (__once_functor_lock)
740 __once_functor_lock.unlock();
744 __throw_system_error(__e);
748 #endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1
750 #endif // __GXX_EXPERIMENTAL_CXX0X__
752 #endif // _GLIBCXX_MUTEX