]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - include/__mutex_base
Vendor import of stripped libc++ trunk r375505, the last commit before
[FreeBSD/FreeBSD.git] / include / __mutex_base
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
32 #ifndef _LIBCPP_THREAD_SAFETY_ANNOTATION
33 #  ifdef _LIBCPP_HAS_THREAD_SAFETY_ANNOTATIONS
34 #    define _LIBCPP_THREAD_SAFETY_ANNOTATION(x) __attribute__((x))
35 #  else
36 #    define _LIBCPP_THREAD_SAFETY_ANNOTATION(x)
37 #  endif
38 #endif  // _LIBCPP_THREAD_SAFETY_ANNOTATION
39
40
41 class _LIBCPP_TYPE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("mutex")) mutex
42 {
43     __libcpp_mutex_t __m_ = _LIBCPP_MUTEX_INITIALIZER;
44
45 public:
46     _LIBCPP_INLINE_VISIBILITY
47     _LIBCPP_CONSTEXPR mutex() = default;
48
49     mutex(const mutex&) = delete;
50     mutex& operator=(const mutex&) = delete;
51
52 #if defined(_LIBCPP_HAS_TRIVIAL_MUTEX_DESTRUCTION)
53     ~mutex() = default;
54 #else
55     ~mutex() _NOEXCEPT;
56 #endif
57
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());
61
62     typedef __libcpp_mutex_t* native_handle_type;
63     _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;}
64 };
65
66 static_assert(is_nothrow_default_constructible<mutex>::value,
67               "the default constructor for std::mutex must be nothrow");
68
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; };
72
73 #if defined(_LIBCPP_CXX03_LANG) || defined(_LIBCPP_BUILDING_LIBRARY)
74
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;
78
79 #else
80
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();
84
85 #endif
86
87 template <class _Mutex>
88 class _LIBCPP_TEMPLATE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable)
89 lock_guard
90 {
91 public:
92     typedef _Mutex mutex_type;
93
94 private:
95     mutex_type& __m_;
96 public:
97
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();}
101
102     _LIBCPP_NODISCARD_EXT _LIBCPP_INLINE_VISIBILITY
103     lock_guard(mutex_type& __m, adopt_lock_t) _LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m))
104         : __m_(__m) {}
105     _LIBCPP_INLINE_VISIBILITY
106     ~lock_guard() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) {__m_.unlock();}
107
108 private:
109     lock_guard(lock_guard const&) _LIBCPP_EQUAL_DELETE;
110     lock_guard& operator=(lock_guard const&) _LIBCPP_EQUAL_DELETE;
111 };
112
113 template <class _Mutex>
114 class _LIBCPP_TEMPLATE_VIS unique_lock
115 {
116 public:
117     typedef _Mutex mutex_type;
118
119 private:
120     mutex_type* __m_;
121     bool __owns_;
122
123 public:
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
147     ~unique_lock()
148     {
149         if (__owns_)
150             __m_->unlock();
151     }
152
153 private:
154     unique_lock(unique_lock const&); // = delete;
155     unique_lock& operator=(unique_lock const&); // = delete;
156
157 public:
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
165         {
166             if (__owns_)
167                 __m_->unlock();
168             __m_ = __u.__m_;
169             __owns_ = __u.__owns_;
170             __u.__m_ = nullptr;
171             __u.__owns_ = false;
172             return *this;
173         }
174
175 #endif  // _LIBCPP_CXX03_LANG
176
177     void lock();
178     bool try_lock();
179
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);
184
185     void unlock();
186
187     _LIBCPP_INLINE_VISIBILITY
188     void swap(unique_lock& __u) _NOEXCEPT
189     {
190         _VSTD::swap(__m_, __u.__m_);
191         _VSTD::swap(__owns_, __u.__owns_);
192     }
193     _LIBCPP_INLINE_VISIBILITY
194     mutex_type* release() _NOEXCEPT
195     {
196         mutex_type* __m = __m_;
197         __m_ = nullptr;
198         __owns_ = false;
199         return __m;
200     }
201
202     _LIBCPP_INLINE_VISIBILITY
203     bool owns_lock() const _NOEXCEPT {return __owns_;}
204     _LIBCPP_INLINE_VISIBILITY
205     _LIBCPP_EXPLICIT
206         operator bool () const _NOEXCEPT {return __owns_;}
207     _LIBCPP_INLINE_VISIBILITY
208     mutex_type* mutex() const _NOEXCEPT {return __m_;}
209 };
210
211 template <class _Mutex>
212 void
213 unique_lock<_Mutex>::lock()
214 {
215     if (__m_ == nullptr)
216         __throw_system_error(EPERM, "unique_lock::lock: references null mutex");
217     if (__owns_)
218         __throw_system_error(EDEADLK, "unique_lock::lock: already locked");
219     __m_->lock();
220     __owns_ = true;
221 }
222
223 template <class _Mutex>
224 bool
225 unique_lock<_Mutex>::try_lock()
226 {
227     if (__m_ == nullptr)
228         __throw_system_error(EPERM, "unique_lock::try_lock: references null mutex");
229     if (__owns_)
230         __throw_system_error(EDEADLK, "unique_lock::try_lock: already locked");
231     __owns_ = __m_->try_lock();
232     return __owns_;
233 }
234
235 template <class _Mutex>
236 template <class _Rep, class _Period>
237 bool
238 unique_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
239 {
240     if (__m_ == nullptr)
241         __throw_system_error(EPERM, "unique_lock::try_lock_for: references null mutex");
242     if (__owns_)
243         __throw_system_error(EDEADLK, "unique_lock::try_lock_for: already locked");
244     __owns_ = __m_->try_lock_for(__d);
245     return __owns_;
246 }
247
248 template <class _Mutex>
249 template <class _Clock, class _Duration>
250 bool
251 unique_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
252 {
253     if (__m_ == nullptr)
254         __throw_system_error(EPERM, "unique_lock::try_lock_until: references null mutex");
255     if (__owns_)
256         __throw_system_error(EDEADLK, "unique_lock::try_lock_until: already locked");
257     __owns_ = __m_->try_lock_until(__t);
258     return __owns_;
259 }
260
261 template <class _Mutex>
262 void
263 unique_lock<_Mutex>::unlock()
264 {
265     if (!__owns_)
266         __throw_system_error(EPERM, "unique_lock::unlock: not locked");
267     __m_->unlock();
268     __owns_ = false;
269 }
270
271 template <class _Mutex>
272 inline _LIBCPP_INLINE_VISIBILITY
273 void
274 swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) _NOEXCEPT
275     {__x.swap(__y);}
276
277 //enum class cv_status
278 _LIBCPP_DECLARE_STRONG_ENUM(cv_status)
279 {
280     no_timeout,
281     timeout
282 };
283 _LIBCPP_DECLARE_STRONG_ENUM_EPILOG(cv_status)
284
285 class _LIBCPP_TYPE_VIS condition_variable
286 {
287     __libcpp_condvar_t __cv_ = _LIBCPP_CONDVAR_INITIALIZER;
288 public:
289     _LIBCPP_INLINE_VISIBILITY
290     _LIBCPP_CONSTEXPR condition_variable() _NOEXCEPT = default;
291
292 #ifdef _LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION
293     ~condition_variable() = default;
294 #else
295     ~condition_variable();
296 #endif
297
298     condition_variable(const condition_variable&) = delete;
299     condition_variable& operator=(const condition_variable&) = delete;
300
301     void notify_one() _NOEXCEPT;
302     void notify_all() _NOEXCEPT;
303
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);
308
309     template <class _Clock, class _Duration>
310         _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
311         cv_status
312         wait_until(unique_lock<mutex>& __lk,
313                    const chrono::time_point<_Clock, _Duration>& __t);
314
315     template <class _Clock, class _Duration, class _Predicate>
316         _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
317         bool
318         wait_until(unique_lock<mutex>& __lk,
319                    const chrono::time_point<_Clock, _Duration>& __t,
320                    _Predicate __pred);
321
322     template <class _Rep, class _Period>
323         _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
324         cv_status
325         wait_for(unique_lock<mutex>& __lk,
326                  const chrono::duration<_Rep, _Period>& __d);
327
328     template <class _Rep, class _Period, class _Predicate>
329         bool
330         _LIBCPP_INLINE_VISIBILITY
331         wait_for(unique_lock<mutex>& __lk,
332                  const chrono::duration<_Rep, _Period>& __d,
333                  _Predicate __pred);
334
335     typedef __libcpp_condvar_t* native_handle_type;
336     _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;}
337
338 private:
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;
344 #endif
345     template <class _Clock>
346     void __do_timed_wait(unique_lock<mutex>& __lk,
347        chrono::time_point<_Clock, chrono::nanoseconds>) _NOEXCEPT;
348 };
349 #endif // !_LIBCPP_HAS_NO_THREADS
350
351 template <class _Rep, class _Period>
352 inline _LIBCPP_INLINE_VISIBILITY
353 typename enable_if
354 <
355     is_floating_point<_Rep>::value,
356     chrono::nanoseconds
357 >::type
358 __safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d)
359 {
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;
364
365     _Rep __result_max = numeric_limits<__ns_rep>::max();
366     if (__result_float >= __result_max) {
367         return nanoseconds::max();
368     }
369
370     _Rep __result_min = numeric_limits<__ns_rep>::min();
371     if (__result_float <= __result_min) {
372         return nanoseconds::min();
373     }
374
375     return nanoseconds(static_cast<__ns_rep>(__result_float));
376 }
377
378 template <class _Rep, class _Period>
379 inline _LIBCPP_INLINE_VISIBILITY
380 typename enable_if
381 <
382     !is_floating_point<_Rep>::value,
383     chrono::nanoseconds
384 >::type
385 __safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d)
386 {
387     using namespace chrono;
388     if (__d.count() == 0) {
389         return nanoseconds(0);
390     }
391
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();
397     }
398
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();
402     }
403
404     __ns_rep __result = __d.count() * __ratio::num / __ratio::den;
405     if (__result == 0) {
406         return nanoseconds(1);
407     }
408
409     return nanoseconds(__result);
410 }
411
412 #ifndef _LIBCPP_HAS_NO_THREADS
413 template <class _Predicate>
414 void
415 condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred)
416 {
417     while (!__pred())
418         wait(__lk);
419 }
420
421 template <class _Clock, class _Duration>
422 cv_status
423 condition_variable::wait_until(unique_lock<mutex>& __lk,
424                                const chrono::time_point<_Clock, _Duration>& __t)
425 {
426     using namespace chrono;
427     using __clock_tp_ns = time_point<_Clock, nanoseconds>;
428
429     typename _Clock::time_point __now = _Clock::now();
430     if (__t <= __now)
431         return cv_status::timeout;
432
433     __clock_tp_ns __t_ns = __clock_tp_ns(__safe_nanosecond_cast(__t.time_since_epoch()));
434
435     __do_timed_wait(__lk, __t_ns);
436     return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
437 }
438
439 template <class _Clock, class _Duration, class _Predicate>
440 bool
441 condition_variable::wait_until(unique_lock<mutex>& __lk,
442                    const chrono::time_point<_Clock, _Duration>& __t,
443                    _Predicate __pred)
444 {
445     while (!__pred())
446     {
447         if (wait_until(__lk, __t) == cv_status::timeout)
448             return __pred();
449     }
450     return true;
451 }
452
453 template <class _Rep, class _Period>
454 cv_status
455 condition_variable::wait_for(unique_lock<mutex>& __lk,
456                              const chrono::duration<_Rep, _Period>& __d)
457 {
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();
463
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();
467 #else
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();
470 #endif
471
472     __ns_rep __d_ns_count = __safe_nanosecond_cast(__d).count();
473
474     if (__now_count_ns > numeric_limits<__ns_rep>::max() - __d_ns_count) {
475         __do_timed_wait(__lk, __clock_tp_ns::max());
476     } else {
477         __do_timed_wait(__lk, __clock_tp_ns(nanoseconds(__now_count_ns + __d_ns_count)));
478     }
479
480     return steady_clock::now() - __c_now < __d ? cv_status::no_timeout :
481                                                  cv_status::timeout;
482 }
483
484 template <class _Rep, class _Period, class _Predicate>
485 inline
486 bool
487 condition_variable::wait_for(unique_lock<mutex>& __lk,
488                              const chrono::duration<_Rep, _Period>& __d,
489                              _Predicate __pred)
490 {
491     return wait_until(__lk, chrono::steady_clock::now() + __d,
492                       _VSTD::move(__pred));
493 }
494
495 #if defined(_LIBCPP_HAS_COND_CLOCKWAIT)
496 inline
497 void
498 condition_variable::__do_timed_wait(unique_lock<mutex>& __lk,
499      chrono::time_point<chrono::steady_clock, chrono::nanoseconds> __tp) _NOEXCEPT
500 {
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();
506     timespec __ts;
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)
511     {
512         __ts.tv_sec = static_cast<__ts_sec>(__s.count());
513         __ts.tv_nsec = (__d - __s).count();
514     }
515     else
516     {
517         __ts.tv_sec = __ts_sec_max;
518         __ts.tv_nsec = giga::num - 1;
519     }
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");
523 }
524 #endif // _LIBCPP_HAS_COND_CLOCKWAIT
525
526 template <class _Clock>
527 inline
528 void
529 condition_variable::__do_timed_wait(unique_lock<mutex>& __lk,
530      chrono::time_point<_Clock, chrono::nanoseconds> __tp) _NOEXCEPT
531 {
532     wait_for(__lk, __tp - _Clock::now());
533 }
534
535 #endif // !_LIBCPP_HAS_NO_THREADS
536
537 _LIBCPP_END_NAMESPACE_STD
538
539 _LIBCPP_POP_MACROS
540
541 #endif  // _LIBCPP___MUTEX_BASE