2 //===----------------------------------------------------------------------===//
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8 //===----------------------------------------------------------------------===//
10 #ifndef _LIBCPP___MUTEX_BASE
11 #define _LIBCPP___MUTEX_BASE
15 #include <system_error>
16 #include <__threading_support>
19 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
20 #pragma GCC system_header
24 #include <__undef_macros>
27 _LIBCPP_BEGIN_NAMESPACE_STD
29 #ifndef _LIBCPP_HAS_NO_THREADS
31 #ifndef _LIBCPP_THREAD_SAFETY_ANNOTATION
32 # ifdef _LIBCPP_HAS_THREAD_SAFETY_ANNOTATIONS
33 # define _LIBCPP_THREAD_SAFETY_ANNOTATION(x) __attribute__((x))
35 # define _LIBCPP_THREAD_SAFETY_ANNOTATION(x)
37 #endif // _LIBCPP_THREAD_SAFETY_ANNOTATION
40 class _LIBCPP_TYPE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("mutex")) mutex
42 __libcpp_mutex_t __m_ = _LIBCPP_MUTEX_INITIALIZER;
45 _LIBCPP_INLINE_VISIBILITY
46 _LIBCPP_CONSTEXPR mutex() = default;
48 mutex(const mutex&) = delete;
49 mutex& operator=(const mutex&) = delete;
51 #if defined(_LIBCPP_HAS_TRIVIAL_MUTEX_DESTRUCTION)
57 void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability());
58 bool try_lock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_capability(true));
59 void unlock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability());
61 typedef __libcpp_mutex_t* native_handle_type;
62 _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;}
65 static_assert(is_nothrow_default_constructible<mutex>::value,
66 "the default constructor for std::mutex must be nothrow");
68 struct _LIBCPP_TYPE_VIS defer_lock_t {};
69 struct _LIBCPP_TYPE_VIS try_to_lock_t {};
70 struct _LIBCPP_TYPE_VIS adopt_lock_t {};
72 #if defined(_LIBCPP_CXX03_LANG) || defined(_LIBCPP_BUILDING_LIBRARY)
74 extern _LIBCPP_EXPORTED_FROM_ABI const defer_lock_t defer_lock;
75 extern _LIBCPP_EXPORTED_FROM_ABI const try_to_lock_t try_to_lock;
76 extern _LIBCPP_EXPORTED_FROM_ABI const adopt_lock_t adopt_lock;
80 /* _LIBCPP_INLINE_VAR */ constexpr defer_lock_t defer_lock = defer_lock_t();
81 /* _LIBCPP_INLINE_VAR */ constexpr try_to_lock_t try_to_lock = try_to_lock_t();
82 /* _LIBCPP_INLINE_VAR */ constexpr adopt_lock_t adopt_lock = adopt_lock_t();
86 template <class _Mutex>
87 class _LIBCPP_TEMPLATE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable)
91 typedef _Mutex mutex_type;
97 _LIBCPP_INLINE_VISIBILITY
98 explicit lock_guard(mutex_type& __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability(__m))
99 : __m_(__m) {__m_.lock();}
100 _LIBCPP_INLINE_VISIBILITY
101 lock_guard(mutex_type& __m, adopt_lock_t) _LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m))
103 _LIBCPP_INLINE_VISIBILITY
104 ~lock_guard() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) {__m_.unlock();}
107 lock_guard(lock_guard const&) _LIBCPP_EQUAL_DELETE;
108 lock_guard& operator=(lock_guard const&) _LIBCPP_EQUAL_DELETE;
111 template <class _Mutex>
112 class _LIBCPP_TEMPLATE_VIS unique_lock
115 typedef _Mutex mutex_type;
122 _LIBCPP_INLINE_VISIBILITY
123 unique_lock() _NOEXCEPT : __m_(nullptr), __owns_(false) {}
124 _LIBCPP_INLINE_VISIBILITY
125 explicit unique_lock(mutex_type& __m)
126 : __m_(_VSTD::addressof(__m)), __owns_(true) {__m_->lock();}
127 _LIBCPP_INLINE_VISIBILITY
128 unique_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
129 : __m_(_VSTD::addressof(__m)), __owns_(false) {}
130 _LIBCPP_INLINE_VISIBILITY
131 unique_lock(mutex_type& __m, try_to_lock_t)
132 : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock()) {}
133 _LIBCPP_INLINE_VISIBILITY
134 unique_lock(mutex_type& __m, adopt_lock_t)
135 : __m_(_VSTD::addressof(__m)), __owns_(true) {}
136 template <class _Clock, class _Duration>
137 _LIBCPP_INLINE_VISIBILITY
138 unique_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __t)
139 : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock_until(__t)) {}
140 template <class _Rep, class _Period>
141 _LIBCPP_INLINE_VISIBILITY
142 unique_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __d)
143 : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock_for(__d)) {}
144 _LIBCPP_INLINE_VISIBILITY
152 unique_lock(unique_lock const&); // = delete;
153 unique_lock& operator=(unique_lock const&); // = delete;
156 #ifndef _LIBCPP_CXX03_LANG
157 _LIBCPP_INLINE_VISIBILITY
158 unique_lock(unique_lock&& __u) _NOEXCEPT
159 : __m_(__u.__m_), __owns_(__u.__owns_)
160 {__u.__m_ = nullptr; __u.__owns_ = false;}
161 _LIBCPP_INLINE_VISIBILITY
162 unique_lock& operator=(unique_lock&& __u) _NOEXCEPT
167 __owns_ = __u.__owns_;
173 #endif // _LIBCPP_CXX03_LANG
178 template <class _Rep, class _Period>
179 bool try_lock_for(const chrono::duration<_Rep, _Period>& __d);
180 template <class _Clock, class _Duration>
181 bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
185 _LIBCPP_INLINE_VISIBILITY
186 void swap(unique_lock& __u) _NOEXCEPT
188 _VSTD::swap(__m_, __u.__m_);
189 _VSTD::swap(__owns_, __u.__owns_);
191 _LIBCPP_INLINE_VISIBILITY
192 mutex_type* release() _NOEXCEPT
194 mutex_type* __m = __m_;
200 _LIBCPP_INLINE_VISIBILITY
201 bool owns_lock() const _NOEXCEPT {return __owns_;}
202 _LIBCPP_INLINE_VISIBILITY
204 operator bool () const _NOEXCEPT {return __owns_;}
205 _LIBCPP_INLINE_VISIBILITY
206 mutex_type* mutex() const _NOEXCEPT {return __m_;}
209 template <class _Mutex>
211 unique_lock<_Mutex>::lock()
214 __throw_system_error(EPERM, "unique_lock::lock: references null mutex");
216 __throw_system_error(EDEADLK, "unique_lock::lock: already locked");
221 template <class _Mutex>
223 unique_lock<_Mutex>::try_lock()
226 __throw_system_error(EPERM, "unique_lock::try_lock: references null mutex");
228 __throw_system_error(EDEADLK, "unique_lock::try_lock: already locked");
229 __owns_ = __m_->try_lock();
233 template <class _Mutex>
234 template <class _Rep, class _Period>
236 unique_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
239 __throw_system_error(EPERM, "unique_lock::try_lock_for: references null mutex");
241 __throw_system_error(EDEADLK, "unique_lock::try_lock_for: already locked");
242 __owns_ = __m_->try_lock_for(__d);
246 template <class _Mutex>
247 template <class _Clock, class _Duration>
249 unique_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
252 __throw_system_error(EPERM, "unique_lock::try_lock_until: references null mutex");
254 __throw_system_error(EDEADLK, "unique_lock::try_lock_until: already locked");
255 __owns_ = __m_->try_lock_until(__t);
259 template <class _Mutex>
261 unique_lock<_Mutex>::unlock()
264 __throw_system_error(EPERM, "unique_lock::unlock: not locked");
269 template <class _Mutex>
270 inline _LIBCPP_INLINE_VISIBILITY
272 swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) _NOEXCEPT
275 //enum class cv_status
276 _LIBCPP_DECLARE_STRONG_ENUM(cv_status)
281 _LIBCPP_DECLARE_STRONG_ENUM_EPILOG(cv_status)
283 class _LIBCPP_TYPE_VIS condition_variable
285 __libcpp_condvar_t __cv_ = _LIBCPP_CONDVAR_INITIALIZER;
287 _LIBCPP_INLINE_VISIBILITY
288 _LIBCPP_CONSTEXPR condition_variable() _NOEXCEPT = default;
290 #ifdef _LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION
291 ~condition_variable() = default;
293 ~condition_variable();
296 condition_variable(const condition_variable&) = delete;
297 condition_variable& operator=(const condition_variable&) = delete;
299 void notify_one() _NOEXCEPT;
300 void notify_all() _NOEXCEPT;
302 void wait(unique_lock<mutex>& __lk) _NOEXCEPT;
303 template <class _Predicate>
304 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
305 void wait(unique_lock<mutex>& __lk, _Predicate __pred);
307 template <class _Clock, class _Duration>
308 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
310 wait_until(unique_lock<mutex>& __lk,
311 const chrono::time_point<_Clock, _Duration>& __t);
313 template <class _Clock, class _Duration, class _Predicate>
314 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
316 wait_until(unique_lock<mutex>& __lk,
317 const chrono::time_point<_Clock, _Duration>& __t,
320 template <class _Rep, class _Period>
321 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
323 wait_for(unique_lock<mutex>& __lk,
324 const chrono::duration<_Rep, _Period>& __d);
326 template <class _Rep, class _Period, class _Predicate>
328 _LIBCPP_INLINE_VISIBILITY
329 wait_for(unique_lock<mutex>& __lk,
330 const chrono::duration<_Rep, _Period>& __d,
333 typedef __libcpp_condvar_t* native_handle_type;
334 _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;}
337 void __do_timed_wait(unique_lock<mutex>& __lk,
338 chrono::time_point<chrono::system_clock, chrono::nanoseconds>) _NOEXCEPT;
340 #endif // !_LIBCPP_HAS_NO_THREADS
342 template <class _To, class _Rep, class _Period>
343 inline _LIBCPP_INLINE_VISIBILITY
346 chrono::__is_duration<_To>::value,
349 __ceil(chrono::duration<_Rep, _Period> __d)
351 using namespace chrono;
352 _To __r = duration_cast<_To>(__d);
358 #ifndef _LIBCPP_HAS_NO_THREADS
359 template <class _Predicate>
361 condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred)
367 template <class _Clock, class _Duration>
369 condition_variable::wait_until(unique_lock<mutex>& __lk,
370 const chrono::time_point<_Clock, _Duration>& __t)
372 using namespace chrono;
373 wait_for(__lk, __t - _Clock::now());
374 return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
377 template <class _Clock, class _Duration, class _Predicate>
379 condition_variable::wait_until(unique_lock<mutex>& __lk,
380 const chrono::time_point<_Clock, _Duration>& __t,
385 if (wait_until(__lk, __t) == cv_status::timeout)
391 template <class _Rep, class _Period>
393 condition_variable::wait_for(unique_lock<mutex>& __lk,
394 const chrono::duration<_Rep, _Period>& __d)
396 using namespace chrono;
397 if (__d <= __d.zero())
398 return cv_status::timeout;
399 typedef time_point<system_clock, duration<long double, nano> > __sys_tpf;
400 typedef time_point<system_clock, nanoseconds> __sys_tpi;
401 __sys_tpf _Max = __sys_tpi::max();
402 steady_clock::time_point __c_now = steady_clock::now();
403 system_clock::time_point __s_now = system_clock::now();
404 if (_Max - __d > __s_now)
405 __do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__d));
407 __do_timed_wait(__lk, __sys_tpi::max());
408 return steady_clock::now() - __c_now < __d ? cv_status::no_timeout :
412 template <class _Rep, class _Period, class _Predicate>
415 condition_variable::wait_for(unique_lock<mutex>& __lk,
416 const chrono::duration<_Rep, _Period>& __d,
419 return wait_until(__lk, chrono::steady_clock::now() + __d,
420 _VSTD::move(__pred));
423 #endif // !_LIBCPP_HAS_NO_THREADS
425 _LIBCPP_END_NAMESPACE_STD
429 #endif // _LIBCPP___MUTEX_BASE