Skip to content

Commit ef4ac96

Browse files
bpo-33608: Factor out a private, per-interpreter _Py_AddPendingCall(). (GH-11617)
This involves moving the global "pending calls" state to PyInterpreterState. https://bugs.python.org/issue33608
1 parent 463572c commit ef4ac96

File tree

10 files changed

+201
-121
lines changed

10 files changed

+201
-121
lines changed

Include/ceval.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ PyAPI_FUNC(Py_ssize_t) _PyEval_RequestCodeExtraIndex(freefunc);
221221
#ifndef Py_LIMITED_API
222222
PyAPI_FUNC(int) _PyEval_SliceIndex(PyObject *, Py_ssize_t *);
223223
PyAPI_FUNC(int) _PyEval_SliceIndexNotNone(PyObject *, Py_ssize_t *);
224-
PyAPI_FUNC(void) _PyEval_SignalAsyncExc(void);
224+
PyAPI_FUNC(void) _PyEval_SignalAsyncExc(PyInterpreterState *);
225225
#endif
226226

227227
/* Masks and values used by FORMAT_VALUE opcode. */

Include/internal/pycore_ceval.h

+13-5
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,12 @@ extern "C" {
1111
#include "pycore_atomic.h"
1212
#include "pythread.h"
1313

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+
1419
struct _pending_calls {
15-
unsigned long main_thread;
1620
PyThread_type_lock lock;
1721
/* Request for running pending calls. */
1822
_Py_atomic_int calls_to_do;
@@ -22,13 +26,21 @@ struct _pending_calls {
2226
int async_exc;
2327
#define NPENDINGCALLS 32
2428
struct {
29+
unsigned long thread_id;
2530
int (*func)(void *);
2631
void *arg;
2732
} calls[NPENDINGCALLS];
2833
int first;
2934
int last;
3035
};
3136

37+
struct _ceval_interpreter_state {
38+
/* This single variable consolidates all requests to break out of
39+
the fast path in the eval loop. */
40+
_Py_atomic_int eval_breaker;
41+
struct _pending_calls pending;
42+
};
43+
3244
#include "pycore_gil.h"
3345

3446
struct _ceval_runtime_state {
@@ -39,12 +51,8 @@ struct _ceval_runtime_state {
3951
c_tracefunc. This speeds up the if statement in
4052
PyEval_EvalFrameEx() after fast_next_opcode. */
4153
int tracing_possible;
42-
/* This single variable consolidates all requests to break out of
43-
the fast path in the eval loop. */
44-
_Py_atomic_int eval_breaker;
4554
/* Request for dropping the GIL */
4655
_Py_atomic_int gil_drop_request;
47-
struct _pending_calls pending;
4856
/* Request for checking signals. */
4957
_Py_atomic_int signals_pending;
5058
struct _gil_runtime_state gil;

Include/internal/pycore_pystate.h

+7
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ extern "C" {
1111
#include "pystate.h"
1212
#include "pythread.h"
1313

14+
#include "pycore_atomic.h"
1415
#include "pycore_ceval.h"
1516
#include "pycore_pathconfig.h"
1617
#include "pycore_pymem.h"
@@ -31,6 +32,8 @@ struct _is {
3132
int64_t id_refcount;
3233
PyThread_type_lock id_mutex;
3334

35+
int finalizing;
36+
3437
PyObject *modules;
3538
PyObject *modules_by_index;
3639
PyObject *sysdict;
@@ -78,6 +81,8 @@ struct _is {
7881
PyObject *pyexitmodule;
7982

8083
uint64_t tstate_next_unique_id;
84+
85+
struct _ceval_interpreter_state ceval;
8186
};
8287

8388
PyAPI_FUNC(struct _is*) _PyInterpreterState_LookUpID(PY_INT64_T);
@@ -207,6 +212,8 @@ typedef struct pyruntimestate {
207212
struct _xidregitem *head;
208213
} xidregistry;
209214

215+
unsigned long main_thread;
216+
210217
#define NEXITFUNCS 32
211218
void (*exitfuncs[NEXITFUNCS])(void);
212219
int nexitfuncs;
Original file line numberDiff line numberDiff 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.

Modules/_testcapimodule.c

+1
Original file line numberDiff line numberDiff line change
@@ -2445,6 +2445,7 @@ pending_threadfunc(PyObject *self, PyObject *arg)
24452445
Py_INCREF(callable);
24462446

24472447
Py_BEGIN_ALLOW_THREADS
2448+
/* XXX Use the internal _Py_AddPendingCall(). */
24482449
r = Py_AddPendingCall(&_pending_callback, callable);
24492450
Py_END_ALLOW_THREADS
24502451

Modules/signalmodule.c

+9-4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <process.h>
2020
#endif
2121
#endif
22+
#include "internal/pycore_pystate.h"
2223

2324
#ifdef HAVE_SIGNAL_H
2425
#include <signal.h>
@@ -295,8 +296,10 @@ trip_signal(int sig_num)
295296
{
296297
/* Py_AddPendingCall() isn't signal-safe, but we
297298
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);
300303
}
301304
}
302305
}
@@ -313,8 +316,10 @@ trip_signal(int sig_num)
313316
{
314317
/* Py_AddPendingCall() isn't signal-safe, but we
315318
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);
318323
}
319324
}
320325
}

0 commit comments

Comments
 (0)