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