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>
20 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
21 #pragma GCC system_header
25 #include <__undef_macros>
28 _LIBCPP_BEGIN_NAMESPACE_STD
30 #ifndef _LIBCPP_HAS_NO_THREADS
32 #ifndef _LIBCPP_THREAD_SAFETY_ANNOTATION
33 # ifdef _LIBCPP_HAS_THREAD_SAFETY_ANNOTATIONS
34 # define _LIBCPP_THREAD_SAFETY_ANNOTATION(x) __attribute__((x))
36 # define _LIBCPP_THREAD_SAFETY_ANNOTATION(x)
38 #endif // _LIBCPP_THREAD_SAFETY_ANNOTATION
41 class _LIBCPP_TYPE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("mutex")) mutex
43 __libcpp_mutex_t __m_ = _LIBCPP_MUTEX_INITIALIZER;
46 _LIBCPP_INLINE_VISIBILITY
47 _LIBCPP_CONSTEXPR mutex() = default;
49 mutex(const mutex&) = delete;
50 mutex& operator=(const mutex&) = delete;
52 #if defined(_LIBCPP_HAS_TRIVIAL_MUTEX_DESTRUCTION)
58 void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability());
59 bool try_lock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_capability(true));
60 void unlock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability());
62 typedef __libcpp_mutex_t* native_handle_type;
63 _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;}
66 static_assert(is_nothrow_default_constructible<mutex>::value,
67 "the default constructor for std::mutex must be nothrow");
69 struct _LIBCPP_TYPE_VIS defer_lock_t { explicit defer_lock_t() = default; };
70 struct _LIBCPP_TYPE_VIS try_to_lock_t { explicit try_to_lock_t() = default; };
71 struct _LIBCPP_TYPE_VIS adopt_lock_t { explicit adopt_lock_t() = default; };
73 #if defined(_LIBCPP_CXX03_LANG) || defined(_LIBCPP_BUILDING_LIBRARY)
75 extern _LIBCPP_EXPORTED_FROM_ABI const defer_lock_t defer_lock;
76 extern _LIBCPP_EXPORTED_FROM_ABI const try_to_lock_t try_to_lock;
77 extern _LIBCPP_EXPORTED_FROM_ABI const adopt_lock_t adopt_lock;
81 /* _LIBCPP_INLINE_VAR */ constexpr defer_lock_t defer_lock = defer_lock_t();
82 /* _LIBCPP_INLINE_VAR */ constexpr try_to_lock_t try_to_lock = try_to_lock_t();
83 /* _LIBCPP_INLINE_VAR */ constexpr adopt_lock_t adopt_lock = adopt_lock_t();
87 template <class _Mutex>
88 class _LIBCPP_TEMPLATE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable)
92 typedef _Mutex mutex_type;
98 _LIBCPP_NODISCARD_EXT _LIBCPP_INLINE_VISIBILITY
99 explicit lock_guard(mutex_type& __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability(__m))
100 : __m_(__m) {__m_.lock();}
102 _LIBCPP_NODISCARD_EXT _LIBCPP_INLINE_VISIBILITY
103 lock_guard(mutex_type& __m, adopt_lock_t) _LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m))
105 _LIBCPP_INLINE_VISIBILITY
106 ~lock_guard() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) {__m_.unlock();}
109 lock_guard(lock_guard const&) _LIBCPP_EQUAL_DELETE;
110 lock_guard& operator=(lock_guard const&) _LIBCPP_EQUAL_DELETE;
113 template <class _Mutex>
114 class _LIBCPP_TEMPLATE_VIS unique_lock
117 typedef _Mutex mutex_type;
124 _LIBCPP_INLINE_VISIBILITY
125 unique_lock() _NOEXCEPT : __m_(nullptr), __owns_(false) {}
126 _LIBCPP_INLINE_VISIBILITY
127 explicit unique_lock(mutex_type& __m)
128 : __m_(_VSTD::addressof(__m)), __owns_(true) {__m_->lock();}
129 _LIBCPP_INLINE_VISIBILITY
130 unique_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
131 : __m_(_VSTD::addressof(__m)), __owns_(false) {}
132 _LIBCPP_INLINE_VISIBILITY
133 unique_lock(mutex_type& __m, try_to_lock_t)
134 : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock()) {}
135 _LIBCPP_INLINE_VISIBILITY
136 unique_lock(mutex_type& __m, adopt_lock_t)
137 : __m_(_VSTD::addressof(__m)), __owns_(true) {}
138 template <class _Clock, class _Duration>
139 _LIBCPP_INLINE_VISIBILITY
140 unique_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __t)
141 : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock_until(__t)) {}
142 template <class _Rep, class _Period>
143 _LIBCPP_INLINE_VISIBILITY
144 unique_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __d)
145 : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock_for(__d)) {}
146 _LIBCPP_INLINE_VISIBILITY
154 unique_lock(unique_lock const&); // = delete;
155 unique_lock& operator=(unique_lock const&); // = delete;
158 #ifndef _LIBCPP_CXX03_LANG
159 _LIBCPP_INLINE_VISIBILITY
160 unique_lock(unique_lock&& __u) _NOEXCEPT
161 : __m_(__u.__m_), __owns_(__u.__owns_)
162 {__u.__m_ = nullptr; __u.__owns_ = false;}
163 _LIBCPP_INLINE_VISIBILITY
164 unique_lock& operator=(unique_lock&& __u) _NOEXCEPT
169 __owns_ = __u.__owns_;
175 #endif // _LIBCPP_CXX03_LANG
180 template <class _Rep, class _Period>
181 bool try_lock_for(const chrono::duration<_Rep, _Period>& __d);
182 template <class _Clock, class _Duration>
183 bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
187 _LIBCPP_INLINE_VISIBILITY
188 void swap(unique_lock& __u) _NOEXCEPT
190 _VSTD::swap(__m_, __u.__m_);
191 _VSTD::swap(__owns_, __u.__owns_);
193 _LIBCPP_INLINE_VISIBILITY
194 mutex_type* release() _NOEXCEPT
196 mutex_type* __m = __m_;
202 _LIBCPP_INLINE_VISIBILITY
203 bool owns_lock() const _NOEXCEPT {return __owns_;}
204 _LIBCPP_INLINE_VISIBILITY
206 operator bool () const _NOEXCEPT {return __owns_;}
207 _LIBCPP_INLINE_VISIBILITY
208 mutex_type* mutex() const _NOEXCEPT {return __m_;}
211 template <class _Mutex>
213 unique_lock<_Mutex>::lock()
216 __throw_system_error(EPERM, "unique_lock::lock: references null mutex");
218 __throw_system_error(EDEADLK, "unique_lock::lock: already locked");
223 template <class _Mutex>
225 unique_lock<_Mutex>::try_lock()
228 __throw_system_error(EPERM, "unique_lock::try_lock: references null mutex");
230 __throw_system_error(EDEADLK, "unique_lock::try_lock: already locked");
231 __owns_ = __m_->try_lock();
235 template <class _Mutex>
236 template <class _Rep, class _Period>
238 unique_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
241 __throw_system_error(EPERM, "unique_lock::try_lock_for: references null mutex");
243 __throw_system_error(EDEADLK, "unique_lock::try_lock_for: already locked");
244 __owns_ = __m_->try_lock_for(__d);
248 template <class _Mutex>
249 template <class _Clock, class _Duration>
251 unique_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
254 __throw_system_error(EPERM, "unique_lock::try_lock_until: references null mutex");
256 __throw_system_error(EDEADLK, "unique_lock::try_lock_until: already locked");
257 __owns_ = __m_->try_lock_until(__t);
261 template <class _Mutex>
263 unique_lock<_Mutex>::unlock()
266 __throw_system_error(EPERM, "unique_lock::unlock: not locked");
271 template <class _Mutex>
272 inline _LIBCPP_INLINE_VISIBILITY
274 swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) _NOEXCEPT
277 //enum class cv_status
278 _LIBCPP_DECLARE_STRONG_ENUM(cv_status)
283 _LIBCPP_DECLARE_STRONG_ENUM_EPILOG(cv_status)
285 class _LIBCPP_TYPE_VIS condition_variable
287 __libcpp_condvar_t __cv_ = _LIBCPP_CONDVAR_INITIALIZER;
289 _LIBCPP_INLINE_VISIBILITY
290 _LIBCPP_CONSTEXPR condition_variable() _NOEXCEPT = default;
292 #ifdef _LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION
293 ~condition_variable() = default;
295 ~condition_variable();
298 condition_variable(const condition_variable&) = delete;
299 condition_variable& operator=(const condition_variable&) = delete;
301 void notify_one() _NOEXCEPT;
302 void notify_all() _NOEXCEPT;
304 void wait(unique_lock<mutex>& __lk) _NOEXCEPT;
305 template <class _Predicate>
306 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
307 void wait(unique_lock<mutex>& __lk, _Predicate __pred);
309 template <class _Clock, class _Duration>
310 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
312 wait_until(unique_lock<mutex>& __lk,
313 const chrono::time_point<_Clock, _Duration>& __t);
315 template <class _Clock, class _Duration, class _Predicate>
316 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
318 wait_until(unique_lock<mutex>& __lk,
319 const chrono::time_point<_Clock, _Duration>& __t,
322 template <class _Rep, class _Period>
323 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
325 wait_for(unique_lock<mutex>& __lk,
326 const chrono::duration<_Rep, _Period>& __d);
328 template <class _Rep, class _Period, class _Predicate>
330 _LIBCPP_INLINE_VISIBILITY
331 wait_for(unique_lock<mutex>& __lk,
332 const chrono::duration<_Rep, _Period>& __d,
335 typedef __libcpp_condvar_t* native_handle_type;
336 _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;}
339 void __do_timed_wait(unique_lock<mutex>& __lk,
340 chrono::time_point<chrono::system_clock, chrono::nanoseconds>) _NOEXCEPT;
341 #if defined(_LIBCPP_HAS_COND_CLOCKWAIT)
342 void __do_timed_wait(unique_lock<mutex>& __lk,
343 chrono::time_point<chrono::steady_clock, chrono::nanoseconds>) _NOEXCEPT;
345 template <class _Clock>
346 void __do_timed_wait(unique_lock<mutex>& __lk,
347 chrono::time_point<_Clock, chrono::nanoseconds>) _NOEXCEPT;
349 #endif // !_LIBCPP_HAS_NO_THREADS
351 template <class _Rep, class _Period>
352 inline _LIBCPP_INLINE_VISIBILITY
355 is_floating_point<_Rep>::value,
358 __safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d)
360 using namespace chrono;
361 using __ratio = ratio_divide<_Period, nano>;
362 using __ns_rep = nanoseconds::rep;
363 _Rep __result_float = __d.count() * __ratio::num / __ratio::den;
365 _Rep __result_max = numeric_limits<__ns_rep>::max();
366 if (__result_float >= __result_max) {
367 return nanoseconds::max();
370 _Rep __result_min = numeric_limits<__ns_rep>::min();
371 if (__result_float <= __result_min) {
372 return nanoseconds::min();
375 return nanoseconds(static_cast<__ns_rep>(__result_float));
378 template <class _Rep, class _Period>
379 inline _LIBCPP_INLINE_VISIBILITY
382 !is_floating_point<_Rep>::value,
385 __safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d)
387 using namespace chrono;
388 if (__d.count() == 0) {
389 return nanoseconds(0);
392 using __ratio = ratio_divide<_Period, nano>;
393 using __ns_rep = nanoseconds::rep;
394 __ns_rep __result_max = std::numeric_limits<__ns_rep>::max();
395 if (__d.count() > 0 && __d.count() > __result_max / __ratio::num) {
396 return nanoseconds::max();
399 __ns_rep __result_min = std::numeric_limits<__ns_rep>::min();
400 if (__d.count() < 0 && __d.count() < __result_min / __ratio::num) {
401 return nanoseconds::min();
404 __ns_rep __result = __d.count() * __ratio::num / __ratio::den;
406 return nanoseconds(1);
409 return nanoseconds(__result);
412 #ifndef _LIBCPP_HAS_NO_THREADS
413 template <class _Predicate>
415 condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred)
421 template <class _Clock, class _Duration>
423 condition_variable::wait_until(unique_lock<mutex>& __lk,
424 const chrono::time_point<_Clock, _Duration>& __t)
426 using namespace chrono;
427 using __clock_tp_ns = time_point<_Clock, nanoseconds>;
429 typename _Clock::time_point __now = _Clock::now();
431 return cv_status::timeout;
433 __clock_tp_ns __t_ns = __clock_tp_ns(__safe_nanosecond_cast(__t.time_since_epoch()));
435 __do_timed_wait(__lk, __t_ns);
436 return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
439 template <class _Clock, class _Duration, class _Predicate>
441 condition_variable::wait_until(unique_lock<mutex>& __lk,
442 const chrono::time_point<_Clock, _Duration>& __t,
447 if (wait_until(__lk, __t) == cv_status::timeout)
453 template <class _Rep, class _Period>
455 condition_variable::wait_for(unique_lock<mutex>& __lk,
456 const chrono::duration<_Rep, _Period>& __d)
458 using namespace chrono;
459 if (__d <= __d.zero())
460 return cv_status::timeout;
461 using __ns_rep = nanoseconds::rep;
462 steady_clock::time_point __c_now = steady_clock::now();
464 #if defined(_LIBCPP_HAS_COND_CLOCKWAIT)
465 using __clock_tp_ns = time_point<steady_clock, nanoseconds>;
466 __ns_rep __now_count_ns = __safe_nanosecond_cast(__c_now.time_since_epoch()).count();
468 using __clock_tp_ns = time_point<system_clock, nanoseconds>;
469 __ns_rep __now_count_ns = __safe_nanosecond_cast(system_clock::now().time_since_epoch()).count();
472 __ns_rep __d_ns_count = __safe_nanosecond_cast(__d).count();
474 if (__now_count_ns > numeric_limits<__ns_rep>::max() - __d_ns_count) {
475 __do_timed_wait(__lk, __clock_tp_ns::max());
477 __do_timed_wait(__lk, __clock_tp_ns(nanoseconds(__now_count_ns + __d_ns_count)));
480 return steady_clock::now() - __c_now < __d ? cv_status::no_timeout :
484 template <class _Rep, class _Period, class _Predicate>
487 condition_variable::wait_for(unique_lock<mutex>& __lk,
488 const chrono::duration<_Rep, _Period>& __d,
491 return wait_until(__lk, chrono::steady_clock::now() + __d,
492 _VSTD::move(__pred));
495 #if defined(_LIBCPP_HAS_COND_CLOCKWAIT)
498 condition_variable::__do_timed_wait(unique_lock<mutex>& __lk,
499 chrono::time_point<chrono::steady_clock, chrono::nanoseconds> __tp) _NOEXCEPT
501 using namespace chrono;
502 if (!__lk.owns_lock())
503 __throw_system_error(EPERM,
504 "condition_variable::timed wait: mutex not locked");
505 nanoseconds __d = __tp.time_since_epoch();
507 seconds __s = duration_cast<seconds>(__d);
508 using __ts_sec = decltype(__ts.tv_sec);
509 const __ts_sec __ts_sec_max = numeric_limits<__ts_sec>::max();
510 if (__s.count() < __ts_sec_max)
512 __ts.tv_sec = static_cast<__ts_sec>(__s.count());
513 __ts.tv_nsec = (__d - __s).count();
517 __ts.tv_sec = __ts_sec_max;
518 __ts.tv_nsec = giga::num - 1;
520 int __ec = pthread_cond_clockwait(&__cv_, __lk.mutex()->native_handle(), CLOCK_MONOTONIC, &__ts);
521 if (__ec != 0 && __ec != ETIMEDOUT)
522 __throw_system_error(__ec, "condition_variable timed_wait failed");
524 #endif // _LIBCPP_HAS_COND_CLOCKWAIT
526 template <class _Clock>
529 condition_variable::__do_timed_wait(unique_lock<mutex>& __lk,
530 chrono::time_point<_Clock, chrono::nanoseconds> __tp) _NOEXCEPT
532 wait_for(__lk, __tp - _Clock::now());
535 #endif // !_LIBCPP_HAS_NO_THREADS
537 _LIBCPP_END_NAMESPACE_STD
541 #endif // _LIBCPP___MUTEX_BASE