bpo-33608: Factor out a private, per-interpreter _Py_AddPendingCall()… · python/cpython@6a150bc (original) (raw)

10 files changed

lines changed

Original file line number Diff line number Diff line change
@@ -12,19 +12,22 @@ extern "C" {
12 12 #include "pycore_pystate.h"
13 13 #include "pythread.h"
14 14
15 -PyAPI_FUNC(void) _Py_FinishPendingCalls(_PyRuntimeState *runtime);
16 15 PyAPI_FUNC(void) _PyEval_Initialize(struct _ceval_runtime_state *);
17 16 PyAPI_FUNC(void) _PyEval_FiniThreads(
18 -struct _ceval_runtime_state *ceval);
17 +struct _ceval_runtime_state *);
19 18 PyAPI_FUNC(void) _PyEval_SignalReceived(
20 -struct _ceval_runtime_state *ceval);
19 +struct _ceval_runtime_state *);
21 20 PyAPI_FUNC(int) _PyEval_AddPendingCall(
22 21 PyThreadState *tstate,
23 -struct _ceval_runtime_state *ceval,
22 +struct _ceval_runtime_state *,
23 +struct _ceval_interpreter_state *,
24 +unsigned long thread_id,
24 25 int (*func)(void *),
25 26 void *arg);
27 +PyAPI_FUNC(void) _PyEval_FinishPendingCalls(PyInterpreterState *);
26 28 PyAPI_FUNC(void) _PyEval_SignalAsyncExc(
27 -struct _ceval_runtime_state *ceval);
29 +struct _ceval_runtime_state *,
30 +struct _ceval_interpreter_state *);
28 31 PyAPI_FUNC(void) _PyEval_ReInitThreads(
29 32 _PyRuntimeState *runtime);
30 33
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@ struct pyruntimestate;
25 25
26 26 /* ceval state */
27 27
28 -struct _pending_calls {
28 +struct _ceval_pending_calls {
29 29 int finishing;
30 30 PyThread_type_lock lock;
31 31 /* Request for running pending calls. */
@@ -36,6 +36,7 @@ struct _pending_calls {
36 36 int async_exc;
37 37 #define NPENDINGCALLS 32
38 38 struct {
39 +unsigned long thread_id;
39 40 int (*func)(void *);
40 41 void *arg;
41 42 } calls[NPENDINGCALLS];
@@ -53,15 +54,21 @@ struct _ceval_runtime_state {
53 54 int tracing_possible;
54 55 /* This single variable consolidates all requests to break out of
55 56 the fast path in the eval loop. */
57 +// XXX This can move to _ceval_interpreter_state once all parts
58 +// from COMPUTE_EVAL_BREAKER have moved under PyInterpreterState.
56 59 _Py_atomic_int eval_breaker;
57 60 /* Request for dropping the GIL */
58 61 _Py_atomic_int gil_drop_request;
59 -struct _pending_calls pending;
60 62 /* Request for checking signals. */
61 63 _Py_atomic_int signals_pending;
62 64 struct _gil_runtime_state gil;
63 65 };
64 66
67 +struct _ceval_interpreter_state {
68 +struct _ceval_pending_calls pending;
69 +};
70 +
71 +
65 72 /* interpreter state */
66 73
67 74 typedef PyObject* (*_PyFrameEvalFunction)(struct _frame *, int);
@@ -136,6 +143,7 @@ struct _is {
136 143
137 144 uint64_t tstate_next_unique_id;
138 145
146 +struct _ceval_interpreter_state ceval;
139 147 struct _warnings_runtime_state warnings;
140 148
141 149 PyObject *audit_hooks;
Original file line number Diff line number Diff line change
@@ -431,7 +431,7 @@ def pendingcalls_wait(self, l, n, context = None):
431 431 def test_pendingcalls_threaded(self):
432 432
433 433 #do every callback on a separate thread
434 -n = 32 #total callbacks
434 +n = 32 #total callbacks (see NPENDINGCALLS in pycore_ceval.h)
435 435 threads = []
436 436 class foo(object):pass
437 437 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
@@ -2677,6 +2677,7 @@ pending_threadfunc(PyObject *self, PyObject *arg)
2677 2677 Py_INCREF(callable);
2678 2678
2679 2679 Py_BEGIN_ALLOW_THREADS
2680 +/* XXX Use the internal _Py_AddPendingCall(). */
2680 2681 r = Py_AddPendingCall(&_pending_callback, callable);
2681 2682 Py_END_ALLOW_THREADS
2682 2683
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@
21 21 #include <process.h>
22 22 #endif
23 23 #endif
24 +#include "internal/pycore_pystate.h"
24 25
25 26 #ifdef HAVE_SIGNAL_H
26 27 #include <signal.h>
@@ -259,6 +260,7 @@ trip_signal(int sig_num)
259 260 /* Notify ceval.c */
260 261 _PyRuntimeState *runtime = &_PyRuntime;
261 262 PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
263 +PyInterpreterState *interp = runtime->interpreters.main;
262 264 _PyEval_SignalReceived(&runtime->ceval);
263 265
264 266 /* And then write to the wakeup fd *after* setting all the globals and
@@ -299,7 +301,10 @@ trip_signal(int sig_num)
299 301 {
300 302 /* Py_AddPendingCall() isn't signal-safe, but we
301 303 still use it for this exceptional case. */
302 -_PyEval_AddPendingCall(tstate, &runtime->ceval,
304 +_PyEval_AddPendingCall(tstate,
305 +&runtime->ceval,
306 +&interp->ceval,
307 +runtime->main_thread,
303 308 report_wakeup_send_error,
304 309 (void *)(intptr_t) last_error);
305 310 }
@@ -318,7 +323,10 @@ trip_signal(int sig_num)
318 323 {
319 324 /* Py_AddPendingCall() isn't signal-safe, but we
320 325 still use it for this exceptional case. */
321 -_PyEval_AddPendingCall(tstate, &runtime->ceval,
326 +_PyEval_AddPendingCall(tstate,
327 +&runtime->ceval,
328 +&interp->ceval,
329 +runtime->main_thread,
322 330 report_wakeup_write_error,
323 331 (void *)(intptr_t)errno);
324 332 }