1// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
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
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef _LIBCPP___MUTEX_BASE
11#define _LIBCPP___MUTEX_BASE
12
13#include <__config>
14#include <chrono>
15#include <system_error>
16#include <__threading_support>
17
18#include <time.h>
19
20#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
21#pragma GCC system_header
22#endif
23
24_LIBCPP_PUSH_MACROS
25#include <__undef_macros>
26
27
28_LIBCPP_BEGIN_NAMESPACE_STD
29
30#ifndef _LIBCPP_HAS_NO_THREADS
31
32class _LIBCPP_TYPE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("mutex")) mutex
33{
34 __libcpp_mutex_t __m_ = _LIBCPP_MUTEX_INITIALIZER;
35
36public:
37 _LIBCPP_INLINE_VISIBILITY
38 _LIBCPP_CONSTEXPR mutex() = default;
39
40 mutex(const mutex&) = delete;
41 mutex& operator=(const mutex&) = delete;
42
43#if defined(_LIBCPP_HAS_TRIVIAL_MUTEX_DESTRUCTION)
44 ~mutex() = default;
45#else
46 ~mutex() _NOEXCEPT;
47#endif
48
49 void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability());
50 bool try_lock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_capability(true));
51 void unlock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability());
52
53 typedef __libcpp_mutex_t* native_handle_type;
54 _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;}
55};
56
57static_assert(is_nothrow_default_constructible<mutex>::value,
58 "the default constructor for std::mutex must be nothrow");
59
60struct _LIBCPP_TYPE_VIS defer_lock_t { explicit defer_lock_t() = default; };
61struct _LIBCPP_TYPE_VIS try_to_lock_t { explicit try_to_lock_t() = default; };
62struct _LIBCPP_TYPE_VIS adopt_lock_t { explicit adopt_lock_t() = default; };
63
64#if defined(_LIBCPP_CXX03_LANG) || defined(_LIBCPP_BUILDING_LIBRARY)
65
66extern _LIBCPP_EXPORTED_FROM_ABI const defer_lock_t defer_lock;
67extern _LIBCPP_EXPORTED_FROM_ABI const try_to_lock_t try_to_lock;
68extern _LIBCPP_EXPORTED_FROM_ABI const adopt_lock_t adopt_lock;
69
70#else
71
72/* _LIBCPP_INLINE_VAR */ constexpr defer_lock_t defer_lock = defer_lock_t();
73/* _LIBCPP_INLINE_VAR */ constexpr try_to_lock_t try_to_lock = try_to_lock_t();
74/* _LIBCPP_INLINE_VAR */ constexpr adopt_lock_t adopt_lock = adopt_lock_t();
75
76#endif
77
78template <class _Mutex>
79class _LIBCPP_TEMPLATE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable)
80lock_guard
81{
82public:
83 typedef _Mutex mutex_type;
84
85private:
86 mutex_type& __m_;
87public:
88
89 _LIBCPP_NODISCARD_EXT _LIBCPP_INLINE_VISIBILITY
90 explicit lock_guard(mutex_type& __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability(__m))
91 : __m_(__m) {__m_.lock();}
92
93 _LIBCPP_NODISCARD_EXT _LIBCPP_INLINE_VISIBILITY
94 lock_guard(mutex_type& __m, adopt_lock_t) _LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m))
95 : __m_(__m) {}
96 _LIBCPP_INLINE_VISIBILITY
97 ~lock_guard() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) {__m_.unlock();}
98
99private:
100 lock_guard(lock_guard const&) _LIBCPP_EQUAL_DELETE;
101 lock_guard& operator=(lock_guard const&) _LIBCPP_EQUAL_DELETE;
102};
103
104template <class _Mutex>
105class _LIBCPP_TEMPLATE_VIS unique_lock
106{
107public:
108 typedef _Mutex mutex_type;
109
110private:
111 mutex_type* __m_;
112 bool __owns_;
113
114public:
115 _LIBCPP_INLINE_VISIBILITY
116 unique_lock() _NOEXCEPT : __m_(nullptr), __owns_(false) {}
117 _LIBCPP_INLINE_VISIBILITY
118 explicit unique_lock(mutex_type& __m)
119 : __m_(_VSTD::addressof(__m)), __owns_(true) {__m_->lock();}
120 _LIBCPP_INLINE_VISIBILITY
121 unique_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
122 : __m_(_VSTD::addressof(__m)), __owns_(false) {}
123 _LIBCPP_INLINE_VISIBILITY
124 unique_lock(mutex_type& __m, try_to_lock_t)
125 : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock()) {}
126 _LIBCPP_INLINE_VISIBILITY
127 unique_lock(mutex_type& __m, adopt_lock_t)
128 : __m_(_VSTD::addressof(__m)), __owns_(true) {}
129 template <class _Clock, class _Duration>
130 _LIBCPP_INLINE_VISIBILITY
131 unique_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __t)
132 : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock_until(__t)) {}
133 template <class _Rep, class _Period>
134 _LIBCPP_INLINE_VISIBILITY
135 unique_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __d)
136 : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock_for(__d)) {}
137 _LIBCPP_INLINE_VISIBILITY
138 ~unique_lock()
139 {
140 if (__owns_)
141 __m_->unlock();
142 }
143
144private:
145 unique_lock(unique_lock const&); // = delete;
146 unique_lock& operator=(unique_lock const&); // = delete;
147
148public:
149#ifndef _LIBCPP_CXX03_LANG
150 _LIBCPP_INLINE_VISIBILITY
151 unique_lock(unique_lock&& __u) _NOEXCEPT
152 : __m_(__u.__m_), __owns_(__u.__owns_)
153 {__u.__m_ = nullptr; __u.__owns_ = false;}
154 _LIBCPP_INLINE_VISIBILITY
155 unique_lock& operator=(unique_lock&& __u) _NOEXCEPT
156 {
157 if (__owns_)
158 __m_->unlock();
159 __m_ = __u.__m_;
160 __owns_ = __u.__owns_;
161 __u.__m_ = nullptr;
162 __u.__owns_ = false;
163 return *this;
164 }
165
166#endif // _LIBCPP_CXX03_LANG
167
168 void lock();
169 bool try_lock();
170
171 template <class _Rep, class _Period>
172 bool try_lock_for(const chrono::duration<_Rep, _Period>& __d);
173 template <class _Clock, class _Duration>
174 bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
175
176 void unlock();
177
178 _LIBCPP_INLINE_VISIBILITY
179 void swap(unique_lock& __u) _NOEXCEPT
180 {
181 _VSTD::swap(__m_, __u.__m_);
182 _VSTD::swap(__owns_, __u.__owns_);
183 }
184 _LIBCPP_INLINE_VISIBILITY
185 mutex_type* release() _NOEXCEPT
186 {
187 mutex_type* __m = __m_;
188 __m_ = nullptr;
189 __owns_ = false;
190 return __m;
191 }
192
193 _LIBCPP_INLINE_VISIBILITY
194 bool owns_lock() const _NOEXCEPT {return __owns_;}
195 _LIBCPP_INLINE_VISIBILITY
196 _LIBCPP_EXPLICIT
197 operator bool () const _NOEXCEPT {return __owns_;}
198 _LIBCPP_INLINE_VISIBILITY
199 mutex_type* mutex() const _NOEXCEPT {return __m_;}
200};
201
202template <class _Mutex>
203void
204unique_lock<_Mutex>::lock()
205{
206 if (__m_ == nullptr)
207 __throw_system_error(EPERM, "unique_lock::lock: references null mutex");
208 if (__owns_)
209 __throw_system_error(EDEADLK, "unique_lock::lock: already locked");
210 __m_->lock();
211 __owns_ = true;
212}
213
214template <class _Mutex>
215bool
216unique_lock<_Mutex>::try_lock()
217{
218 if (__m_ == nullptr)
219 __throw_system_error(EPERM, "unique_lock::try_lock: references null mutex");
220 if (__owns_)
221 __throw_system_error(EDEADLK, "unique_lock::try_lock: already locked");
222 __owns_ = __m_->try_lock();
223 return __owns_;
224}
225
226template <class _Mutex>
227template <class _Rep, class _Period>
228bool
229unique_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
230{
231 if (__m_ == nullptr)
232 __throw_system_error(EPERM, "unique_lock::try_lock_for: references null mutex");
233 if (__owns_)
234 __throw_system_error(EDEADLK, "unique_lock::try_lock_for: already locked");
235 __owns_ = __m_->try_lock_for(__d);
236 return __owns_;
237}
238
239template <class _Mutex>
240template <class _Clock, class _Duration>
241bool
242unique_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
243{
244 if (__m_ == nullptr)
245 __throw_system_error(EPERM, "unique_lock::try_lock_until: references null mutex");
246 if (__owns_)
247 __throw_system_error(EDEADLK, "unique_lock::try_lock_until: already locked");
248 __owns_ = __m_->try_lock_until(__t);
249 return __owns_;
250}
251
252template <class _Mutex>
253void
254unique_lock<_Mutex>::unlock()
255{
256 if (!__owns_)
257 __throw_system_error(EPERM, "unique_lock::unlock: not locked");
258 __m_->unlock();
259 __owns_ = false;
260}
261
262template <class _Mutex>
263inline _LIBCPP_INLINE_VISIBILITY
264void
265swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) _NOEXCEPT
266 {__x.swap(__y);}
267
268//enum class cv_status
269_LIBCPP_DECLARE_STRONG_ENUM(cv_status)
270{
271 no_timeout,
272 timeout
273};
274_LIBCPP_DECLARE_STRONG_ENUM_EPILOG(cv_status)
275
276class _LIBCPP_TYPE_VIS condition_variable
277{
278 __libcpp_condvar_t __cv_ = _LIBCPP_CONDVAR_INITIALIZER;
279public:
280 _LIBCPP_INLINE_VISIBILITY
281 _LIBCPP_CONSTEXPR condition_variable() _NOEXCEPT = default;
282
283#ifdef _LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION
284 ~condition_variable() = default;
285#else
286 ~condition_variable();
287#endif
288
289 condition_variable(const condition_variable&) = delete;
290 condition_variable& operator=(const condition_variable&) = delete;
291
292 void notify_one() _NOEXCEPT;
293 void notify_all() _NOEXCEPT;
294
295 void wait(unique_lock<mutex>& __lk) _NOEXCEPT;
296 template <class _Predicate>
297 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
298 void wait(unique_lock<mutex>& __lk, _Predicate __pred);
299
300 template <class _Clock, class _Duration>
301 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
302 cv_status
303 wait_until(unique_lock<mutex>& __lk,
304 const chrono::time_point<_Clock, _Duration>& __t);
305
306 template <class _Clock, class _Duration, class _Predicate>
307 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
308 bool
309 wait_until(unique_lock<mutex>& __lk,
310 const chrono::time_point<_Clock, _Duration>& __t,
311 _Predicate __pred);
312
313 template <class _Rep, class _Period>
314 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
315 cv_status
316 wait_for(unique_lock<mutex>& __lk,
317 const chrono::duration<_Rep, _Period>& __d);
318
319 template <class _Rep, class _Period, class _Predicate>
320 bool
321 _LIBCPP_INLINE_VISIBILITY
322 wait_for(unique_lock<mutex>& __lk,
323 const chrono::duration<_Rep, _Period>& __d,
324 _Predicate __pred);
325
326 typedef __libcpp_condvar_t* native_handle_type;
327 _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;}
328
329private:
330 void __do_timed_wait(unique_lock<mutex>& __lk,
331 chrono::time_point<chrono::system_clock, chrono::nanoseconds>) _NOEXCEPT;
332#if defined(_LIBCPP_HAS_COND_CLOCKWAIT)
333 void __do_timed_wait(unique_lock<mutex>& __lk,
334 chrono::time_point<chrono::steady_clock, chrono::nanoseconds>) _NOEXCEPT;
335#endif
336 template <class _Clock>
337 void __do_timed_wait(unique_lock<mutex>& __lk,
338 chrono::time_point<_Clock, chrono::nanoseconds>) _NOEXCEPT;
339};
340#endif // !_LIBCPP_HAS_NO_THREADS
341
342template <class _Rep, class _Period>
343inline _LIBCPP_INLINE_VISIBILITY
344typename enable_if
345<
346 is_floating_point<_Rep>::value,
347 chrono::nanoseconds
348>::type
349__safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d)
350{
351 using namespace chrono;
352 using __ratio = ratio_divide<_Period, nano>;
353 using __ns_rep = nanoseconds::rep;
354 _Rep __result_float = __d.count() * __ratio::num / __ratio::den;
355
356 _Rep __result_max = numeric_limits<__ns_rep>::max();
357 if (__result_float >= __result_max) {
358 return nanoseconds::max();
359 }
360
361 _Rep __result_min = numeric_limits<__ns_rep>::min();
362 if (__result_float <= __result_min) {
363 return nanoseconds::min();
364 }
365
366 return nanoseconds(static_cast<__ns_rep>(__result_float));
367}
368
369template <class _Rep, class _Period>
370inline _LIBCPP_INLINE_VISIBILITY
371typename enable_if
372<
373 !is_floating_point<_Rep>::value,
374 chrono::nanoseconds
375>::type
376__safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d)
377{
378 using namespace chrono;
379 if (__d.count() == 0) {
380 return nanoseconds(0);
381 }
382
383 using __ratio = ratio_divide<_Period, nano>;
384 using __ns_rep = nanoseconds::rep;
385 __ns_rep __result_max = std::numeric_limits<__ns_rep>::max();
386 if (__d.count() > 0 && __d.count() > __result_max / __ratio::num) {
387 return nanoseconds::max();
388 }
389
390 __ns_rep __result_min = std::numeric_limits<__ns_rep>::min();
391 if (__d.count() < 0 && __d.count() < __result_min / __ratio::num) {
392 return nanoseconds::min();
393 }
394
395 __ns_rep __result = __d.count() * __ratio::num / __ratio::den;
396 if (__result == 0) {
397 return nanoseconds(1);
398 }
399
400 return nanoseconds(__result);
401}
402
403#ifndef _LIBCPP_HAS_NO_THREADS
404template <class _Predicate>
405void
406condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred)
407{
408 while (!__pred())
409 wait(__lk);
410}
411
412template <class _Clock, class _Duration>
413cv_status
414condition_variable::wait_until(unique_lock<mutex>& __lk,
415 const chrono::time_point<_Clock, _Duration>& __t)
416{
417 using namespace chrono;
418 using __clock_tp_ns = time_point<_Clock, nanoseconds>;
419
420 typename _Clock::time_point __now = _Clock::now();
421 if (__t <= __now)
422 return cv_status::timeout;
423
424 __clock_tp_ns __t_ns = __clock_tp_ns(__safe_nanosecond_cast(__t.time_since_epoch()));
425
426 __do_timed_wait(__lk, __t_ns);
427 return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
428}
429
430template <class _Clock, class _Duration, class _Predicate>
431bool
432condition_variable::wait_until(unique_lock<mutex>& __lk,
433 const chrono::time_point<_Clock, _Duration>& __t,
434 _Predicate __pred)
435{
436 while (!__pred())
437 {
438 if (wait_until(__lk, __t) == cv_status::timeout)
439 return __pred();
440 }
441 return true;
442}
443
444template <class _Rep, class _Period>
445cv_status
446condition_variable::wait_for(unique_lock<mutex>& __lk,
447 const chrono::duration<_Rep, _Period>& __d)
448{
449 using namespace chrono;
450 if (__d <= __d.zero())
451 return cv_status::timeout;
452 using __ns_rep = nanoseconds::rep;
453 steady_clock::time_point __c_now = steady_clock::now();
454
455#if defined(_LIBCPP_HAS_COND_CLOCKWAIT)
456 using __clock_tp_ns = time_point<steady_clock, nanoseconds>;
457 __ns_rep __now_count_ns = __safe_nanosecond_cast(__c_now.time_since_epoch()).count();
458#else
459 using __clock_tp_ns = time_point<system_clock, nanoseconds>;
460 __ns_rep __now_count_ns = __safe_nanosecond_cast(system_clock::now().time_since_epoch()).count();
461#endif
462
463 __ns_rep __d_ns_count = __safe_nanosecond_cast(__d).count();
464
465 if (__now_count_ns > numeric_limits<__ns_rep>::max() - __d_ns_count) {
466 __do_timed_wait(__lk, __clock_tp_ns::max());
467 } else {
468 __do_timed_wait(__lk, __clock_tp_ns(nanoseconds(__now_count_ns + __d_ns_count)));
469 }
470
471 return steady_clock::now() - __c_now < __d ? cv_status::no_timeout :
472 cv_status::timeout;
473}
474
475template <class _Rep, class _Period, class _Predicate>
476inline
477bool
478condition_variable::wait_for(unique_lock<mutex>& __lk,
479 const chrono::duration<_Rep, _Period>& __d,
480 _Predicate __pred)
481{
482 return wait_until(__lk, chrono::steady_clock::now() + __d,
483 _VSTD::move(__pred));
484}
485
486#if defined(_LIBCPP_HAS_COND_CLOCKWAIT)
487inline
488void
489condition_variable::__do_timed_wait(unique_lock<mutex>& __lk,
490 chrono::time_point<chrono::steady_clock, chrono::nanoseconds> __tp) _NOEXCEPT
491{
492 using namespace chrono;
493 if (!__lk.owns_lock())
494 __throw_system_error(EPERM,
495 "condition_variable::timed wait: mutex not locked");
496 nanoseconds __d = __tp.time_since_epoch();
497 timespec __ts;
498 seconds __s = duration_cast<seconds>(__d);
499 using __ts_sec = decltype(__ts.tv_sec);
500 const __ts_sec __ts_sec_max = numeric_limits<__ts_sec>::max();
501 if (__s.count() < __ts_sec_max)
502 {
503 __ts.tv_sec = static_cast<__ts_sec>(__s.count());
504 __ts.tv_nsec = (__d - __s).count();
505 }
506 else
507 {
508 __ts.tv_sec = __ts_sec_max;
509 __ts.tv_nsec = giga::num - 1;
510 }
511 int __ec = pthread_cond_clockwait(&__cv_, __lk.mutex()->native_handle(), CLOCK_MONOTONIC, &__ts);
512 if (__ec != 0 && __ec != ETIMEDOUT)
513 __throw_system_error(__ec, "condition_variable timed_wait failed");
514}
515#endif // _LIBCPP_HAS_COND_CLOCKWAIT
516
517template <class _Clock>
518inline
519void
520condition_variable::__do_timed_wait(unique_lock<mutex>& __lk,
521 chrono::time_point<_Clock, chrono::nanoseconds> __tp) _NOEXCEPT
522{
523 wait_for(__lk, __tp - _Clock::now());
524}
525
526#endif // !_LIBCPP_HAS_NO_THREADS
527
528_LIBCPP_END_NAMESPACE_STD
529
530_LIBCPP_POP_MACROS
531
532#endif // _LIBCPP___MUTEX_BASE
533