bpo-33608: Factor out a private, per-interpreter _Py_AddPendingCall()… · python/cpython@f13c5c8 (original) (raw)
11 files changed
lines changed
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -221,7 +221,7 @@ PyAPI_FUNC(Py_ssize_t) _PyEval_RequestCodeExtraIndex(freefunc); | ||
221 | 221 | #ifndef Py_LIMITED_API |
222 | 222 | PyAPI_FUNC(int) _PyEval_SliceIndex(PyObject *, Py_ssize_t *); |
223 | 223 | PyAPI_FUNC(int) _PyEval_SliceIndexNotNone(PyObject *, Py_ssize_t *); |
224 | -PyAPI_FUNC(void) _PyEval_SignalAsyncExc(void); | |
224 | +PyAPI_FUNC(void) _PyEval_SignalAsyncExc(PyInterpreterState *); | |
225 | 225 | #endif |
226 | 226 | |
227 | 227 | /* Masks and values used by FORMAT_VALUE opcode. */ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -11,7 +11,11 @@ extern "C" { | ||
11 | 11 | #include "pycore_atomic.h" |
12 | 12 | #include "pythread.h" |
13 | 13 | |
14 | -PyAPI_FUNC(void) _Py_FinishPendingCalls(void); | |
14 | +struct _is; // See PyInterpreterState in cpython/pystate.h. | |
15 | + | |
16 | +PyAPI_FUNC(int) _Py_AddPendingCall(struct _is*, unsigned long, int (*)(void *), void *); | |
17 | +PyAPI_FUNC(int) _Py_MakePendingCalls(struct _is*); | |
18 | +PyAPI_FUNC(void) _Py_FinishPendingCalls(struct _is*); | |
15 | 19 | |
16 | 20 | struct _pending_calls { |
17 | 21 | int finishing; |
@@ -24,13 +28,21 @@ struct _pending_calls { | ||
24 | 28 | int async_exc; |
25 | 29 | #define NPENDINGCALLS 32 |
26 | 30 | struct { |
31 | +unsigned long thread_id; | |
27 | 32 | int (*func)(void *); |
28 | 33 | void *arg; |
29 | 34 | } calls[NPENDINGCALLS]; |
30 | 35 | int first; |
31 | 36 | int last; |
32 | 37 | }; |
33 | 38 | |
39 | +struct _ceval_interpreter_state { | |
40 | +/* This single variable consolidates all requests to break out of | |
41 | + the fast path in the eval loop. */ | |
42 | +_Py_atomic_int eval_breaker; | |
43 | +struct _pending_calls pending; | |
44 | +}; | |
45 | + | |
34 | 46 | #include "pycore_gil.h" |
35 | 47 | |
36 | 48 | struct _ceval_runtime_state { |
@@ -41,12 +53,8 @@ struct _ceval_runtime_state { | ||
41 | 53 | c_tracefunc. This speeds up the if statement in |
42 | 54 | PyEval_EvalFrameEx() after fast_next_opcode. */ |
43 | 55 | int tracing_possible; |
44 | -/* This single variable consolidates all requests to break out of | |
45 | - the fast path in the eval loop. */ | |
46 | -_Py_atomic_int eval_breaker; | |
47 | 56 | /* Request for dropping the GIL */ |
48 | 57 | _Py_atomic_int gil_drop_request; |
49 | -struct _pending_calls pending; | |
50 | 58 | /* Request for checking signals. */ |
51 | 59 | _Py_atomic_int signals_pending; |
52 | 60 | struct _gil_runtime_state gil; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -12,6 +12,7 @@ extern "C" { | ||
12 | 12 | #include "pystate.h" |
13 | 13 | #include "pythread.h" |
14 | 14 | |
15 | +#include "pycore_atomic.h" | |
15 | 16 | #include "pycore_ceval.h" |
16 | 17 | #include "pycore_pathconfig.h" |
17 | 18 | #include "pycore_pymem.h" |
@@ -83,6 +84,8 @@ struct _is { | ||
83 | 84 | PyObject *pyexitmodule; |
84 | 85 | |
85 | 86 | uint64_t tstate_next_unique_id; |
87 | + | |
88 | +struct _ceval_interpreter_state ceval; | |
86 | 89 | }; |
87 | 90 | |
88 | 91 | PyAPI_FUNC(struct _is*) _PyInterpreterState_LookUpID(PY_INT64_T); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -373,7 +373,7 @@ def pendingcalls_wait(self, l, n, context = None): | ||
373 | 373 | def test_pendingcalls_threaded(self): |
374 | 374 | |
375 | 375 | #do every callback on a separate thread |
376 | -n = 32 #total callbacks | |
376 | +n = 32 #total callbacks (see NPENDINGCALLS in pycore_ceval.h) | |
377 | 377 | threads = [] |
378 | 378 | class foo(object):pass |
379 | 379 | context = foo() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
1 | +We added a new internal _Py_AddPendingCall() that operates relative to the | |
2 | +provided interpreter. This allows us to use the existing implementation to | |
3 | +ask another interpreter to do work that cannot be done in the current | |
4 | +interpreter, like decref an object the other interpreter owns. The existing | |
5 | +Py_AddPendingCall() only operates relative to the main interpreter. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -2445,6 +2445,7 @@ pending_threadfunc(PyObject *self, PyObject *arg) | ||
2445 | 2445 | Py_INCREF(callable); |
2446 | 2446 | |
2447 | 2447 | Py_BEGIN_ALLOW_THREADS |
2448 | +/* XXX Use the internal _Py_AddPendingCall(). */ | |
2448 | 2449 | r = Py_AddPendingCall(&_pending_callback, callable); |
2449 | 2450 | Py_END_ALLOW_THREADS |
2450 | 2451 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -19,6 +19,7 @@ | ||
19 | 19 | #include <process.h> |
20 | 20 | #endif |
21 | 21 | #endif |
22 | +#include "internal/pycore_pystate.h" | |
22 | 23 | |
23 | 24 | #ifdef HAVE_SIGNAL_H |
24 | 25 | #include <signal.h> |
@@ -295,8 +296,10 @@ trip_signal(int sig_num) | ||
295 | 296 | { |
296 | 297 | /* Py_AddPendingCall() isn't signal-safe, but we |
297 | 298 | still use it for this exceptional case. */ |
298 | -Py_AddPendingCall(report_wakeup_send_error, | |
299 | - (void *)(intptr_t) last_error); | |
299 | +_Py_AddPendingCall(_PyRuntime.interpreters.main, | |
300 | +main_thread, | |
301 | +report_wakeup_send_error, | |
302 | + (void *)(intptr_t) last_error); | |
300 | 303 | } |
301 | 304 | } |
302 | 305 | } |
@@ -313,8 +316,10 @@ trip_signal(int sig_num) | ||
313 | 316 | { |
314 | 317 | /* Py_AddPendingCall() isn't signal-safe, but we |
315 | 318 | still use it for this exceptional case. */ |
316 | -Py_AddPendingCall(report_wakeup_write_error, | |
317 | - (void *)(intptr_t)errno); | |
319 | +_Py_AddPendingCall(_PyRuntime.interpreters.main, | |
320 | +main_thread, | |
321 | +report_wakeup_write_error, | |
322 | + (void *)(intptr_t)errno); | |
318 | 323 | } |
319 | 324 | } |
320 | 325 | } |