Skip to content

Commit 64bd446

Browse files
ericsnowcurrentlypicnixz
authored andcommitted
pythongh-76785: Minor Cleanup of "Cross-interpreter" Code (pythongh-126457)
The primary objective here is to allow some later changes to be cleaner. Mostly this involves renaming things and moving a few things around. * CrossInterpreterData -> XIData * crossinterpdatafunc -> xidatafunc * split out pycore_crossinterp_data_registry.h * add _PyXIData_lookup_t
1 parent 379bbd5 commit 64bd446

15 files changed

+343
-337
lines changed

Include/internal/pycore_crossinterp.h

+46-68
Original file line numberDiff line numberDiff line change
@@ -38,28 +38,28 @@ extern int _Py_CallInInterpreterAndRawFree(
3838
/* cross-interpreter data */
3939
/**************************/
4040

41-
typedef struct _xid _PyCrossInterpreterData;
42-
typedef PyObject *(*xid_newobjectfunc)(_PyCrossInterpreterData *);
41+
typedef struct _xid _PyXIData_t;
42+
typedef PyObject *(*xid_newobjectfunc)(_PyXIData_t *);
4343
typedef void (*xid_freefunc)(void *);
4444

45-
// _PyCrossInterpreterData is similar to Py_buffer as an effectively
45+
// _PyXIData_t is similar to Py_buffer as an effectively
4646
// opaque struct that holds data outside the object machinery. This
4747
// is necessary to pass safely between interpreters in the same process.
4848
struct _xid {
4949
// data is the cross-interpreter-safe derivation of a Python object
50-
// (see _PyObject_GetCrossInterpreterData). It will be NULL if the
50+
// (see _PyObject_GetXIData). It will be NULL if the
5151
// new_object func (below) encodes the data.
5252
void *data;
5353
// obj is the Python object from which the data was derived. This
5454
// is non-NULL only if the data remains bound to the object in some
5555
// way, such that the object must be "released" (via a decref) when
5656
// the data is released. In that case the code that sets the field,
57-
// likely a registered "crossinterpdatafunc", is responsible for
57+
// likely a registered "xidatafunc", is responsible for
5858
// ensuring it owns the reference (i.e. incref).
5959
PyObject *obj;
6060
// interp is the ID of the owning interpreter of the original
6161
// object. It corresponds to the active interpreter when
62-
// _PyObject_GetCrossInterpreterData() was called. This should only
62+
// _PyObject_GetXIData() was called. This should only
6363
// be set by the cross-interpreter machinery.
6464
//
6565
// We use the ID rather than the PyInterpreterState to avoid issues
@@ -77,96 +77,77 @@ struct _xid {
7777
// okay (e.g. bytes) and for those types this field should be set
7878
// to NULL. However, for most the data was allocated just for
7979
// cross-interpreter use, so it must be freed when
80-
// _PyCrossInterpreterData_Release is called or the memory will
80+
// _PyXIData_Release is called or the memory will
8181
// leak. In that case, at the very least this field should be set
8282
// to PyMem_RawFree (the default if not explicitly set to NULL).
8383
// The call will happen with the original interpreter activated.
8484
xid_freefunc free;
8585
};
8686

87-
PyAPI_FUNC(_PyCrossInterpreterData *) _PyCrossInterpreterData_New(void);
88-
PyAPI_FUNC(void) _PyCrossInterpreterData_Free(_PyCrossInterpreterData *data);
87+
PyAPI_FUNC(_PyXIData_t *) _PyXIData_New(void);
88+
PyAPI_FUNC(void) _PyXIData_Free(_PyXIData_t *data);
8989

90-
#define _PyCrossInterpreterData_DATA(DATA) ((DATA)->data)
91-
#define _PyCrossInterpreterData_OBJ(DATA) ((DATA)->obj)
92-
#define _PyCrossInterpreterData_INTERPID(DATA) ((DATA)->interpid)
90+
#define _PyXIData_DATA(DATA) ((DATA)->data)
91+
#define _PyXIData_OBJ(DATA) ((DATA)->obj)
92+
#define _PyXIData_INTERPID(DATA) ((DATA)->interpid)
9393
// Users should not need getters for "new_object" or "free".
9494

9595

96+
/* getting cross-interpreter data */
97+
98+
typedef int (*xidatafunc)(PyThreadState *tstate, PyObject *, _PyXIData_t *);
99+
100+
typedef struct _xid_lookup_state _PyXIData_lookup_t;
101+
102+
PyAPI_FUNC(xidatafunc) _PyXIData_Lookup(PyObject *);
103+
PyAPI_FUNC(int) _PyObject_CheckXIData(PyObject *);
104+
PyAPI_FUNC(int) _PyObject_GetXIData(PyObject *, _PyXIData_t *);
105+
106+
107+
/* using cross-interpreter data */
108+
109+
PyAPI_FUNC(PyObject *) _PyXIData_NewObject(_PyXIData_t *);
110+
PyAPI_FUNC(int) _PyXIData_Release(_PyXIData_t *);
111+
PyAPI_FUNC(int) _PyXIData_ReleaseAndRawFree(_PyXIData_t *);
112+
113+
96114
/* defining cross-interpreter data */
97115

98-
PyAPI_FUNC(void) _PyCrossInterpreterData_Init(
99-
_PyCrossInterpreterData *data,
116+
PyAPI_FUNC(void) _PyXIData_Init(
117+
_PyXIData_t *data,
100118
PyInterpreterState *interp, void *shared, PyObject *obj,
101119
xid_newobjectfunc new_object);
102-
PyAPI_FUNC(int) _PyCrossInterpreterData_InitWithSize(
103-
_PyCrossInterpreterData *,
120+
PyAPI_FUNC(int) _PyXIData_InitWithSize(
121+
_PyXIData_t *,
104122
PyInterpreterState *interp, const size_t, PyObject *,
105123
xid_newobjectfunc);
106-
PyAPI_FUNC(void) _PyCrossInterpreterData_Clear(
107-
PyInterpreterState *, _PyCrossInterpreterData *);
124+
PyAPI_FUNC(void) _PyXIData_Clear( PyInterpreterState *, _PyXIData_t *);
108125

109126
// Normally the Init* functions are sufficient. The only time
110127
// additional initialization might be needed is to set the "free" func,
111128
// though that should be infrequent.
112-
#define _PyCrossInterpreterData_SET_FREE(DATA, FUNC) \
129+
#define _PyXIData_SET_FREE(DATA, FUNC) \
113130
do { \
114131
(DATA)->free = (FUNC); \
115132
} while (0)
116133
// Additionally, some shareable types are essentially light wrappers
117-
// around other shareable types. The crossinterpdatafunc of the wrapper
134+
// around other shareable types. The xidatafunc of the wrapper
118135
// can often be implemented by calling the wrapped object's
119-
// crossinterpdatafunc and then changing the "new_object" function.
120-
// We have _PyCrossInterpreterData_SET_NEW_OBJECT() here for that,
136+
// xidatafunc and then changing the "new_object" function.
137+
// We have _PyXIData_SET_NEW_OBJECT() here for that,
121138
// but might be better to have a function like
122-
// _PyCrossInterpreterData_AdaptToWrapper() instead.
123-
#define _PyCrossInterpreterData_SET_NEW_OBJECT(DATA, FUNC) \
139+
// _PyXIData_AdaptToWrapper() instead.
140+
#define _PyXIData_SET_NEW_OBJECT(DATA, FUNC) \
124141
do { \
125142
(DATA)->new_object = (FUNC); \
126143
} while (0)
127144

128145

129-
/* using cross-interpreter data */
130-
131-
PyAPI_FUNC(int) _PyObject_CheckCrossInterpreterData(PyObject *);
132-
PyAPI_FUNC(int) _PyObject_GetCrossInterpreterData(PyObject *, _PyCrossInterpreterData *);
133-
PyAPI_FUNC(PyObject *) _PyCrossInterpreterData_NewObject(_PyCrossInterpreterData *);
134-
PyAPI_FUNC(int) _PyCrossInterpreterData_Release(_PyCrossInterpreterData *);
135-
PyAPI_FUNC(int) _PyCrossInterpreterData_ReleaseAndRawFree(_PyCrossInterpreterData *);
136-
137-
138146
/* cross-interpreter data registry */
139147

140-
// For now we use a global registry of shareable classes. An
141-
// alternative would be to add a tp_* slot for a class's
142-
// crossinterpdatafunc. It would be simpler and more efficient.
143-
144-
typedef int (*crossinterpdatafunc)(PyThreadState *tstate, PyObject *,
145-
_PyCrossInterpreterData *);
146-
147-
struct _xidregitem;
148-
149-
struct _xidregitem {
150-
struct _xidregitem *prev;
151-
struct _xidregitem *next;
152-
/* This can be a dangling pointer, but only if weakref is set. */
153-
PyTypeObject *cls;
154-
/* This is NULL for builtin types. */
155-
PyObject *weakref;
156-
size_t refcount;
157-
crossinterpdatafunc getdata;
158-
};
159-
160-
struct _xidregistry {
161-
int global; /* builtin types or heap types */
162-
int initialized;
163-
PyMutex mutex;
164-
struct _xidregitem *head;
165-
};
166-
167-
PyAPI_FUNC(int) _PyCrossInterpreterData_RegisterClass(PyTypeObject *, crossinterpdatafunc);
168-
PyAPI_FUNC(int) _PyCrossInterpreterData_UnregisterClass(PyTypeObject *);
169-
PyAPI_FUNC(crossinterpdatafunc) _PyCrossInterpreterData_Lookup(PyObject *);
148+
#define Py_CORE_CROSSINTERP_DATA_REGISTRY_H
149+
#include "pycore_crossinterp_data_registry.h"
150+
#undef Py_CORE_CROSSINTERP_DATA_REGISTRY_H
170151

171152

172153
/*****************************/
@@ -175,22 +156,19 @@ PyAPI_FUNC(crossinterpdatafunc) _PyCrossInterpreterData_Lookup(PyObject *);
175156

176157
struct _xi_runtime_state {
177158
// builtin types
178-
// XXX Remove this field once we have a tp_* slot.
179-
struct _xidregistry registry;
159+
_PyXIData_lookup_t data_lookup;
180160
};
181161

182162
struct _xi_state {
183163
// heap types
184-
// XXX Remove this field once we have a tp_* slot.
185-
struct _xidregistry registry;
164+
_PyXIData_lookup_t data_lookup;
186165

187166
// heap types
188167
PyObject *PyExc_NotShareableError;
189168
};
190169

191170
extern PyStatus _PyXI_Init(PyInterpreterState *interp);
192171
extern void _PyXI_Fini(PyInterpreterState *interp);
193-
194172
extern PyStatus _PyXI_InitTypes(PyInterpreterState *interp);
195173
extern void _PyXI_FiniTypes(PyInterpreterState *interp);
196174

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#ifndef Py_CORE_CROSSINTERP_DATA_REGISTRY_H
2+
# error "this header must not be included directly"
3+
#endif
4+
5+
6+
// For now we use a global registry of shareable classes. An
7+
// alternative would be to add a tp_* slot for a class's
8+
// xidatafunc. It would be simpler and more efficient.
9+
10+
struct _xidregitem;
11+
12+
struct _xidregitem {
13+
struct _xidregitem *prev;
14+
struct _xidregitem *next;
15+
/* This can be a dangling pointer, but only if weakref is set. */
16+
PyTypeObject *cls;
17+
/* This is NULL for builtin types. */
18+
PyObject *weakref;
19+
size_t refcount;
20+
xidatafunc getdata;
21+
};
22+
23+
struct _xidregistry {
24+
int global; /* builtin types or heap types */
25+
int initialized;
26+
PyMutex mutex;
27+
struct _xidregitem *head;
28+
};
29+
30+
PyAPI_FUNC(int) _PyXIData_RegisterClass(PyTypeObject *, xidatafunc);
31+
PyAPI_FUNC(int) _PyXIData_UnregisterClass(PyTypeObject *);
32+
33+
struct _xid_lookup_state {
34+
// XXX Remove this field once we have a tp_* slot.
35+
struct _xidregistry registry;
36+
};

Include/internal/pycore_runtime_init.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,10 @@ extern PyTypeObject _PyExc_MemoryError;
5050
.next_id = -1, \
5151
}, \
5252
.xi = { \
53-
.registry = { \
54-
.global = 1, \
53+
.data_lookup = { \
54+
.registry = { \
55+
.global = 1, \
56+
}, \
5557
}, \
5658
}, \
5759
/* A TSS key must be initialized with Py_tss_NEEDS_INIT \

Makefile.pre.in

+1
Original file line numberDiff line numberDiff line change
@@ -1203,6 +1203,7 @@ PYTHON_HEADERS= \
12031203
$(srcdir)/Include/internal/pycore_context.h \
12041204
$(srcdir)/Include/internal/pycore_critical_section.h \
12051205
$(srcdir)/Include/internal/pycore_crossinterp.h \
1206+
$(srcdir)/Include/internal/pycore_crossinterp_data_registry.h \
12061207
$(srcdir)/Include/internal/pycore_debug_offsets.h \
12071208
$(srcdir)/Include/internal/pycore_descrobject.h \
12081209
$(srcdir)/Include/internal/pycore_dict.h \

0 commit comments

Comments
 (0)