Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/libcxx/include/__condition_variable/condition_variable.h
35234 views
1
//===----------------------------------------------------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#ifndef _LIBCPP___CONDITION_VARIABLE_CONDITION_VARIABLE_H
10
#define _LIBCPP___CONDITION_VARIABLE_CONDITION_VARIABLE_H
11
12
#include <__chrono/duration.h>
13
#include <__chrono/steady_clock.h>
14
#include <__chrono/system_clock.h>
15
#include <__chrono/time_point.h>
16
#include <__config>
17
#include <__mutex/mutex.h>
18
#include <__mutex/unique_lock.h>
19
#include <__system_error/system_error.h>
20
#include <__thread/support.h>
21
#include <__type_traits/enable_if.h>
22
#include <__type_traits/is_floating_point.h>
23
#include <__utility/move.h>
24
#include <limits>
25
#include <ratio>
26
27
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
28
# pragma GCC system_header
29
#endif
30
31
_LIBCPP_PUSH_MACROS
32
#include <__undef_macros>
33
34
_LIBCPP_BEGIN_NAMESPACE_STD
35
36
#ifndef _LIBCPP_HAS_NO_THREADS
37
38
// enum class cv_status
39
_LIBCPP_DECLARE_STRONG_ENUM(cv_status){no_timeout, timeout};
40
_LIBCPP_DECLARE_STRONG_ENUM_EPILOG(cv_status)
41
42
class _LIBCPP_EXPORTED_FROM_ABI condition_variable {
43
__libcpp_condvar_t __cv_ = _LIBCPP_CONDVAR_INITIALIZER;
44
45
public:
46
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR condition_variable() _NOEXCEPT = default;
47
48
# ifdef _LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION
49
~condition_variable() = default;
50
# else
51
~condition_variable();
52
# endif
53
54
condition_variable(const condition_variable&) = delete;
55
condition_variable& operator=(const condition_variable&) = delete;
56
57
void notify_one() _NOEXCEPT;
58
void notify_all() _NOEXCEPT;
59
60
void wait(unique_lock<mutex>& __lk) _NOEXCEPT;
61
template <class _Predicate>
62
_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS void wait(unique_lock<mutex>& __lk, _Predicate __pred);
63
64
template <class _Clock, class _Duration>
65
_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS cv_status
66
wait_until(unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t);
67
68
template <class _Clock, class _Duration, class _Predicate>
69
_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool
70
wait_until(unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t, _Predicate __pred);
71
72
template <class _Rep, class _Period>
73
_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS cv_status
74
wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d);
75
76
template <class _Rep, class _Period, class _Predicate>
77
bool _LIBCPP_HIDE_FROM_ABI
78
wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d, _Predicate __pred);
79
80
typedef __libcpp_condvar_t* native_handle_type;
81
_LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return &__cv_; }
82
83
private:
84
void
85
__do_timed_wait(unique_lock<mutex>& __lk, chrono::time_point<chrono::system_clock, chrono::nanoseconds>) _NOEXCEPT;
86
# if defined(_LIBCPP_HAS_COND_CLOCKWAIT)
87
_LIBCPP_HIDE_FROM_ABI void
88
__do_timed_wait(unique_lock<mutex>& __lk, chrono::time_point<chrono::steady_clock, chrono::nanoseconds>) _NOEXCEPT;
89
# endif
90
template <class _Clock>
91
_LIBCPP_HIDE_FROM_ABI void
92
__do_timed_wait(unique_lock<mutex>& __lk, chrono::time_point<_Clock, chrono::nanoseconds>) _NOEXCEPT;
93
};
94
#endif // !_LIBCPP_HAS_NO_THREADS
95
96
template <class _Rep, class _Period, __enable_if_t<is_floating_point<_Rep>::value, int> = 0>
97
inline _LIBCPP_HIDE_FROM_ABI chrono::nanoseconds __safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d) {
98
using namespace chrono;
99
using __ratio = ratio_divide<_Period, nano>;
100
using __ns_rep = nanoseconds::rep;
101
_Rep __result_float = __d.count() * __ratio::num / __ratio::den;
102
103
_Rep __result_max = numeric_limits<__ns_rep>::max();
104
if (__result_float >= __result_max) {
105
return nanoseconds::max();
106
}
107
108
_Rep __result_min = numeric_limits<__ns_rep>::min();
109
if (__result_float <= __result_min) {
110
return nanoseconds::min();
111
}
112
113
return nanoseconds(static_cast<__ns_rep>(__result_float));
114
}
115
116
template <class _Rep, class _Period, __enable_if_t<!is_floating_point<_Rep>::value, int> = 0>
117
inline _LIBCPP_HIDE_FROM_ABI chrono::nanoseconds __safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d) {
118
using namespace chrono;
119
if (__d.count() == 0) {
120
return nanoseconds(0);
121
}
122
123
using __ratio = ratio_divide<_Period, nano>;
124
using __ns_rep = nanoseconds::rep;
125
__ns_rep __result_max = numeric_limits<__ns_rep>::max();
126
if (__d.count() > 0 && __d.count() > __result_max / __ratio::num) {
127
return nanoseconds::max();
128
}
129
130
__ns_rep __result_min = numeric_limits<__ns_rep>::min();
131
if (__d.count() < 0 && __d.count() < __result_min / __ratio::num) {
132
return nanoseconds::min();
133
}
134
135
__ns_rep __result = __d.count() * __ratio::num / __ratio::den;
136
if (__result == 0) {
137
return nanoseconds(1);
138
}
139
140
return nanoseconds(__result);
141
}
142
143
#ifndef _LIBCPP_HAS_NO_THREADS
144
template <class _Predicate>
145
void condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred) {
146
while (!__pred())
147
wait(__lk);
148
}
149
150
template <class _Clock, class _Duration>
151
cv_status condition_variable::wait_until(unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t) {
152
using namespace chrono;
153
using __clock_tp_ns = time_point<_Clock, nanoseconds>;
154
155
typename _Clock::time_point __now = _Clock::now();
156
if (__t <= __now)
157
return cv_status::timeout;
158
159
__clock_tp_ns __t_ns = __clock_tp_ns(std::__safe_nanosecond_cast(__t.time_since_epoch()));
160
161
__do_timed_wait(__lk, __t_ns);
162
return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
163
}
164
165
template <class _Clock, class _Duration, class _Predicate>
166
bool condition_variable::wait_until(
167
unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t, _Predicate __pred) {
168
while (!__pred()) {
169
if (wait_until(__lk, __t) == cv_status::timeout)
170
return __pred();
171
}
172
return true;
173
}
174
175
template <class _Rep, class _Period>
176
cv_status condition_variable::wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d) {
177
using namespace chrono;
178
if (__d <= __d.zero())
179
return cv_status::timeout;
180
using __ns_rep = nanoseconds::rep;
181
steady_clock::time_point __c_now = steady_clock::now();
182
183
# if defined(_LIBCPP_HAS_COND_CLOCKWAIT)
184
using __clock_tp_ns = time_point<steady_clock, nanoseconds>;
185
__ns_rep __now_count_ns = std::__safe_nanosecond_cast(__c_now.time_since_epoch()).count();
186
# else
187
using __clock_tp_ns = time_point<system_clock, nanoseconds>;
188
__ns_rep __now_count_ns = std::__safe_nanosecond_cast(system_clock::now().time_since_epoch()).count();
189
# endif
190
191
__ns_rep __d_ns_count = std::__safe_nanosecond_cast(__d).count();
192
193
if (__now_count_ns > numeric_limits<__ns_rep>::max() - __d_ns_count) {
194
__do_timed_wait(__lk, __clock_tp_ns::max());
195
} else {
196
__do_timed_wait(__lk, __clock_tp_ns(nanoseconds(__now_count_ns + __d_ns_count)));
197
}
198
199
return steady_clock::now() - __c_now < __d ? cv_status::no_timeout : cv_status::timeout;
200
}
201
202
template <class _Rep, class _Period, class _Predicate>
203
inline bool
204
condition_variable::wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d, _Predicate __pred) {
205
return wait_until(__lk, chrono::steady_clock::now() + __d, std::move(__pred));
206
}
207
208
# if defined(_LIBCPP_HAS_COND_CLOCKWAIT)
209
inline void condition_variable::__do_timed_wait(
210
unique_lock<mutex>& __lk, chrono::time_point<chrono::steady_clock, chrono::nanoseconds> __tp) _NOEXCEPT {
211
using namespace chrono;
212
if (!__lk.owns_lock())
213
__throw_system_error(EPERM, "condition_variable::timed wait: mutex not locked");
214
nanoseconds __d = __tp.time_since_epoch();
215
timespec __ts;
216
seconds __s = duration_cast<seconds>(__d);
217
using __ts_sec = decltype(__ts.tv_sec);
218
const __ts_sec __ts_sec_max = numeric_limits<__ts_sec>::max();
219
if (__s.count() < __ts_sec_max) {
220
__ts.tv_sec = static_cast<__ts_sec>(__s.count());
221
__ts.tv_nsec = (__d - __s).count();
222
} else {
223
__ts.tv_sec = __ts_sec_max;
224
__ts.tv_nsec = giga::num - 1;
225
}
226
int __ec = pthread_cond_clockwait(&__cv_, __lk.mutex()->native_handle(), CLOCK_MONOTONIC, &__ts);
227
if (__ec != 0 && __ec != ETIMEDOUT)
228
__throw_system_error(__ec, "condition_variable timed_wait failed");
229
}
230
# endif // _LIBCPP_HAS_COND_CLOCKWAIT
231
232
template <class _Clock>
233
inline void condition_variable::__do_timed_wait(unique_lock<mutex>& __lk,
234
chrono::time_point<_Clock, chrono::nanoseconds> __tp) _NOEXCEPT {
235
wait_for(__lk, __tp - _Clock::now());
236
}
237
238
#endif // _LIBCPP_HAS_NO_THREADS
239
240
_LIBCPP_END_NAMESPACE_STD
241
242
_LIBCPP_POP_MACROS
243
244
#endif // _LIBCPP___CONDITION_VARIABLE_CONDITION_VARIABLE_H
245
246