1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
|
# cython: preliminary_late_includes_cy28=True
from libcpp.mutex cimport unique_lock, mutex
from libcpp.stop_token cimport stop_token
from libcpp cimport bool as _bool
cdef extern from "<condition_variable>" namespace "std" nogil:
cdef enum class cv_status:
no_timeout
timeout
cdef cppclass condition_variable:
cppclass native_handle_type:
pass
condition_variable() except+
void notify_one() noexcept
void notify_all() noexcept
# Be very wary of calling any of the wait functions with the GIL held.
# Also be a little wary of re-acquiring the GIL in the predicate
# (because in principle it may deadlock with the lock).
# The predicate should not require the GIL or throw Python exceptions.
void wait(unique_lock[mutex]& lock) except+
void wait[Predicate](unique_lock[mutex]& lock, Predicate pred) except+
cv_status wait_for[Duration](unique_lock[mutex]& lock, const Duration &duration) except+
_bool wait_for[Duration, Predicate](unique_lock[mutex]& lock, const Duration &duration, Predicate pred) except+
cv_status wait_until[TimePoint](unique_lock[mutex]& lock, const TimePoint& time_point) except+
_bool wait_until[TimePoint, Predicate](unique_lock[mutex]& lock, const TimePoint& time_point, Predicate pred) except+
native_handle_type native_handle() except+
cdef cppclass condition_variable_any:
condition_variable_any() except+
void notify_one() noexcept
void notify_all() noexcept
# Be very wary of calling any of the wait functions with the GIL held.
# Also be a little wary of re-acquiring the GIL in the predicate
# (because in principle it may deadlock with the lock).
# The predicate should not require the GIL or throw Python exceptions.
void wait[Lock](Lock& lock) except+
void wait[Lock, Predicate](Lock& lock, Predicate pred) except+
_bool wait[Lock, Predicate](Lock& lock, stop_token stoken, Predicate pred) except+
cv_status wait_for[Lock, Duration](Lock& lock, const Duration &duration) except+
_bool wait_for[Lock, Duration, Predicate](Lock& lock, const Duration &duration, Predicate pred) except+
_bool wait_for[Lock, Duration, Predicate](Lock& lock, stop_token stoken, const Duration &duration, Predicate pred) except+
cv_status wait_until[Lock, TimePoint](Lock& lock, const TimePoint &time_point) except+
_bool wait_until[Lock, TimePoint, Predicate](Lock& lock, const TimePoint &time_point, Predicate pred) except+
_bool wait_until[Lock, TimePoint, Predicate](Lock& lock, stop_token stoken, const TimePoint &time_point, Predicate pred) except+
void notify_all_at_thread_exit(condition_variable& cv, unique_lock[mutex]& lock) except+
cdef inline void _dummy_force_utility_code_inclusion() nogil:
with nogil:
pass
cdef extern from *:
"""
namespace {
template <typename Lock>
void __Pyx_libcpp_cv_relock_at_end(Lock& lock, __Pyx_UnknownThreadState &ts) {
if (__Pyx_UnknownThreadStateMayHaveHadGil(ts)) {
lock.unlock(); // unlocking should not throw
__Pyx_RestoreUnknownThread(ts);
// ensure_gil, release_gil and py_safe_std_lock are defined in mutex.pdx
PyGILState_STATE gil_state = __pyx_libcpp_mutex_limited_api_ensure_gil();
auto cleanup = __pyx_make_libcpp_mutex_cleanup_on_exit([&gil_state](){
__pyx_libcpp_mutex_limited_api_release_gil(gil_state);
});
__pyx_py_safe_std_lock(lock);
} else {
__Pyx_RestoreUnknownThread(ts);
}
}
template <typename Lock, typename Predicate>
class __Pyx_libcpp_cv_WrappedPySafePredicate {
Lock *lock;
Predicate *pred;
__Pyx_UnknownThreadState *ts;
public:
__Pyx_libcpp_cv_WrappedPySafePredicate(Lock *l, Predicate *p, __Pyx_UnknownThreadState *ts)
: lock(l)
, pred(p)
, ts(ts)
{}
bool operator()() const {
PyGILState_STATE gil_state;
lock->unlock();
int had_gil_on_call = __Pyx_UnknownThreadStateDefinitelyHadGil(*ts);
if (had_gil_on_call) {
__Pyx_RestoreUnknownThread(*ts);
} else {
gil_state = PyGILState_Ensure();
}
auto release_gil = __pyx_make_libcpp_mutex_cleanup_on_exit(
[&]() {
if (had_gil_on_call) {
*ts = __Pyx_SaveUnknownThread();
} else {
PyGILState_Release(gil_state);
}
});
__pyx_py_safe_std_lock(*lock);
// No need to unlock - the condition variable is responsible for that and it shouldn't be possible
// to deadlock from here.
bool result = (*pred)();
if (PyErr_Occurred()) {
// The PyErr_Occurred check in __Pyx_CppExn2PyErr will deal with
// presenting the exception to Cython.
throw std::exception();
}
return result;
}
};
template <typename Lock, typename Predicate>
__Pyx_libcpp_cv_WrappedPySafePredicate<Lock, Predicate> __Pyx_libcpp_cv_py_safe_wrap_predicate(Lock* lock, Predicate* pred, __Pyx_UnknownThreadState* ts) {
return __Pyx_libcpp_cv_WrappedPySafePredicate<Lock, Predicate>(lock, pred, ts);
}
class __Pyx_libcpp_cv_WrappedPyObjectPredicate {
PyObject *pred; // unowned
public:
explicit __Pyx_libcpp_cv_WrappedPyObjectPredicate(PyObject *pred) : pred(pred) {}
bool operator()() const {
PyObject *res = PyObject_CallObject(pred, nullptr);
if (res) {
auto is_true = PyObject_IsTrue(res);
Py_DECREF(res);
return is_true; // exceptions don't matter - we have a PyErr_Occurred check outside
}
return false; // we have a PyErr_Occurred check outside
}
};
inline bool __Pyx_libcpp_cv_dummy_predicate() { return true; } // Just used for type deduction, not called
template <typename Lock, typename CV_T>
void __Pyx_libcpp_cv_py_safe_wait_2arg(CV_T& cv, Lock& lock) {
__Pyx_UnknownThreadState ts = __Pyx_SaveUnknownThread();
auto cleanup = __pyx_make_libcpp_mutex_cleanup_on_exit(
[&ts, &lock](){
__Pyx_libcpp_cv_relock_at_end(lock, ts);
}
);
cv.wait(lock);
}
template <typename Lock, typename Predicate, typename CV_T, typename ...Args>
auto __Pyx_libcpp_cv_py_safe_wait_impl(CV_T& cv, Lock& lock, Predicate pred, Args&&... args)
-> decltype(cv.wait(lock, std::forward<Args>(args)..., __Pyx_libcpp_cv_dummy_predicate)) {
__Pyx_UnknownThreadState ts = __Pyx_SaveUnknownThread();
auto cleanup = __pyx_make_libcpp_mutex_cleanup_on_exit(
[&ts, &lock](){
__Pyx_libcpp_cv_relock_at_end(lock, ts);
});
return cv.wait(lock, std::forward<Args>(args)..., __Pyx_libcpp_cv_py_safe_wrap_predicate(&lock, &pred, &ts));
}
template <typename Predicate, typename Lock, typename CV>
void __Pyx_libcpp_cv_py_safe_wait_3arg(CV& cv, Lock& lock, Predicate predicate) {
return __Pyx_libcpp_cv_py_safe_wait_impl(cv, lock, std::move(predicate));
}
// StopToken only templated not break c++11 (where std::stop_token doesn't yet exist)
template <typename Lock, typename Predicate, typename StopToken>
bool __Pyx_libcpp_cv_py_safe_wait_4arg(std::condition_variable_any& cv, Lock& lock, StopToken stoken, Predicate pred) {
// note in impl, predicate comes first
return __Pyx_libcpp_cv_py_safe_wait_impl(cv, lock, std::move(pred), std::move(stoken));
}
template <typename Lock, typename CV_T>
void __Pyx_libcpp_cv_py_safe_wait_object3(CV_T& cv, Lock& lock, PyObject *pred) {
__Pyx_libcpp_cv_py_safe_wait_impl(
cv, lock,
__Pyx_libcpp_cv_WrappedPyObjectPredicate(pred));
}
template <typename Lock, typename CV_T, typename StopToken>
bool __Pyx_libcpp_cv_py_safe_wait_object4(CV_T& cv, Lock& lock, StopToken st, PyObject *pred) {
return __Pyx_libcpp_cv_py_safe_wait_impl(
cv, lock,
__Pyx_libcpp_cv_WrappedPyObjectPredicate(pred),
std::move(st));
}
template <typename Duration, typename Lock, typename CV_T>
std::cv_status __Pyx_libcpp_cv_py_safe_wait_for_3arg(CV_T& cv, Lock& lock, const Duration& duration) {
__Pyx_UnknownThreadState ts = __Pyx_SaveUnknownThread();
auto cleanup = __pyx_make_libcpp_mutex_cleanup_on_exit(
[&ts, &lock](){
__Pyx_libcpp_cv_relock_at_end(lock, ts);
}
);
return cv.wait_for(lock, duration);
}
template <typename Duration, typename Lock, typename Predicate, typename CV_T, typename ...Args>
bool __Pyx_libcpp_cv_py_safe_wait_for_impl(CV_T& cv, Lock& lock, const Duration &duration, Predicate pred, Args&&... args) {
__Pyx_UnknownThreadState ts = __Pyx_SaveUnknownThread();
auto cleanup = __pyx_make_libcpp_mutex_cleanup_on_exit(
[&ts, &lock](){
__Pyx_libcpp_cv_relock_at_end(lock, ts);
});
return cv.wait_for(lock, std::forward<Args>(args)..., duration, __Pyx_libcpp_cv_py_safe_wrap_predicate(&lock, &pred, &ts));
}
template <typename Duration, typename Predicate, typename Lock, typename CV>
bool __Pyx_libcpp_cv_py_safe_wait_for_4arg(CV& cv, Lock& lock, const Duration& duration, Predicate predicate) {
return __Pyx_libcpp_cv_py_safe_wait_for_impl(cv, lock, duration, std::move(predicate));
}
template <typename Duration, typename Predicate, typename Lock, typename CV, typename StopToken>
bool __Pyx_libcpp_cv_py_safe_wait_for_5arg(CV& cv, Lock& lock, StopToken stop_token, const Duration& duration, Predicate predicate) {
return __Pyx_libcpp_cv_py_safe_wait_for_impl(cv, lock, duration, std::move(predicate), std::move(stop_token));
}
template <typename Duration, typename Lock, typename CV_T>
bool __Pyx_libcpp_cv_py_safe_wait_for_object4(CV_T& cv, Lock& lock, const Duration& duration, PyObject *pred) {
return __Pyx_libcpp_cv_py_safe_wait_for_impl(
cv, lock, duration,
__Pyx_libcpp_cv_WrappedPyObjectPredicate(pred));
}
template <typename Duration, typename Lock, typename CV_T, typename StopToken>
bool __Pyx_libcpp_cv_py_safe_wait_for_object5(CV_T& cv, Lock& lock, StopToken st, const Duration& duration, PyObject *pred) {
return __Pyx_libcpp_cv_py_safe_wait_for_impl(
cv, lock, duration,
__Pyx_libcpp_cv_WrappedPyObjectPredicate(pred),
std::move(st));
}
template <typename Timepoint, typename Lock, typename CV_T>
std::cv_status __Pyx_libcpp_cv_py_safe_wait_until_3arg(CV_T& cv, Lock& lock, const Timepoint& timepoint) {
__Pyx_UnknownThreadState ts = __Pyx_SaveUnknownThread();
auto cleanup = __pyx_make_libcpp_mutex_cleanup_on_exit(
[&ts, &lock](){
__Pyx_libcpp_cv_relock_at_end(lock, ts);
}
);
return cv.wait_until(lock, timepoint);
}
template <typename Timepoint, typename Lock, typename Predicate, typename CV_T, typename ...Args>
bool __Pyx_libcpp_cv_py_safe_wait_until_impl(CV_T& cv, Lock& lock, const Timepoint &timepoint, Predicate pred, Args&&... args) {
__Pyx_UnknownThreadState ts = __Pyx_SaveUnknownThread();
auto cleanup = __pyx_make_libcpp_mutex_cleanup_on_exit(
[&ts, &lock](){
__Pyx_libcpp_cv_relock_at_end(lock, ts);
});
return cv.wait_until(lock, std::forward<Args>(args)..., timepoint, __Pyx_libcpp_cv_py_safe_wrap_predicate(&lock, &pred, &ts));
}
template <typename Timepoint, typename Predicate, typename Lock, typename CV>
bool __Pyx_libcpp_cv_py_safe_wait_until_4arg(CV& cv, Lock& lock, const Timepoint& timepoint, Predicate predicate) {
return __Pyx_libcpp_cv_py_safe_wait_until_impl(cv, lock, timepoint, std::move(predicate));
}
template <typename Timepoint, typename Predicate, typename Lock, typename CV, typename StopToken>
bool __Pyx_libcpp_cv_py_safe_wait_until_5arg(CV& cv, Lock& lock, StopToken stop_token, const Timepoint& timepoint, Predicate predicate) {
return __Pyx_libcpp_cv_py_safe_wait_until_impl(cv, lock, timepoint, std::move(predicate), std::move(stop_token));
}
template <typename Timepoint, typename Lock, typename CV_T>
bool __Pyx_libcpp_cv_py_safe_wait_until_object4(CV_T& cv, Lock& lock, const Timepoint& timepoint, PyObject *pred) {
return __Pyx_libcpp_cv_py_safe_wait_until_impl(
cv, lock, timepoint,
__Pyx_libcpp_cv_WrappedPyObjectPredicate(pred));
}
template <typename Timepoint, typename Lock, typename CV_T, typename StopToken>
bool __Pyx_libcpp_cv_py_safe_wait_until_object5(CV_T& cv, Lock& lock, StopToken st, const Timepoint& timepoint, PyObject *pred) {
return __Pyx_libcpp_cv_py_safe_wait_until_impl(
cv, lock, timepoint,
__Pyx_libcpp_cv_WrappedPyObjectPredicate(pred),
std::move(st));
}
} // namespace
"""
# py_safe functions:
# * Release the GIL when blocking
# * Restore the GIL to whatever state it was when called (without deadlock)
# * Hold the GIL while evaluating the predicate (without deadlock)
# * Can accept a Python object callable predicate
# The condition_variable_any versions require a lockable class that implements try_lock in addition to lock and unlock
#
void py_safe_wait "__Pyx_libcpp_cv_py_safe_wait_2arg" (condition_variable& cv, unique_lock[mutex]& lock) except+ nogil
void py_safe_object_wait "__Pyx_libcpp_cv_py_safe_wait_object3" (condition_variable& cv, unique_lock[mutex]& lock, object predicate) except+
void py_safe_wait "__Pyx_libcpp_cv_py_safe_wait_3arg" [Predicate](condition_variable& cv, unique_lock[mutex]& lock, Predicate predicate) except+ nogil
void py_safe_wait "__Pyx_libcpp_cv_py_safe_wait_2arg" [Lock](condition_variable_any& cv, Lock& lock) except+ nogil
void py_safe_object_wait "__Pyx_libcpp_cv_py_safe_wait_object3" [Lock](condition_variable_any& cv, Lock& lock, object predicate) except+
void py_safe_wait "__Pyx_libcpp_cv_py_safe_wait_3arg" [Predicate, Lock](condition_variable_any& cv, Lock& lock, Predicate predicate) except+ nogil
_bool py_safe_object_wait "__Pyx_libcpp_cv_py_safe_wait_object4" [Lock](condition_variable_any& cv, Lock& lock, stop_token stoken, object predicate) except+
_bool py_safe_wait "__Pyx_libcpp_cv_py_safe_wait_4arg" [Lock, Predicate](condition_variable_any& cv, Lock& lock, stop_token stoken, Predicate predicate) except+ nogil
cv_status py_safe_wait_for "__Pyx_libcpp_cv_py_safe_wait_for_3arg" [Duration](condition_variable& cv, unique_lock[mutex]& lock, const Duration &duration) except+ nogil
_bool py_safe_object_wait_for "__Pyx_libcpp_cv_py_safe_wait_for_object4" [Duration](condition_variable& cv, unique_lock[mutex]& lock, const Duration &duration, object pred) except+
_bool py_safe_wait_for "__Pyx_libcpp_cv_py_safe_wait_for_4arg" [Duration, Predicate](condition_variable& cv, unique_lock[mutex]& lock, const Duration &duration, Predicate pred) except+ nogil
cv_status py_safe_wait_for "__Pyx_libcpp_cv_py_safe_wait_for_3arg" [Duration, Lock](condition_variable_any& cv, Lock& lock, const Duration &duration) except+ nogil
_bool py_safe_object_wait_for "__Pyx_libcpp_cv_py_safe_wait_for_object4" [Duration, Lock](condition_variable_any& cv, Lock& lock, const Duration &duration, object pred) except+
_bool py_safe_wait_for "__Pyx_libcpp_cv_py_safe_wait_for_4arg" [Duration, Predicate, Lock](condition_variable_any& cv, Lock& lock, const Duration &duration, Predicate pred) except+ nogil
_bool py_safe_object_wait_for "__Pyx_libcpp_cv_py_safe_wait_for_object5" [Duration, Lock](condition_variable_any& cv, Lock& lock, stop_token stoken, const Duration &duration, object pred) except+
_bool py_safe_wait_for "__Pyx_libcpp_cv_py_safe_wait_for_5arg" [Duration, Predicate, Lock](condition_variable_any& cv, Lock& lock, stop_token stoken, const Duration &duration, Predicate pred) except+ nogil
cv_status py_safe_wait_until "__Pyx_libcpp_cv_py_safe_wait_until_3arg" [Timepoint](condition_variable& cv, unique_lock[mutex]& lock, const Timepoint &timepoint) except+ nogil
_bool py_safe_object_wait_until "__Pyx_libcpp_cv_py_safe_wait_until_object4" [Timepoint](condition_variable& cv, unique_lock[mutex]& lock, const Timepoint &timepoint, object pred) except+
_bool py_safe_wait_until "__Pyx_libcpp_cv_py_safe_wait_until_4arg" [Timepoint, Predicate](condition_variable& cv, unique_lock[mutex]& lock, const Timepoint &timepoint, Predicate pred) except+ nogil
cv_status py_safe_wait_until "__Pyx_libcpp_cv_py_safe_wait_until_3arg" [Timepoint, Lock](condition_variable_any& cv, Lock& lock, const Timepoint &timepoint) except+ nogil
_bool py_safe_object_wait_until "__Pyx_libcpp_cv_py_safe_wait_until_object4" [Timepoint, Lock](condition_variable_any& cv, Lock& lock, const Timepoint &timepoint, object pred) except+
_bool py_safe_wait_until "__Pyx_libcpp_cv_py_safe_wait_until_4arg" [Timepoint, Predicate, Lock](condition_variable_any& cv, Lock& lock, const Timepoint &timepoint, Predicate pred) except+ nogil
_bool py_safe_object_wait_until "__Pyx_libcpp_cv_py_safe_wait_until_object5" [Timepoint, Lock](condition_variable_any& cv, Lock& lock, stop_token stoken, const Timepoint &timepoint, object pred) except+
_bool py_safe_wait_until "__Pyx_libcpp_cv_py_safe_wait_until_5arg" [Timepoint, Predicate, Lock](condition_variable_any& cv, Lock& lock, stop_token stoken, const Timepoint &timepoint, Predicate pred) except+ nogil
|