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 }