Skip to content

Commit 4d61e6e

Browse files
authored
Revert: bpo-33608: Factor out a private, per-interpreter _Py_AddPendingCall(). (GH-11617) (GH-12159)
* Revert "bpo-36097: Use only public C-API in the_xxsubinterpreters module (adding as necessary). (#12003)" This reverts commit bcfa450. * Revert "bpo-33608: Simplify ceval's DISPATCH by hoisting eval_breaker ahead of time. (gh-12062)" This reverts commit bda918b. * Revert "bpo-33608: Use _Py_AddPendingCall() in _PyCrossInterpreterData_Release(). (gh-12024)" This reverts commit b05b711. * Revert "bpo-33608: Factor out a private, per-interpreter _Py_AddPendingCall(). (GH-11617)" This reverts commit ef4ac96.
1 parent f4b0a1c commit 4d61e6e

20 files changed

+576
-745
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(PyInterpreterState *);
224+
PyAPI_FUNC(void) _PyEval_SignalAsyncExc(void);
225225
#endif
226226

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

Include/cpython/interpreteridobject.h

-21
This file was deleted.

Include/cpython/pystate.h

-63
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,9 @@ typedef struct {
3030
(_PyMainInterpreterConfig){.install_signal_handlers = -1}
3131
/* Note: _PyMainInterpreterConfig_INIT sets other fields to 0/NULL */
3232

33-
PyAPI_FUNC(int) _PyInterpreterState_RequiresIDRef(PyInterpreterState *);
34-
PyAPI_FUNC(void) _PyInterpreterState_RequireIDRef(PyInterpreterState *, int);
35-
3633
PyAPI_FUNC(_PyCoreConfig *) _PyInterpreterState_GetCoreConfig(PyInterpreterState *);
3734
PyAPI_FUNC(_PyMainInterpreterConfig *) _PyInterpreterState_GetMainConfig(PyInterpreterState *);
3835

39-
PyAPI_FUNC(PyObject *) _PyInterpreterState_GetMainModule(PyInterpreterState *);
4036

4137
/* State unique per thread */
4238

@@ -218,65 +214,6 @@ PyAPI_FUNC(PyThreadState *) PyThreadState_Next(PyThreadState *);
218214

219215
typedef struct _frame *(*PyThreadFrameGetter)(PyThreadState *self_);
220216

221-
/* cross-interpreter data */
222-
223-
struct _xid;
224-
225-
// _PyCrossInterpreterData is similar to Py_buffer as an effectively
226-
// opaque struct that holds data outside the object machinery. This
227-
// is necessary to pass safely between interpreters in the same process.
228-
typedef struct _xid {
229-
// data is the cross-interpreter-safe derivation of a Python object
230-
// (see _PyObject_GetCrossInterpreterData). It will be NULL if the
231-
// new_object func (below) encodes the data.
232-
void *data;
233-
// obj is the Python object from which the data was derived. This
234-
// is non-NULL only if the data remains bound to the object in some
235-
// way, such that the object must be "released" (via a decref) when
236-
// the data is released. In that case the code that sets the field,
237-
// likely a registered "crossinterpdatafunc", is responsible for
238-
// ensuring it owns the reference (i.e. incref).
239-
PyObject *obj;
240-
// interp is the ID of the owning interpreter of the original
241-
// object. It corresponds to the active interpreter when
242-
// _PyObject_GetCrossInterpreterData() was called. This should only
243-
// be set by the cross-interpreter machinery.
244-
//
245-
// We use the ID rather than the PyInterpreterState to avoid issues
246-
// with deleted interpreters. Note that IDs are never re-used, so
247-
// each one will always correspond to a specific interpreter
248-
// (whether still alive or not).
249-
int64_t interp;
250-
// new_object is a function that returns a new object in the current
251-
// interpreter given the data. The resulting object (a new
252-
// reference) will be equivalent to the original object. This field
253-
// is required.
254-
PyObject *(*new_object)(struct _xid *);
255-
// free is called when the data is released. If it is NULL then
256-
// nothing will be done to free the data. For some types this is
257-
// okay (e.g. bytes) and for those types this field should be set
258-
// to NULL. However, for most the data was allocated just for
259-
// cross-interpreter use, so it must be freed when
260-
// _PyCrossInterpreterData_Release is called or the memory will
261-
// leak. In that case, at the very least this field should be set
262-
// to PyMem_RawFree (the default if not explicitly set to NULL).
263-
// The call will happen with the original interpreter activated.
264-
void (*free)(void *);
265-
} _PyCrossInterpreterData;
266-
267-
PyAPI_FUNC(int) _PyObject_GetCrossInterpreterData(PyObject *, _PyCrossInterpreterData *);
268-
PyAPI_FUNC(PyObject *) _PyCrossInterpreterData_NewObject(_PyCrossInterpreterData *);
269-
PyAPI_FUNC(void) _PyCrossInterpreterData_Release(_PyCrossInterpreterData *);
270-
271-
PyAPI_FUNC(int) _PyObject_CheckCrossInterpreterData(PyObject *);
272-
273-
/* cross-interpreter data registry */
274-
275-
typedef int (*crossinterpdatafunc)(PyObject *, struct _xid *);
276-
277-
PyAPI_FUNC(int) _PyCrossInterpreterData_RegisterClass(PyTypeObject *, crossinterpdatafunc);
278-
PyAPI_FUNC(crossinterpdatafunc) _PyCrossInterpreterData_Lookup(PyObject *);
279-
280217
#ifdef __cplusplus
281218
}
282219
#endif

Include/internal/pycore_atomic.h

+24-24
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,10 @@ typedef struct _Py_atomic_int {
5858
atomic_thread_fence(ORDER)
5959

6060
#define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \
61-
atomic_store_explicit(&((ATOMIC_VAL)->_value), NEW_VAL, ORDER)
61+
atomic_store_explicit(&(ATOMIC_VAL)->_value, NEW_VAL, ORDER)
6262

6363
#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \
64-
atomic_load_explicit(&((ATOMIC_VAL)->_value), ORDER)
64+
atomic_load_explicit(&(ATOMIC_VAL)->_value, ORDER)
6565

6666
/* Use builtin atomic operations in GCC >= 4.7 */
6767
#elif defined(HAVE_BUILTIN_ATOMIC)
@@ -92,14 +92,14 @@ typedef struct _Py_atomic_int {
9292
(assert((ORDER) == __ATOMIC_RELAXED \
9393
|| (ORDER) == __ATOMIC_SEQ_CST \
9494
|| (ORDER) == __ATOMIC_RELEASE), \
95-
__atomic_store_n(&((ATOMIC_VAL)->_value), NEW_VAL, ORDER))
95+
__atomic_store_n(&(ATOMIC_VAL)->_value, NEW_VAL, ORDER))
9696

9797
#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \
9898
(assert((ORDER) == __ATOMIC_RELAXED \
9999
|| (ORDER) == __ATOMIC_SEQ_CST \
100100
|| (ORDER) == __ATOMIC_ACQUIRE \
101101
|| (ORDER) == __ATOMIC_CONSUME), \
102-
__atomic_load_n(&((ATOMIC_VAL)->_value), ORDER))
102+
__atomic_load_n(&(ATOMIC_VAL)->_value, ORDER))
103103

104104
/* Only support GCC (for expression statements) and x86 (for simple
105105
* atomic semantics) and MSVC x86/x64/ARM */
@@ -324,7 +324,7 @@ inline intptr_t _Py_atomic_load_64bit(volatile uintptr_t* value, int order) {
324324
}
325325

326326
#else
327-
#define _Py_atomic_load_64bit(ATOMIC_VAL, ORDER) *(ATOMIC_VAL)
327+
#define _Py_atomic_load_64bit(ATOMIC_VAL, ORDER) *ATOMIC_VAL
328328
#endif
329329

330330
inline int _Py_atomic_load_32bit(volatile int* value, int order) {
@@ -359,15 +359,15 @@ inline int _Py_atomic_load_32bit(volatile int* value, int order) {
359359
}
360360

361361
#define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \
362-
if (sizeof((ATOMIC_VAL)->_value) == 8) { \
363-
_Py_atomic_store_64bit((volatile long long*)&((ATOMIC_VAL)->_value), NEW_VAL, ORDER) } else { \
364-
_Py_atomic_store_32bit((volatile long*)&((ATOMIC_VAL)->_value), NEW_VAL, ORDER) }
362+
if (sizeof(*ATOMIC_VAL._value) == 8) { \
363+
_Py_atomic_store_64bit((volatile long long*)ATOMIC_VAL._value, NEW_VAL, ORDER) } else { \
364+
_Py_atomic_store_32bit((volatile long*)ATOMIC_VAL._value, NEW_VAL, ORDER) }
365365

366366
#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \
367367
( \
368-
sizeof((ATOMIC_VAL)->_value) == 8 ? \
369-
_Py_atomic_load_64bit((volatile long long*)&((ATOMIC_VAL)->_value), ORDER) : \
370-
_Py_atomic_load_32bit((volatile long*)&((ATOMIC_VAL)->_value), ORDER) \
368+
sizeof(*(ATOMIC_VAL._value)) == 8 ? \
369+
_Py_atomic_load_64bit((volatile long long*)ATOMIC_VAL._value, ORDER) : \
370+
_Py_atomic_load_32bit((volatile long*)ATOMIC_VAL._value, ORDER) \
371371
)
372372
#elif defined(_M_ARM) || defined(_M_ARM64)
373373
typedef enum _Py_memory_order {
@@ -391,13 +391,13 @@ typedef struct _Py_atomic_int {
391391
#define _Py_atomic_store_64bit(ATOMIC_VAL, NEW_VAL, ORDER) \
392392
switch (ORDER) { \
393393
case _Py_memory_order_acquire: \
394-
_InterlockedExchange64_acq((__int64 volatile*)&((ATOMIC_VAL)->_value), (__int64)NEW_VAL); \
394+
_InterlockedExchange64_acq((__int64 volatile*)ATOMIC_VAL, (__int64)NEW_VAL); \
395395
break; \
396396
case _Py_memory_order_release: \
397-
_InterlockedExchange64_rel((__int64 volatile*)&((ATOMIC_VAL)->_value), (__int64)NEW_VAL); \
397+
_InterlockedExchange64_rel((__int64 volatile*)ATOMIC_VAL, (__int64)NEW_VAL); \
398398
break; \
399399
default: \
400-
_InterlockedExchange64((__int64 volatile*)&((ATOMIC_VAL)->_value), (__int64)NEW_VAL); \
400+
_InterlockedExchange64((__int64 volatile*)ATOMIC_VAL, (__int64)NEW_VAL); \
401401
break; \
402402
}
403403
#else
@@ -407,13 +407,13 @@ typedef struct _Py_atomic_int {
407407
#define _Py_atomic_store_32bit(ATOMIC_VAL, NEW_VAL, ORDER) \
408408
switch (ORDER) { \
409409
case _Py_memory_order_acquire: \
410-
_InterlockedExchange_acq((volatile long*)&((ATOMIC_VAL)->_value), (int)NEW_VAL); \
410+
_InterlockedExchange_acq((volatile long*)ATOMIC_VAL, (int)NEW_VAL); \
411411
break; \
412412
case _Py_memory_order_release: \
413-
_InterlockedExchange_rel((volatile long*)&((ATOMIC_VAL)->_value), (int)NEW_VAL); \
413+
_InterlockedExchange_rel((volatile long*)ATOMIC_VAL, (int)NEW_VAL); \
414414
break; \
415415
default: \
416-
_InterlockedExchange((volatile long*)&((ATOMIC_VAL)->_value), (int)NEW_VAL); \
416+
_InterlockedExchange((volatile long*)ATOMIC_VAL, (int)NEW_VAL); \
417417
break; \
418418
}
419419

@@ -454,7 +454,7 @@ inline intptr_t _Py_atomic_load_64bit(volatile uintptr_t* value, int order) {
454454
}
455455

456456
#else
457-
#define _Py_atomic_load_64bit(ATOMIC_VAL, ORDER) *(ATOMIC_VAL)
457+
#define _Py_atomic_load_64bit(ATOMIC_VAL, ORDER) *ATOMIC_VAL
458458
#endif
459459

460460
inline int _Py_atomic_load_32bit(volatile int* value, int order) {
@@ -489,15 +489,15 @@ inline int _Py_atomic_load_32bit(volatile int* value, int order) {
489489
}
490490

491491
#define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \
492-
if (sizeof((ATOMIC_VAL)->_value) == 8) { \
493-
_Py_atomic_store_64bit(&((ATOMIC_VAL)->_value), NEW_VAL, ORDER) } else { \
494-
_Py_atomic_store_32bit(&((ATOMIC_VAL)->_value), NEW_VAL, ORDER) }
492+
if (sizeof(*ATOMIC_VAL._value) == 8) { \
493+
_Py_atomic_store_64bit(ATOMIC_VAL._value, NEW_VAL, ORDER) } else { \
494+
_Py_atomic_store_32bit(ATOMIC_VAL._value, NEW_VAL, ORDER) }
495495

496496
#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \
497497
( \
498-
sizeof((ATOMIC_VAL)->_value) == 8 ? \
499-
_Py_atomic_load_64bit(&((ATOMIC_VAL)->_value), ORDER) : \
500-
_Py_atomic_load_32bit(&((ATOMIC_VAL)->_value), ORDER) \
498+
sizeof(*(ATOMIC_VAL._value)) == 8 ? \
499+
_Py_atomic_load_64bit(ATOMIC_VAL._value, ORDER) : \
500+
_Py_atomic_load_32bit(ATOMIC_VAL._value, ORDER) \
501501
)
502502
#endif
503503
#else /* !gcc x86 !_msc_ver */

Include/internal/pycore_ceval.h

+5-13
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,8 @@ 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-
1914
struct _pending_calls {
15+
unsigned long main_thread;
2016
PyThread_type_lock lock;
2117
/* Request for running pending calls. */
2218
_Py_atomic_int calls_to_do;
@@ -26,21 +22,13 @@ struct _pending_calls {
2622
int async_exc;
2723
#define NPENDINGCALLS 32
2824
struct {
29-
unsigned long thread_id;
3025
int (*func)(void *);
3126
void *arg;
3227
} calls[NPENDINGCALLS];
3328
int first;
3429
int last;
3530
};
3631

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-
4432
#include "pycore_gil.h"
4533

4634
struct _ceval_runtime_state {
@@ -51,8 +39,12 @@ struct _ceval_runtime_state {
5139
c_tracefunc. This speeds up the if statement in
5240
PyEval_EvalFrameEx() after fast_next_opcode. */
5341
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;
5445
/* Request for dropping the GIL */
5546
_Py_atomic_int gil_drop_request;
47+
struct _pending_calls pending;
5648
/* Request for checking signals. */
5749
_Py_atomic_int signals_pending;
5850
struct _gil_runtime_state gil;

Include/internal/pycore_pystate.h

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

14-
#include "pycore_atomic.h"
1514
#include "pycore_ceval.h"
1615
#include "pycore_pathconfig.h"
1716
#include "pycore_pymem.h"
@@ -30,11 +29,8 @@ struct _is {
3029

3130
int64_t id;
3231
int64_t id_refcount;
33-
int requires_idref;
3432
PyThread_type_lock id_mutex;
3533

36-
int finalizing;
37-
3834
PyObject *modules;
3935
PyObject *modules_by_index;
4036
PyObject *sysdict;
@@ -82,8 +78,6 @@ struct _is {
8278
PyObject *pyexitmodule;
8379

8480
uint64_t tstate_next_unique_id;
85-
86-
struct _ceval_interpreter_state ceval;
8781
};
8882

8983
PyAPI_FUNC(struct _is*) _PyInterpreterState_LookUpID(PY_INT64_T);
@@ -93,12 +87,66 @@ PyAPI_FUNC(void) _PyInterpreterState_IDIncref(struct _is *);
9387
PyAPI_FUNC(void) _PyInterpreterState_IDDecref(struct _is *);
9488

9589

90+
/* cross-interpreter data */
91+
92+
struct _xid;
93+
94+
// _PyCrossInterpreterData is similar to Py_buffer as an effectively
95+
// opaque struct that holds data outside the object machinery. This
96+
// is necessary to pass safely between interpreters in the same process.
97+
typedef struct _xid {
98+
// data is the cross-interpreter-safe derivation of a Python object
99+
// (see _PyObject_GetCrossInterpreterData). It will be NULL if the
100+
// new_object func (below) encodes the data.
101+
void *data;
102+
// obj is the Python object from which the data was derived. This
103+
// is non-NULL only if the data remains bound to the object in some
104+
// way, such that the object must be "released" (via a decref) when
105+
// the data is released. In that case the code that sets the field,
106+
// likely a registered "crossinterpdatafunc", is responsible for
107+
// ensuring it owns the reference (i.e. incref).
108+
PyObject *obj;
109+
// interp is the ID of the owning interpreter of the original
110+
// object. It corresponds to the active interpreter when
111+
// _PyObject_GetCrossInterpreterData() was called. This should only
112+
// be set by the cross-interpreter machinery.
113+
//
114+
// We use the ID rather than the PyInterpreterState to avoid issues
115+
// with deleted interpreters.
116+
int64_t interp;
117+
// new_object is a function that returns a new object in the current
118+
// interpreter given the data. The resulting object (a new
119+
// reference) will be equivalent to the original object. This field
120+
// is required.
121+
PyObject *(*new_object)(struct _xid *);
122+
// free is called when the data is released. If it is NULL then
123+
// nothing will be done to free the data. For some types this is
124+
// okay (e.g. bytes) and for those types this field should be set
125+
// to NULL. However, for most the data was allocated just for
126+
// cross-interpreter use, so it must be freed when
127+
// _PyCrossInterpreterData_Release is called or the memory will
128+
// leak. In that case, at the very least this field should be set
129+
// to PyMem_RawFree (the default if not explicitly set to NULL).
130+
// The call will happen with the original interpreter activated.
131+
void (*free)(void *);
132+
} _PyCrossInterpreterData;
133+
134+
typedef int (*crossinterpdatafunc)(PyObject *, _PyCrossInterpreterData *);
135+
PyAPI_FUNC(int) _PyObject_CheckCrossInterpreterData(PyObject *);
136+
137+
PyAPI_FUNC(int) _PyObject_GetCrossInterpreterData(PyObject *, _PyCrossInterpreterData *);
138+
PyAPI_FUNC(PyObject *) _PyCrossInterpreterData_NewObject(_PyCrossInterpreterData *);
139+
PyAPI_FUNC(void) _PyCrossInterpreterData_Release(_PyCrossInterpreterData *);
140+
96141
/* cross-interpreter data registry */
97142

98143
/* For now we use a global registry of shareable classes. An
99144
alternative would be to add a tp_* slot for a class's
100145
crossinterpdatafunc. It would be simpler and more efficient. */
101146

147+
PyAPI_FUNC(int) _PyCrossInterpreterData_Register_Class(PyTypeObject *, crossinterpdatafunc);
148+
PyAPI_FUNC(crossinterpdatafunc) _PyCrossInterpreterData_Lookup(PyObject *);
149+
102150
struct _xidregitem;
103151

104152
struct _xidregitem {
@@ -159,8 +207,6 @@ typedef struct pyruntimestate {
159207
struct _xidregitem *head;
160208
} xidregistry;
161209

162-
unsigned long main_thread;
163-
164210
#define NEXITFUNCS 32
165211
void (*exitfuncs[NEXITFUNCS])(void);
166212
int nexitfuncs;

0 commit comments

Comments
 (0)