Skip to content

Commit f5f96b2

Browse files
ericsnowcurrentlypicnixz
authored andcommitted
pythongh-76785: Improved Subinterpreters Compatibility with 3.12 (1/2) (pythongh-126704)
These changes makes it easier to backport the _interpreters, _interpqueues, and _interpchannels modules to Python 3.12. This involves the following: * rename several structs and typedefs * add several typedefs * stop using the PyThreadState.state field directly in parking_lot.c
1 parent 77ea4e4 commit f5f96b2

9 files changed

+55
-43
lines changed

Include/internal/pycore_crossinterp.h

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,14 @@ extern int _Py_CallInInterpreterAndRawFree(
3939
/* cross-interpreter data */
4040
/**************************/
4141

42-
typedef struct _xid _PyXIData_t;
43-
typedef PyObject *(*xid_newobjectfunc)(_PyXIData_t *);
42+
typedef struct _xidata _PyXIData_t;
43+
typedef PyObject *(*xid_newobjfunc)(_PyXIData_t *);
4444
typedef void (*xid_freefunc)(void *);
4545

4646
// _PyXIData_t is similar to Py_buffer as an effectively
4747
// opaque struct that holds data outside the object machinery. This
4848
// is necessary to pass safely between interpreters in the same process.
49-
struct _xid {
49+
struct _xidata {
5050
// data is the cross-interpreter-safe derivation of a Python object
5151
// (see _PyObject_GetXIData). It will be NULL if the
5252
// new_object func (below) encodes the data.
@@ -72,7 +72,7 @@ struct _xid {
7272
// interpreter given the data. The resulting object (a new
7373
// reference) will be equivalent to the original object. This field
7474
// is required.
75-
xid_newobjectfunc new_object;
75+
xid_newobjfunc new_object;
7676
// free is called when the data is released. If it is NULL then
7777
// nothing will be done to free the data. For some types this is
7878
// okay (e.g. bytes) and for those types this field should be set
@@ -117,11 +117,11 @@ PyAPI_FUNC(int) _PyXIData_ReleaseAndRawFree(_PyXIData_t *);
117117
PyAPI_FUNC(void) _PyXIData_Init(
118118
_PyXIData_t *data,
119119
PyInterpreterState *interp, void *shared, PyObject *obj,
120-
xid_newobjectfunc new_object);
120+
xid_newobjfunc new_object);
121121
PyAPI_FUNC(int) _PyXIData_InitWithSize(
122122
_PyXIData_t *,
123123
PyInterpreterState *interp, const size_t, PyObject *,
124-
xid_newobjectfunc);
124+
xid_newobjfunc);
125125
PyAPI_FUNC(void) _PyXIData_Clear( PyInterpreterState *, _PyXIData_t *);
126126

127127
// Normally the Init* functions are sufficient. The only time
@@ -155,12 +155,12 @@ PyAPI_FUNC(void) _PyXIData_Clear( PyInterpreterState *, _PyXIData_t *);
155155
/* runtime state & lifecycle */
156156
/*****************************/
157157

158-
struct _xi_runtime_state {
158+
typedef struct {
159159
// builtin types
160160
_PyXIData_lookup_t data_lookup;
161-
};
161+
} _PyXI_global_state_t;
162162

163-
struct _xi_state {
163+
typedef struct {
164164
// heap types
165165
_PyXIData_lookup_t data_lookup;
166166

@@ -171,7 +171,7 @@ struct _xi_state {
171171
// heap types
172172
PyObject *PyExc_NotShareableError;
173173
} exceptions;
174-
};
174+
} _PyXI_state_t;
175175

176176
extern PyStatus _PyXI_Init(PyInterpreterState *interp);
177177
extern void _PyXI_Fini(PyInterpreterState *interp);

Include/internal/pycore_crossinterp_data_registry.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,30 +7,30 @@
77
// alternative would be to add a tp_* slot for a class's
88
// xidatafunc. It would be simpler and more efficient.
99

10-
struct _xidregitem;
10+
struct _xid_regitem;
1111

12-
struct _xidregitem {
13-
struct _xidregitem *prev;
14-
struct _xidregitem *next;
12+
typedef struct _xid_regitem {
13+
struct _xid_regitem *prev;
14+
struct _xid_regitem *next;
1515
/* This can be a dangling pointer, but only if weakref is set. */
1616
PyTypeObject *cls;
1717
/* This is NULL for builtin types. */
1818
PyObject *weakref;
1919
size_t refcount;
2020
xidatafunc getdata;
21-
};
21+
} _PyXIData_regitem_t;
2222

23-
struct _xidregistry {
23+
typedef struct {
2424
int global; /* builtin types or heap types */
2525
int initialized;
2626
PyMutex mutex;
27-
struct _xidregitem *head;
28-
};
27+
_PyXIData_regitem_t *head;
28+
} _PyXIData_registry_t;
2929

3030
PyAPI_FUNC(int) _PyXIData_RegisterClass(PyTypeObject *, xidatafunc);
3131
PyAPI_FUNC(int) _PyXIData_UnregisterClass(PyTypeObject *);
3232

3333
struct _xid_lookup_state {
3434
// XXX Remove this field once we have a tp_* slot.
35-
struct _xidregistry registry;
35+
_PyXIData_registry_t registry;
3636
};

Include/internal/pycore_interp.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ extern "C" {
1616
#include "pycore_code.h" // struct callable_cache
1717
#include "pycore_codecs.h" // struct codecs_state
1818
#include "pycore_context.h" // struct _Py_context_state
19-
#include "pycore_crossinterp.h" // struct _xidregistry
19+
#include "pycore_crossinterp.h" // _PyXI_state_t
2020
#include "pycore_dict_state.h" // struct _Py_dict_state
2121
#include "pycore_dtoa.h" // struct _dtoa_state
2222
#include "pycore_exceptions.h" // struct _Py_exc_state
@@ -205,7 +205,7 @@ struct _is {
205205
freefunc co_extra_freefuncs[MAX_CO_EXTRA_USERS];
206206

207207
/* cross-interpreter data and utils */
208-
struct _xi_state xi;
208+
_PyXI_state_t xi;
209209

210210
#ifdef HAVE_FORK
211211
PyObject *before_forkers;

Include/internal/pycore_pystate.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,12 @@ _PyThreadState_GET(void)
141141
#endif
142142
}
143143

144+
static inline int
145+
_PyThreadState_IsAttached(PyThreadState *tstate)
146+
{
147+
return (_Py_atomic_load_int_relaxed(&tstate->state) == _Py_THREAD_ATTACHED);
148+
}
149+
144150
// Attaches the current thread to the interpreter.
145151
//
146152
// This may block while acquiring the GIL (if the GIL is enabled) or while

Include/internal/pycore_runtime.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ extern "C" {
1111
#include "pycore_atexit.h" // struct _atexit_runtime_state
1212
#include "pycore_audit.h" // _Py_AuditHookEntry
1313
#include "pycore_ceval_state.h" // struct _ceval_runtime_state
14-
#include "pycore_crossinterp.h" // struct _xidregistry
14+
#include "pycore_crossinterp.h" // _PyXI_global_state_t
1515
#include "pycore_debug_offsets.h" // _Py_DebugOffsets
1616
#include "pycore_faulthandler.h" // struct _faulthandler_runtime_state
1717
#include "pycore_floatobject.h" // struct _Py_float_runtime_state
@@ -106,7 +106,7 @@ typedef struct pyruntimestate {
106106
tools. */
107107

108108
/* cross-interpreter data and utils */
109-
struct _xi_runtime_state xi;
109+
_PyXI_global_state_t xi;
110110

111111
struct _pymem_allocators allocators;
112112
struct _obmalloc_global_state obmalloc;

Modules/_interpchannelsmodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ _globals (static struct globals):
6363
data (void *)
6464
obj (PyObject *)
6565
interpid (int64_t)
66-
new_object (xid_newobjectfunc)
66+
new_object (xid_newobjfunc)
6767
free (xid_freefunc)
6868
last (struct _channelitem *):
6969
...

Python/crossinterp.c

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ void
126126
_PyXIData_Init(_PyXIData_t *data,
127127
PyInterpreterState *interp,
128128
void *shared, PyObject *obj,
129-
xid_newobjectfunc new_object)
129+
xid_newobjfunc new_object)
130130
{
131131
assert(data != NULL);
132132
assert(new_object != NULL);
@@ -150,7 +150,7 @@ int
150150
_PyXIData_InitWithSize(_PyXIData_t *data,
151151
PyInterpreterState *interp,
152152
const size_t size, PyObject *obj,
153-
xid_newobjectfunc new_object)
153+
xid_newobjfunc new_object)
154154
{
155155
assert(size > 0);
156156
// For now we always free the shared data in the same interpreter
@@ -202,11 +202,9 @@ _check_xidata(PyThreadState *tstate, _PyXIData_t *data)
202202
}
203203

204204
static inline void
205-
_set_xid_lookup_failure(PyInterpreterState *interp,
206-
PyObject *obj, const char *msg)
205+
_set_xid_lookup_failure(_PyXI_state_t *state, PyObject *obj, const char *msg)
207206
{
208-
exceptions_t *state = &_PyInterpreterState_GetXIState(interp)->exceptions;
209-
PyObject *exctype = state->PyExc_NotShareableError;
207+
PyObject *exctype = state->exceptions.PyExc_NotShareableError;
210208
assert(exctype != NULL);
211209
if (msg != NULL) {
212210
assert(obj == NULL);
@@ -226,10 +224,11 @@ int
226224
_PyObject_CheckXIData(PyObject *obj)
227225
{
228226
PyInterpreterState *interp = PyInterpreterState_Get();
227+
_PyXI_state_t *state = _PyXI_GET_STATE(interp);
229228
xidatafunc getdata = lookup_getdata(interp, obj);
230229
if (getdata == NULL) {
231230
if (!PyErr_Occurred()) {
232-
_set_xid_lookup_failure(interp, obj, NULL);
231+
_set_xid_lookup_failure(state, obj, NULL);
233232
}
234233
return -1;
235234
}
@@ -241,6 +240,7 @@ _PyObject_GetXIData(PyObject *obj, _PyXIData_t *data)
241240
{
242241
PyThreadState *tstate = PyThreadState_Get();
243242
PyInterpreterState *interp = tstate->interp;
243+
_PyXI_state_t *state = _PyXI_GET_STATE(interp);
244244

245245
// Reset data before re-populating.
246246
*data = (_PyXIData_t){0};
@@ -252,7 +252,7 @@ _PyObject_GetXIData(PyObject *obj, _PyXIData_t *data)
252252
if (getdata == NULL) {
253253
Py_DECREF(obj);
254254
if (!PyErr_Occurred()) {
255-
_set_xid_lookup_failure(interp, obj, NULL);
255+
_set_xid_lookup_failure(state, obj, NULL);
256256
}
257257
return -1;
258258
}
@@ -969,6 +969,7 @@ _PyXI_ClearExcInfo(_PyXI_excinfo *info)
969969
static int
970970
_PyXI_ApplyErrorCode(_PyXI_errcode code, PyInterpreterState *interp)
971971
{
972+
_PyXI_state_t *state;
972973
assert(!PyErr_Occurred());
973974
switch (code) {
974975
case _PyXI_ERR_NO_ERROR: _Py_FALLTHROUGH;
@@ -999,7 +1000,8 @@ _PyXI_ApplyErrorCode(_PyXI_errcode code, PyInterpreterState *interp)
9991000
"failed to apply namespace to __main__");
10001001
break;
10011002
case _PyXI_ERR_NOT_SHAREABLE:
1002-
_set_xid_lookup_failure(interp, NULL, NULL);
1003+
state = _PyXI_GET_STATE(interp);
1004+
_set_xid_lookup_failure(state, NULL, NULL);
10031005
break;
10041006
default:
10051007
#ifdef Py_DEBUG
@@ -1061,7 +1063,8 @@ _PyXI_ApplyError(_PyXI_error *error)
10611063
}
10621064
else if (error->code == _PyXI_ERR_NOT_SHAREABLE) {
10631065
// Propagate the exception directly.
1064-
_set_xid_lookup_failure(error->interp, NULL, error->uncaught.msg);
1066+
_PyXI_state_t *state = _PyXI_GET_STATE(error->interp);
1067+
_set_xid_lookup_failure(state, NULL, error->uncaught.msg);
10651068
}
10661069
else {
10671070
// Raise an exception corresponding to the code.
@@ -1606,9 +1609,9 @@ _propagate_not_shareable_error(_PyXI_session *session)
16061609
return;
16071610
}
16081611
PyInterpreterState *interp = PyInterpreterState_Get();
1609-
exceptions_t *state = &_PyInterpreterState_GetXIState(interp)->exceptions;
1610-
assert(state->PyExc_NotShareableError != NULL);
1611-
if (PyErr_ExceptionMatches(state->PyExc_NotShareableError)) {
1612+
_PyXI_state_t *state = _PyXI_GET_STATE(interp);
1613+
assert(state->exceptions.PyExc_NotShareableError != NULL);
1614+
if (PyErr_ExceptionMatches(state->exceptions.PyExc_NotShareableError)) {
16121615
// We want to propagate the exception directly.
16131616
session->_error_override = _PyXI_ERR_NOT_SHAREABLE;
16141617
session->error_override = &session->_error_override;
@@ -1779,11 +1782,13 @@ _PyXI_Exit(_PyXI_session *session)
17791782
PyStatus
17801783
_PyXI_Init(PyInterpreterState *interp)
17811784
{
1785+
_PyXI_state_t *state = _PyXI_GET_STATE(interp);
1786+
17821787
// Initialize the XID lookup state (e.g. registry).
17831788
if (_Py_IsMainInterpreter(interp)) {
17841789
xid_lookup_init(&_PyXI_GET_GLOBAL_STATE(interp)->data_lookup);
17851790
}
1786-
xid_lookup_init(&_PyXI_GET_STATE(interp)->data_lookup);
1791+
xid_lookup_init(&state->data_lookup);
17871792

17881793
// Initialize exceptions.(heap types).
17891794
// See _PyXI_InitTypes() for the static types.
@@ -1801,12 +1806,14 @@ _PyXI_Init(PyInterpreterState *interp)
18011806
void
18021807
_PyXI_Fini(PyInterpreterState *interp)
18031808
{
1809+
_PyXI_state_t *state = _PyXI_GET_STATE(interp);
1810+
18041811
// Finalize exceptions (heap types).
18051812
// See _PyXI_FiniTypes() for the static types.
18061813
fini_heap_exctypes(&_PyXI_GET_STATE(interp)->exceptions);
18071814

18081815
// Finalize the XID lookup state (e.g. registry).
1809-
xid_lookup_fini(&_PyXI_GET_STATE(interp)->data_lookup);
1816+
xid_lookup_fini(&state->data_lookup);
18101817
if (_Py_IsMainInterpreter(interp)) {
18111818
xid_lookup_fini(&_PyXI_GET_GLOBAL_STATE(interp)->data_lookup);
18121819
}

Python/crossinterp_data_lookup.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#include "pycore_weakref.h" // _PyWeakref_GET_REF()
22

33

4-
typedef struct _xidregistry dlregistry_t;
5-
typedef struct _xidregitem dlregitem_t;
4+
typedef _PyXIData_registry_t dlregistry_t;
5+
typedef _PyXIData_regitem_t dlregitem_t;
66

77

88
// forward

Python/parking_lot.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,7 @@ _PySemaphore_Wait(_PySemaphore *sema, PyTime_t timeout, int detach)
221221
PyThreadState *tstate = NULL;
222222
if (detach) {
223223
tstate = _PyThreadState_GET();
224-
if (tstate && _Py_atomic_load_int_relaxed(&tstate->state) ==
225-
_Py_THREAD_ATTACHED) {
224+
if (tstate && _PyThreadState_IsAttached(tstate)) {
226225
// Only detach if we are attached
227226
PyEval_ReleaseThread(tstate);
228227
}

0 commit comments

Comments
 (0)