diff --git a/Include/internal/pycore_crossinterp.h b/Include/internal/pycore_crossinterp.h
index 2dd165eae74..e91e911feb3 100644
--- a/Include/internal/pycore_crossinterp.h
+++ b/Include/internal/pycore_crossinterp.h
@@ -38,28 +38,28 @@ extern int _Py_CallInInterpreterAndRawFree(
/* cross-interpreter data */
/**************************/
-typedef struct _xid _PyCrossInterpreterData;
-typedef PyObject *(*xid_newobjectfunc)(_PyCrossInterpreterData *);
+typedef struct _xid _PyXIData_t;
+typedef PyObject *(*xid_newobjectfunc)(_PyXIData_t *);
typedef void (*xid_freefunc)(void *);
-// _PyCrossInterpreterData is similar to Py_buffer as an effectively
+// _PyXIData_t is similar to Py_buffer as an effectively
// opaque struct that holds data outside the object machinery. This
// is necessary to pass safely between interpreters in the same process.
struct _xid {
// data is the cross-interpreter-safe derivation of a Python object
- // (see _PyObject_GetCrossInterpreterData). It will be NULL if the
+ // (see _PyObject_GetXIData). It will be NULL if the
// new_object func (below) encodes the data.
void *data;
// obj is the Python object from which the data was derived. This
// is non-NULL only if the data remains bound to the object in some
// way, such that the object must be "released" (via a decref) when
// the data is released. In that case the code that sets the field,
- // likely a registered "crossinterpdatafunc", is responsible for
+ // likely a registered "xidatafunc", is responsible for
// ensuring it owns the reference (i.e. incref).
PyObject *obj;
// interp is the ID of the owning interpreter of the original
// object. It corresponds to the active interpreter when
- // _PyObject_GetCrossInterpreterData() was called. This should only
+ // _PyObject_GetXIData() was called. This should only
// be set by the cross-interpreter machinery.
//
// We use the ID rather than the PyInterpreterState to avoid issues
@@ -77,96 +77,77 @@ struct _xid {
// okay (e.g. bytes) and for those types this field should be set
// to NULL. However, for most the data was allocated just for
// cross-interpreter use, so it must be freed when
- // _PyCrossInterpreterData_Release is called or the memory will
+ // _PyXIData_Release is called or the memory will
// leak. In that case, at the very least this field should be set
// to PyMem_RawFree (the default if not explicitly set to NULL).
// The call will happen with the original interpreter activated.
xid_freefunc free;
};
-PyAPI_FUNC(_PyCrossInterpreterData *) _PyCrossInterpreterData_New(void);
-PyAPI_FUNC(void) _PyCrossInterpreterData_Free(_PyCrossInterpreterData *data);
+PyAPI_FUNC(_PyXIData_t *) _PyXIData_New(void);
+PyAPI_FUNC(void) _PyXIData_Free(_PyXIData_t *data);
-#define _PyCrossInterpreterData_DATA(DATA) ((DATA)->data)
-#define _PyCrossInterpreterData_OBJ(DATA) ((DATA)->obj)
-#define _PyCrossInterpreterData_INTERPID(DATA) ((DATA)->interpid)
+#define _PyXIData_DATA(DATA) ((DATA)->data)
+#define _PyXIData_OBJ(DATA) ((DATA)->obj)
+#define _PyXIData_INTERPID(DATA) ((DATA)->interpid)
// Users should not need getters for "new_object" or "free".
+/* getting cross-interpreter data */
+
+typedef int (*xidatafunc)(PyThreadState *tstate, PyObject *, _PyXIData_t *);
+
+typedef struct _xid_lookup_state _PyXIData_lookup_t;
+
+PyAPI_FUNC(xidatafunc) _PyXIData_Lookup(PyObject *);
+PyAPI_FUNC(int) _PyObject_CheckXIData(PyObject *);
+PyAPI_FUNC(int) _PyObject_GetXIData(PyObject *, _PyXIData_t *);
+
+
+/* using cross-interpreter data */
+
+PyAPI_FUNC(PyObject *) _PyXIData_NewObject(_PyXIData_t *);
+PyAPI_FUNC(int) _PyXIData_Release(_PyXIData_t *);
+PyAPI_FUNC(int) _PyXIData_ReleaseAndRawFree(_PyXIData_t *);
+
+
/* defining cross-interpreter data */
-PyAPI_FUNC(void) _PyCrossInterpreterData_Init(
- _PyCrossInterpreterData *data,
+PyAPI_FUNC(void) _PyXIData_Init(
+ _PyXIData_t *data,
PyInterpreterState *interp, void *shared, PyObject *obj,
xid_newobjectfunc new_object);
-PyAPI_FUNC(int) _PyCrossInterpreterData_InitWithSize(
- _PyCrossInterpreterData *,
+PyAPI_FUNC(int) _PyXIData_InitWithSize(
+ _PyXIData_t *,
PyInterpreterState *interp, const size_t, PyObject *,
xid_newobjectfunc);
-PyAPI_FUNC(void) _PyCrossInterpreterData_Clear(
- PyInterpreterState *, _PyCrossInterpreterData *);
+PyAPI_FUNC(void) _PyXIData_Clear( PyInterpreterState *, _PyXIData_t *);
// Normally the Init* functions are sufficient. The only time
// additional initialization might be needed is to set the "free" func,
// though that should be infrequent.
-#define _PyCrossInterpreterData_SET_FREE(DATA, FUNC) \
+#define _PyXIData_SET_FREE(DATA, FUNC) \
do { \
(DATA)->free = (FUNC); \
} while (0)
// Additionally, some shareable types are essentially light wrappers
-// around other shareable types. The crossinterpdatafunc of the wrapper
+// around other shareable types. The xidatafunc of the wrapper
// can often be implemented by calling the wrapped object's
-// crossinterpdatafunc and then changing the "new_object" function.
-// We have _PyCrossInterpreterData_SET_NEW_OBJECT() here for that,
+// xidatafunc and then changing the "new_object" function.
+// We have _PyXIData_SET_NEW_OBJECT() here for that,
// but might be better to have a function like
-// _PyCrossInterpreterData_AdaptToWrapper() instead.
-#define _PyCrossInterpreterData_SET_NEW_OBJECT(DATA, FUNC) \
+// _PyXIData_AdaptToWrapper() instead.
+#define _PyXIData_SET_NEW_OBJECT(DATA, FUNC) \
do { \
(DATA)->new_object = (FUNC); \
} while (0)
-/* using cross-interpreter data */
-
-PyAPI_FUNC(int) _PyObject_CheckCrossInterpreterData(PyObject *);
-PyAPI_FUNC(int) _PyObject_GetCrossInterpreterData(PyObject *, _PyCrossInterpreterData *);
-PyAPI_FUNC(PyObject *) _PyCrossInterpreterData_NewObject(_PyCrossInterpreterData *);
-PyAPI_FUNC(int) _PyCrossInterpreterData_Release(_PyCrossInterpreterData *);
-PyAPI_FUNC(int) _PyCrossInterpreterData_ReleaseAndRawFree(_PyCrossInterpreterData *);
-
-
/* cross-interpreter data registry */
-// For now we use a global registry of shareable classes. An
-// alternative would be to add a tp_* slot for a class's
-// crossinterpdatafunc. It would be simpler and more efficient.
-
-typedef int (*crossinterpdatafunc)(PyThreadState *tstate, PyObject *,
- _PyCrossInterpreterData *);
-
-struct _xidregitem;
-
-struct _xidregitem {
- struct _xidregitem *prev;
- struct _xidregitem *next;
- /* This can be a dangling pointer, but only if weakref is set. */
- PyTypeObject *cls;
- /* This is NULL for builtin types. */
- PyObject *weakref;
- size_t refcount;
- crossinterpdatafunc getdata;
-};
-
-struct _xidregistry {
- int global; /* builtin types or heap types */
- int initialized;
- PyMutex mutex;
- struct _xidregitem *head;
-};
-
-PyAPI_FUNC(int) _PyCrossInterpreterData_RegisterClass(PyTypeObject *, crossinterpdatafunc);
-PyAPI_FUNC(int) _PyCrossInterpreterData_UnregisterClass(PyTypeObject *);
-PyAPI_FUNC(crossinterpdatafunc) _PyCrossInterpreterData_Lookup(PyObject *);
+#define Py_CORE_CROSSINTERP_DATA_REGISTRY_H
+#include "pycore_crossinterp_data_registry.h"
+#undef Py_CORE_CROSSINTERP_DATA_REGISTRY_H
/*****************************/
@@ -175,14 +156,12 @@ PyAPI_FUNC(crossinterpdatafunc) _PyCrossInterpreterData_Lookup(PyObject *);
struct _xi_runtime_state {
// builtin types
- // XXX Remove this field once we have a tp_* slot.
- struct _xidregistry registry;
+ _PyXIData_lookup_t data_lookup;
};
struct _xi_state {
// heap types
- // XXX Remove this field once we have a tp_* slot.
- struct _xidregistry registry;
+ _PyXIData_lookup_t data_lookup;
// heap types
PyObject *PyExc_NotShareableError;
@@ -190,7 +169,6 @@ struct _xi_state {
extern PyStatus _PyXI_Init(PyInterpreterState *interp);
extern void _PyXI_Fini(PyInterpreterState *interp);
-
extern PyStatus _PyXI_InitTypes(PyInterpreterState *interp);
extern void _PyXI_FiniTypes(PyInterpreterState *interp);
diff --git a/Include/internal/pycore_crossinterp_data_registry.h b/Include/internal/pycore_crossinterp_data_registry.h
new file mode 100644
index 00000000000..2990c6af62e
--- /dev/null
+++ b/Include/internal/pycore_crossinterp_data_registry.h
@@ -0,0 +1,36 @@
+#ifndef Py_CORE_CROSSINTERP_DATA_REGISTRY_H
+# error "this header must not be included directly"
+#endif
+
+
+// For now we use a global registry of shareable classes. An
+// alternative would be to add a tp_* slot for a class's
+// xidatafunc. It would be simpler and more efficient.
+
+struct _xidregitem;
+
+struct _xidregitem {
+ struct _xidregitem *prev;
+ struct _xidregitem *next;
+ /* This can be a dangling pointer, but only if weakref is set. */
+ PyTypeObject *cls;
+ /* This is NULL for builtin types. */
+ PyObject *weakref;
+ size_t refcount;
+ xidatafunc getdata;
+};
+
+struct _xidregistry {
+ int global; /* builtin types or heap types */
+ int initialized;
+ PyMutex mutex;
+ struct _xidregitem *head;
+};
+
+PyAPI_FUNC(int) _PyXIData_RegisterClass(PyTypeObject *, xidatafunc);
+PyAPI_FUNC(int) _PyXIData_UnregisterClass(PyTypeObject *);
+
+struct _xid_lookup_state {
+ // XXX Remove this field once we have a tp_* slot.
+ struct _xidregistry registry;
+};
diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h
index e99febab2f3..bd3d704cb77 100644
--- a/Include/internal/pycore_runtime_init.h
+++ b/Include/internal/pycore_runtime_init.h
@@ -50,8 +50,10 @@ extern PyTypeObject _PyExc_MemoryError;
.next_id = -1, \
}, \
.xi = { \
- .registry = { \
- .global = 1, \
+ .data_lookup = { \
+ .registry = { \
+ .global = 1, \
+ }, \
}, \
}, \
/* A TSS key must be initialized with Py_tss_NEEDS_INIT \
diff --git a/Makefile.pre.in b/Makefile.pre.in
index c650ecaf7be..a337223d4d8 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -1203,6 +1203,7 @@ PYTHON_HEADERS= \
$(srcdir)/Include/internal/pycore_context.h \
$(srcdir)/Include/internal/pycore_critical_section.h \
$(srcdir)/Include/internal/pycore_crossinterp.h \
+ $(srcdir)/Include/internal/pycore_crossinterp_data_registry.h \
$(srcdir)/Include/internal/pycore_debug_offsets.h \
$(srcdir)/Include/internal/pycore_descrobject.h \
$(srcdir)/Include/internal/pycore_dict.h \
diff --git a/Modules/_interpchannelsmodule.c b/Modules/_interpchannelsmodule.c
index 5dc032b46ca..b8d7dfb87cc 100644
--- a/Modules/_interpchannelsmodule.c
+++ b/Modules/_interpchannelsmodule.c
@@ -6,7 +6,7 @@
#endif
#include "Python.h"
-#include "pycore_crossinterp.h" // struct _xid
+#include "pycore_crossinterp.h" // _PyXIData_t
#include "pycore_interp.h" // _PyInterpreterState_LookUpID()
#include "pycore_pystate.h" // _PyInterpreterState_GetIDObject()
@@ -59,7 +59,7 @@ _globals (static struct globals):
first (struct _channelitem *):
next (struct _channelitem *):
...
- data (_PyCrossInterpreterData *):
+ data (_PyXIData_t *):
data (void *)
obj (PyObject *)
interpid (int64_t)
@@ -80,10 +80,10 @@ The above state includes the following allocations by the module:
* 1 struct _channelqueue
* for each item in each channel:
* 1 struct _channelitem
- * 1 _PyCrossInterpreterData
+ * 1 _PyXIData_t
The only objects in that global state are the references held by each
-channel's queue, which are safely managed via the _PyCrossInterpreterData_*()
+channel's queue, which are safely managed via the _PyXIData_*()
API.. The module does not create any objects that are shared globally.
*/
@@ -102,7 +102,7 @@ API.. The module does not create any objects that are shared globally.
#define XID_FREE 2
static int
-_release_xid_data(_PyCrossInterpreterData *data, int flags)
+_release_xid_data(_PyXIData_t *data, int flags)
{
int ignoreexc = flags & XID_IGNORE_EXC;
PyObject *exc;
@@ -111,10 +111,10 @@ _release_xid_data(_PyCrossInterpreterData *data, int flags)
}
int res;
if (flags & XID_FREE) {
- res = _PyCrossInterpreterData_ReleaseAndRawFree(data);
+ res = _PyXIData_ReleaseAndRawFree(data);
}
else {
- res = _PyCrossInterpreterData_Release(data);
+ res = _PyXIData_Release(data);
}
if (res < 0) {
/* The owning interpreter is already destroyed. */
@@ -519,7 +519,7 @@ typedef struct _channelitem {
This is necessary because item->data might be NULL,
meaning the interpreter has been destroyed. */
int64_t interpid;
- _PyCrossInterpreterData *data;
+ _PyXIData_t *data;
_waiting_t *waiting;
int unboundop;
struct _channelitem *next;
@@ -533,7 +533,7 @@ _channelitem_ID(_channelitem *item)
static void
_channelitem_init(_channelitem *item,
- int64_t interpid, _PyCrossInterpreterData *data,
+ int64_t interpid, _PyXIData_t *data,
_waiting_t *waiting, int unboundop)
{
if (interpid < 0) {
@@ -541,8 +541,8 @@ _channelitem_init(_channelitem *item,
}
else {
assert(data == NULL
- || _PyCrossInterpreterData_INTERPID(data) < 0
- || interpid == _PyCrossInterpreterData_INTERPID(data));
+ || _PyXIData_INTERPID(data) < 0
+ || interpid == _PyXIData_INTERPID(data));
}
*item = (_channelitem){
.interpid = interpid,
@@ -580,7 +580,7 @@ _channelitem_clear(_channelitem *item)
}
static _channelitem *
-_channelitem_new(int64_t interpid, _PyCrossInterpreterData *data,
+_channelitem_new(int64_t interpid, _PyXIData_t *data,
_waiting_t *waiting, int unboundop)
{
_channelitem *item = GLOBAL_MALLOC(_channelitem);
@@ -611,7 +611,7 @@ _channelitem_free_all(_channelitem *item)
static void
_channelitem_popped(_channelitem *item,
- _PyCrossInterpreterData **p_data, _waiting_t **p_waiting,
+ _PyXIData_t **p_data, _waiting_t **p_waiting,
int *p_unboundop)
{
assert(item->waiting == NULL || item->waiting->status == WAITING_ACQUIRED);
@@ -634,7 +634,7 @@ _channelitem_clear_interpreter(_channelitem *item)
assert(item->unboundop != UNBOUND_REMOVE);
return 0;
}
- assert(_PyCrossInterpreterData_INTERPID(item->data) == item->interpid);
+ assert(_PyXIData_INTERPID(item->data) == item->interpid);
switch (item->unboundop) {
case UNBOUND_REMOVE:
@@ -691,7 +691,7 @@ _channelqueue_free(_channelqueue *queue)
static int
_channelqueue_put(_channelqueue *queue,
- int64_t interpid, _PyCrossInterpreterData *data,
+ int64_t interpid, _PyXIData_t *data,
_waiting_t *waiting, int unboundop)
{
_channelitem *item = _channelitem_new(interpid, data, waiting, unboundop);
@@ -717,7 +717,7 @@ _channelqueue_put(_channelqueue *queue,
static int
_channelqueue_get(_channelqueue *queue,
- _PyCrossInterpreterData **p_data, _waiting_t **p_waiting,
+ _PyXIData_t **p_data, _waiting_t **p_waiting,
int *p_unboundop)
{
_channelitem *item = queue->first;
@@ -769,7 +769,7 @@ _channelqueue_find(_channelqueue *queue, _channelitem_id_t itemid,
static void
_channelqueue_remove(_channelqueue *queue, _channelitem_id_t itemid,
- _PyCrossInterpreterData **p_data, _waiting_t **p_waiting)
+ _PyXIData_t **p_data, _waiting_t **p_waiting)
{
_channelitem *prev = NULL;
_channelitem *item = NULL;
@@ -1128,8 +1128,7 @@ _channel_free(_channel_state *chan)
static int
_channel_add(_channel_state *chan, int64_t interpid,
- _PyCrossInterpreterData *data, _waiting_t *waiting,
- int unboundop)
+ _PyXIData_t *data, _waiting_t *waiting, int unboundop)
{
int res = -1;
PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
@@ -1156,8 +1155,7 @@ done:
static int
_channel_next(_channel_state *chan, int64_t interpid,
- _PyCrossInterpreterData **p_data, _waiting_t **p_waiting,
- int *p_unboundop)
+ _PyXIData_t **p_data, _waiting_t **p_waiting, int *p_unboundop)
{
int err = 0;
PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
@@ -1193,7 +1191,7 @@ done:
static void
_channel_remove(_channel_state *chan, _channelitem_id_t itemid)
{
- _PyCrossInterpreterData *data = NULL;
+ _PyXIData_t *data = NULL;
_waiting_t *waiting = NULL;
PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
@@ -1776,12 +1774,12 @@ channel_send(_channels *channels, int64_t cid, PyObject *obj,
}
// Convert the object to cross-interpreter data.
- _PyCrossInterpreterData *data = GLOBAL_MALLOC(_PyCrossInterpreterData);
+ _PyXIData_t *data = GLOBAL_MALLOC(_PyXIData_t);
if (data == NULL) {
PyThread_release_lock(mutex);
return -1;
}
- if (_PyObject_GetCrossInterpreterData(obj, data) != 0) {
+ if (_PyObject_GetXIData(obj, data) != 0) {
PyThread_release_lock(mutex);
GLOBAL_FREE(data);
return -1;
@@ -1904,7 +1902,7 @@ channel_recv(_channels *channels, int64_t cid, PyObject **res, int *p_unboundop)
// Past this point we are responsible for releasing the mutex.
// Pop off the next item from the channel.
- _PyCrossInterpreterData *data = NULL;
+ _PyXIData_t *data = NULL;
_waiting_t *waiting = NULL;
err = _channel_next(chan, interpid, &data, &waiting, p_unboundop);
PyThread_release_lock(mutex);
@@ -1919,7 +1917,7 @@ channel_recv(_channels *channels, int64_t cid, PyObject **res, int *p_unboundop)
}
// Convert the data back to an object.
- PyObject *obj = _PyCrossInterpreterData_NewObject(data);
+ PyObject *obj = _PyXIData_NewObject(data);
if (obj == NULL) {
assert(PyErr_Occurred());
// It was allocated in channel_send(), so we free it.
@@ -2545,10 +2543,9 @@ struct _channelid_xid {
};
static PyObject *
-_channelid_from_xid(_PyCrossInterpreterData *data)
+_channelid_from_xid(_PyXIData_t *data)
{
- struct _channelid_xid *xid = \
- (struct _channelid_xid *)_PyCrossInterpreterData_DATA(data);
+ struct _channelid_xid *xid = (struct _channelid_xid *)_PyXIData_DATA(data);
// It might not be imported yet, so we can't use _get_current_module().
PyObject *mod = PyImport_ImportModule(MODULE_NAME_STR);
@@ -2594,18 +2591,16 @@ done:
}
static int
-_channelid_shared(PyThreadState *tstate, PyObject *obj,
- _PyCrossInterpreterData *data)
+_channelid_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data)
{
- if (_PyCrossInterpreterData_InitWithSize(
+ if (_PyXIData_InitWithSize(
data, tstate->interp, sizeof(struct _channelid_xid), obj,
_channelid_from_xid
) < 0)
{
return -1;
}
- struct _channelid_xid *xid = \
- (struct _channelid_xid *)_PyCrossInterpreterData_DATA(data);
+ struct _channelid_xid *xid = (struct _channelid_xid *)_PyXIData_DATA(data);
xid->cid = ((channelid *)obj)->cid;
xid->end = ((channelid *)obj)->end;
xid->resolve = ((channelid *)obj)->resolve;
@@ -2745,7 +2740,7 @@ _get_current_channelend_type(int end)
}
static PyObject *
-_channelend_from_xid(_PyCrossInterpreterData *data)
+_channelend_from_xid(_PyXIData_t *data)
{
channelid *cidobj = (channelid *)_channelid_from_xid(data);
if (cidobj == NULL) {
@@ -2762,8 +2757,7 @@ _channelend_from_xid(_PyCrossInterpreterData *data)
}
static int
-_channelend_shared(PyThreadState *tstate, PyObject *obj,
- _PyCrossInterpreterData *data)
+_channelend_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data)
{
PyObject *cidobj = PyObject_GetAttrString(obj, "_id");
if (cidobj == NULL) {
@@ -2774,7 +2768,7 @@ _channelend_shared(PyThreadState *tstate, PyObject *obj,
if (res < 0) {
return -1;
}
- _PyCrossInterpreterData_SET_NEW_OBJECT(data, _channelend_from_xid);
+ _PyXIData_SET_NEW_OBJECT(data, _channelend_from_xid);
return 0;
}
diff --git a/Modules/_interpqueuesmodule.c b/Modules/_interpqueuesmodule.c
index 297a1763a98..8d0e223db7f 100644
--- a/Modules/_interpqueuesmodule.c
+++ b/Modules/_interpqueuesmodule.c
@@ -6,7 +6,7 @@
#endif
#include "Python.h"
-#include "pycore_crossinterp.h" // struct _xid
+#include "pycore_crossinterp.h" // _PyXIData_t
#define REGISTERS_HEAP_TYPES
#define HAS_UNBOUND_ITEMS
@@ -30,7 +30,7 @@
#define XID_FREE 2
static int
-_release_xid_data(_PyCrossInterpreterData *data, int flags)
+_release_xid_data(_PyXIData_t *data, int flags)
{
int ignoreexc = flags & XID_IGNORE_EXC;
PyObject *exc;
@@ -39,10 +39,10 @@ _release_xid_data(_PyCrossInterpreterData *data, int flags)
}
int res;
if (flags & XID_FREE) {
- res = _PyCrossInterpreterData_ReleaseAndRawFree(data);
+ res = _PyXIData_ReleaseAndRawFree(data);
}
else {
- res = _PyCrossInterpreterData_Release(data);
+ res = _PyXIData_Release(data);
}
if (res < 0) {
/* The owning interpreter is already destroyed. */
@@ -400,7 +400,7 @@ typedef struct _queueitem {
This is necessary because item->data might be NULL,
meaning the interpreter has been destroyed. */
int64_t interpid;
- _PyCrossInterpreterData *data;
+ _PyXIData_t *data;
int fmt;
int unboundop;
struct _queueitem *next;
@@ -408,16 +408,15 @@ typedef struct _queueitem {
static void
_queueitem_init(_queueitem *item,
- int64_t interpid, _PyCrossInterpreterData *data,
- int fmt, int unboundop)
+ int64_t interpid, _PyXIData_t *data, int fmt, int unboundop)
{
if (interpid < 0) {
interpid = _get_interpid(data);
}
else {
assert(data == NULL
- || _PyCrossInterpreterData_INTERPID(data) < 0
- || interpid == _PyCrossInterpreterData_INTERPID(data));
+ || _PyXIData_INTERPID(data) < 0
+ || interpid == _PyXIData_INTERPID(data));
}
assert(check_unbound(unboundop));
*item = (_queueitem){
@@ -447,8 +446,7 @@ _queueitem_clear(_queueitem *item)
}
static _queueitem *
-_queueitem_new(int64_t interpid, _PyCrossInterpreterData *data,
- int fmt, int unboundop)
+_queueitem_new(int64_t interpid, _PyXIData_t *data, int fmt, int unboundop)
{
_queueitem *item = GLOBAL_MALLOC(_queueitem);
if (item == NULL) {
@@ -478,7 +476,7 @@ _queueitem_free_all(_queueitem *item)
static void
_queueitem_popped(_queueitem *item,
- _PyCrossInterpreterData **p_data, int *p_fmt, int *p_unboundop)
+ _PyXIData_t **p_data, int *p_fmt, int *p_unboundop)
{
*p_data = item->data;
*p_fmt = item->fmt;
@@ -498,7 +496,7 @@ _queueitem_clear_interpreter(_queueitem *item)
assert(item->unboundop != UNBOUND_REMOVE);
return 0;
}
- assert(_PyCrossInterpreterData_INTERPID(item->data) == item->interpid);
+ assert(_PyXIData_INTERPID(item->data) == item->interpid);
switch (item->unboundop) {
case UNBOUND_REMOVE:
@@ -633,7 +631,7 @@ _queue_unlock(_queue *queue)
}
static int
-_queue_add(_queue *queue, int64_t interpid, _PyCrossInterpreterData *data,
+_queue_add(_queue *queue, int64_t interpid, _PyXIData_t *data,
int fmt, int unboundop)
{
int err = _queue_lock(queue);
@@ -671,7 +669,7 @@ _queue_add(_queue *queue, int64_t interpid, _PyCrossInterpreterData *data,
static int
_queue_next(_queue *queue,
- _PyCrossInterpreterData **p_data, int *p_fmt, int *p_unboundop)
+ _PyXIData_t **p_data, int *p_fmt, int *p_unboundop)
{
int err = _queue_lock(queue);
if (err < 0) {
@@ -1138,17 +1136,17 @@ queue_put(_queues *queues, int64_t qid, PyObject *obj, int fmt, int unboundop)
assert(queue != NULL);
// Convert the object to cross-interpreter data.
- _PyCrossInterpreterData *data = GLOBAL_MALLOC(_PyCrossInterpreterData);
+ _PyXIData_t *data = GLOBAL_MALLOC(_PyXIData_t);
if (data == NULL) {
_queue_unmark_waiter(queue, queues->mutex);
return -1;
}
- if (_PyObject_GetCrossInterpreterData(obj, data) != 0) {
+ if (_PyObject_GetXIData(obj, data) != 0) {
_queue_unmark_waiter(queue, queues->mutex);
GLOBAL_FREE(data);
return -1;
}
- assert(_PyCrossInterpreterData_INTERPID(data) == \
+ assert(_PyXIData_INTERPID(data) == \
PyInterpreterState_GetID(PyInterpreterState_Get()));
// Add the data to the queue.
@@ -1184,7 +1182,7 @@ queue_get(_queues *queues, int64_t qid,
assert(queue != NULL);
// Pop off the next item from the queue.
- _PyCrossInterpreterData *data = NULL;
+ _PyXIData_t *data = NULL;
err = _queue_next(queue, &data, p_fmt, p_unboundop);
_queue_unmark_waiter(queue, queues->mutex);
if (err != 0) {
@@ -1196,7 +1194,7 @@ queue_get(_queues *queues, int64_t qid,
}
// Convert the data back to an object.
- PyObject *obj = _PyCrossInterpreterData_NewObject(data);
+ PyObject *obj = _PyXIData_NewObject(data);
if (obj == NULL) {
assert(PyErr_Occurred());
// It was allocated in queue_put(), so we free it.
@@ -1258,8 +1256,7 @@ queue_get_count(_queues *queues, int64_t qid, Py_ssize_t *p_count)
/* external Queue objects ***************************************************/
-static int _queueobj_shared(PyThreadState *,
- PyObject *, _PyCrossInterpreterData *);
+static int _queueobj_shared(PyThreadState *, PyObject *, _PyXIData_t *);
static int
set_external_queue_type(module_state *state, PyTypeObject *queue_type)
@@ -1339,9 +1336,9 @@ _queueid_xid_free(void *data)
}
static PyObject *
-_queueobj_from_xid(_PyCrossInterpreterData *data)
+_queueobj_from_xid(_PyXIData_t *data)
{
- int64_t qid = *(int64_t *)_PyCrossInterpreterData_DATA(data);
+ int64_t qid = *(int64_t *)_PyXIData_DATA(data);
PyObject *qidobj = PyLong_FromLongLong(qid);
if (qidobj == NULL) {
return NULL;
@@ -1367,8 +1364,7 @@ _queueobj_from_xid(_PyCrossInterpreterData *data)
}
static int
-_queueobj_shared(PyThreadState *tstate, PyObject *queueobj,
- _PyCrossInterpreterData *data)
+_queueobj_shared(PyThreadState *tstate, PyObject *queueobj, _PyXIData_t *data)
{
PyObject *qidobj = PyObject_GetAttrString(queueobj, "_id");
if (qidobj == NULL) {
@@ -1388,9 +1384,8 @@ _queueobj_shared(PyThreadState *tstate, PyObject *queueobj,
if (raw == NULL) {
return -1;
}
- _PyCrossInterpreterData_Init(data, tstate->interp, raw, NULL,
- _queueobj_from_xid);
- _PyCrossInterpreterData_SET_FREE(data, _queueid_xid_free);
+ _PyXIData_Init(data, tstate->interp, raw, NULL, _queueobj_from_xid);
+ _PyXIData_SET_FREE(data, _queueid_xid_free);
return 0;
}
diff --git a/Modules/_interpreters_common.h b/Modules/_interpreters_common.h
index 0d2e0c9efd3..b0e31a33734 100644
--- a/Modules/_interpreters_common.h
+++ b/Modules/_interpreters_common.h
@@ -6,27 +6,27 @@
static int
-ensure_xid_class(PyTypeObject *cls, crossinterpdatafunc getdata)
+ensure_xid_class(PyTypeObject *cls, xidatafunc getdata)
{
//assert(cls->tp_flags & Py_TPFLAGS_HEAPTYPE);
- return _PyCrossInterpreterData_RegisterClass(cls, getdata);
+ return _PyXIData_RegisterClass(cls, getdata);
}
#ifdef REGISTERS_HEAP_TYPES
static int
clear_xid_class(PyTypeObject *cls)
{
- return _PyCrossInterpreterData_UnregisterClass(cls);
+ return _PyXIData_UnregisterClass(cls);
}
#endif
static inline int64_t
-_get_interpid(_PyCrossInterpreterData *data)
+_get_interpid(_PyXIData_t *data)
{
int64_t interpid;
if (data != NULL) {
- interpid = _PyCrossInterpreterData_INTERPID(data);
+ interpid = _PyXIData_INTERPID(data);
assert(!PyErr_Occurred());
}
else {
diff --git a/Modules/_interpretersmodule.c b/Modules/_interpretersmodule.c
index 63f2bb38768..95acdd69e53 100644
--- a/Modules/_interpretersmodule.c
+++ b/Modules/_interpretersmodule.c
@@ -7,7 +7,7 @@
#include "Python.h"
#include "pycore_abstract.h" // _PyIndex_Check()
-#include "pycore_crossinterp.h" // struct _xid
+#include "pycore_crossinterp.h" // _PyXIData_t
#include "pycore_interp.h" // _PyInterpreterState_IDIncref()
#include "pycore_initconfig.h" // _PyErr_SetFromPyStatus()
#include "pycore_modsupport.h" // _PyArg_BadArgument()
@@ -84,18 +84,18 @@ typedef struct {
} XIBufferViewObject;
static PyObject *
-xibufferview_from_xid(PyTypeObject *cls, _PyCrossInterpreterData *data)
+xibufferview_from_xid(PyTypeObject *cls, _PyXIData_t *data)
{
- assert(_PyCrossInterpreterData_DATA(data) != NULL);
- assert(_PyCrossInterpreterData_OBJ(data) == NULL);
- assert(_PyCrossInterpreterData_INTERPID(data) >= 0);
+ assert(_PyXIData_DATA(data) != NULL);
+ assert(_PyXIData_OBJ(data) == NULL);
+ assert(_PyXIData_INTERPID(data) >= 0);
XIBufferViewObject *self = PyObject_Malloc(sizeof(XIBufferViewObject));
if (self == NULL) {
return NULL;
}
PyObject_Init((PyObject *)self, cls);
- self->view = (Py_buffer *)_PyCrossInterpreterData_DATA(data);
- self->interpid = _PyCrossInterpreterData_INTERPID(data);
+ self->view = (Py_buffer *)_PyXIData_DATA(data);
+ self->interpid = _PyXIData_INTERPID(data);
return (PyObject *)self;
}
@@ -154,7 +154,7 @@ static PyType_Spec XIBufferViewType_spec = {
static PyTypeObject * _get_current_xibufferview_type(void);
static PyObject *
-_memoryview_from_xid(_PyCrossInterpreterData *data)
+_memoryview_from_xid(_PyXIData_t *data)
{
PyTypeObject *cls = _get_current_xibufferview_type();
if (cls == NULL) {
@@ -168,8 +168,7 @@ _memoryview_from_xid(_PyCrossInterpreterData *data)
}
static int
-_memoryview_shared(PyThreadState *tstate, PyObject *obj,
- _PyCrossInterpreterData *data)
+_memoryview_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data)
{
Py_buffer *view = PyMem_RawMalloc(sizeof(Py_buffer));
if (view == NULL) {
@@ -179,8 +178,7 @@ _memoryview_shared(PyThreadState *tstate, PyObject *obj,
PyMem_RawFree(view);
return -1;
}
- _PyCrossInterpreterData_Init(data, tstate->interp, view, NULL,
- _memoryview_from_xid);
+ _PyXIData_Init(data, tstate->interp, view, NULL, _memoryview_from_xid);
return 0;
}
@@ -1183,7 +1181,7 @@ object_is_shareable(PyObject *self, PyObject *args, PyObject *kwds)
return NULL;
}
- if (_PyObject_CheckCrossInterpreterData(obj) == 0) {
+ if (_PyObject_CheckXIData(obj) == 0) {
Py_RETURN_TRUE;
}
PyErr_Clear();
diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c
index 883f32599fb..327a0776710 100644
--- a/Modules/_testinternalcapi.c
+++ b/Modules/_testinternalcapi.c
@@ -1787,11 +1787,10 @@ interpreter_refcount_linked(PyObject *self, PyObject *idobj)
static void
_xid_capsule_destructor(PyObject *capsule)
{
- _PyCrossInterpreterData *data = \
- (_PyCrossInterpreterData *)PyCapsule_GetPointer(capsule, NULL);
+ _PyXIData_t *data = (_PyXIData_t *)PyCapsule_GetPointer(capsule, NULL);
if (data != NULL) {
- assert(_PyCrossInterpreterData_Release(data) == 0);
- _PyCrossInterpreterData_Free(data);
+ assert(_PyXIData_Release(data) == 0);
+ _PyXIData_Free(data);
}
}
@@ -1803,18 +1802,18 @@ get_crossinterp_data(PyObject *self, PyObject *args)
return NULL;
}
- _PyCrossInterpreterData *data = _PyCrossInterpreterData_New();
+ _PyXIData_t *data = _PyXIData_New();
if (data == NULL) {
return NULL;
}
- if (_PyObject_GetCrossInterpreterData(obj, data) != 0) {
- _PyCrossInterpreterData_Free(data);
+ if (_PyObject_GetXIData(obj, data) != 0) {
+ _PyXIData_Free(data);
return NULL;
}
PyObject *capsule = PyCapsule_New(data, NULL, _xid_capsule_destructor);
if (capsule == NULL) {
- assert(_PyCrossInterpreterData_Release(data) == 0);
- _PyCrossInterpreterData_Free(data);
+ assert(_PyXIData_Release(data) == 0);
+ _PyXIData_Free(data);
}
return capsule;
}
@@ -1827,12 +1826,11 @@ restore_crossinterp_data(PyObject *self, PyObject *args)
return NULL;
}
- _PyCrossInterpreterData *data = \
- (_PyCrossInterpreterData *)PyCapsule_GetPointer(capsule, NULL);
+ _PyXIData_t *data = (_PyXIData_t *)PyCapsule_GetPointer(capsule, NULL);
if (data == NULL) {
return NULL;
}
- return _PyCrossInterpreterData_NewObject(data);
+ return _PyXIData_NewObject(data);
}
diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj
index f840e7fd61f..95552cade52 100644
--- a/PCbuild/pythoncore.vcxproj
+++ b/PCbuild/pythoncore.vcxproj
@@ -229,6 +229,7 @@
+
diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters
index a930cd0b0b1..1708cf6e0b3 100644
--- a/PCbuild/pythoncore.vcxproj.filters
+++ b/PCbuild/pythoncore.vcxproj.filters
@@ -609,6 +609,9 @@
Include\internal
+
+ Include\internal
+
Include\internal
diff --git a/Python/crossinterp.c b/Python/crossinterp.c
index 0aca322d987..2daba99988c 100644
--- a/Python/crossinterp.c
+++ b/Python/crossinterp.c
@@ -3,11 +3,14 @@
#include "Python.h"
#include "pycore_ceval.h" // _Py_simple_func
-#include "pycore_crossinterp.h" // struct _xid
+#include "pycore_crossinterp.h" // _PyXIData_t
#include "pycore_initconfig.h" // _PyStatus_OK()
#include "pycore_namespace.h" //_PyNamespace_New()
#include "pycore_pyerrors.h" // _PyErr_Clear()
-#include "pycore_weakref.h" // _PyWeakref_GET_REF()
+
+
+#define _PyXI_GET_GLOBAL_STATE(interp) (&(interp)->runtime->xi)
+#define _PyXI_GET_STATE(interp) (&(interp)->xi)
/**************/
@@ -57,25 +60,24 @@ _Py_CallInInterpreterAndRawFree(PyInterpreterState *interp,
/* cross-interpreter data */
/**************************/
-/* registry of {type -> crossinterpdatafunc} */
+/* registry of {type -> xidatafunc} */
/* For now we use a global registry of shareable classes. An
alternative would be to add a tp_* slot for a class's
- crossinterpdatafunc. It would be simpler and more efficient. */
+ xidatafunc. It would be simpler and more efficient. */
-static void xid_lookup_init(PyInterpreterState *);
-static void xid_lookup_fini(PyInterpreterState *);
-static crossinterpdatafunc lookup_getdata(PyInterpreterState *, PyObject *);
+static void xid_lookup_init(_PyXIData_lookup_t *);
+static void xid_lookup_fini(_PyXIData_lookup_t *);
+static xidatafunc lookup_getdata(PyInterpreterState *, PyObject *);
#include "crossinterp_data_lookup.h"
/* lifecycle */
-_PyCrossInterpreterData *
-_PyCrossInterpreterData_New(void)
+_PyXIData_t *
+_PyXIData_New(void)
{
- _PyCrossInterpreterData *xid = PyMem_RawMalloc(
- sizeof(_PyCrossInterpreterData));
+ _PyXIData_t *xid = PyMem_RawMalloc(sizeof(_PyXIData_t));
if (xid == NULL) {
PyErr_NoMemory();
}
@@ -83,10 +85,10 @@ _PyCrossInterpreterData_New(void)
}
void
-_PyCrossInterpreterData_Free(_PyCrossInterpreterData *xid)
+_PyXIData_Free(_PyXIData_t *xid)
{
PyInterpreterState *interp = PyInterpreterState_Get();
- _PyCrossInterpreterData_Clear(interp, xid);
+ _PyXIData_Clear(interp, xid);
PyMem_RawFree(xid);
}
@@ -94,20 +96,20 @@ _PyCrossInterpreterData_Free(_PyCrossInterpreterData *xid)
/* defining cross-interpreter data */
static inline void
-_xidata_init(_PyCrossInterpreterData *data)
+_xidata_init(_PyXIData_t *data)
{
// If the value is being reused
// then _xidata_clear() should have been called already.
assert(data->data == NULL);
assert(data->obj == NULL);
- *data = (_PyCrossInterpreterData){0};
- _PyCrossInterpreterData_INTERPID(data) = -1;
+ *data = (_PyXIData_t){0};
+ _PyXIData_INTERPID(data) = -1;
}
static inline void
-_xidata_clear(_PyCrossInterpreterData *data)
+_xidata_clear(_PyXIData_t *data)
{
- // _PyCrossInterpreterData only has two members that need to be
+ // _PyXIData_t only has two members that need to be
// cleaned up, if set: "data" must be freed and "obj" must be decref'ed.
// In both cases the original (owning) interpreter must be used,
// which is the caller's responsibility to ensure.
@@ -121,10 +123,10 @@ _xidata_clear(_PyCrossInterpreterData *data)
}
void
-_PyCrossInterpreterData_Init(_PyCrossInterpreterData *data,
- PyInterpreterState *interp,
- void *shared, PyObject *obj,
- xid_newobjectfunc new_object)
+_PyXIData_Init(_PyXIData_t *data,
+ PyInterpreterState *interp,
+ void *shared, PyObject *obj,
+ xid_newobjectfunc new_object)
{
assert(data != NULL);
assert(new_object != NULL);
@@ -132,29 +134,29 @@ _PyCrossInterpreterData_Init(_PyCrossInterpreterData *data,
data->data = shared;
if (obj != NULL) {
assert(interp != NULL);
- // released in _PyCrossInterpreterData_Clear()
+ // released in _PyXIData_Clear()
data->obj = Py_NewRef(obj);
}
// Ideally every object would know its owning interpreter.
// Until then, we have to rely on the caller to identify it
// (but we don't need it in all cases).
- _PyCrossInterpreterData_INTERPID(data) = (interp != NULL)
+ _PyXIData_INTERPID(data) = (interp != NULL)
? PyInterpreterState_GetID(interp)
: -1;
data->new_object = new_object;
}
int
-_PyCrossInterpreterData_InitWithSize(_PyCrossInterpreterData *data,
- PyInterpreterState *interp,
- const size_t size, PyObject *obj,
- xid_newobjectfunc new_object)
+_PyXIData_InitWithSize(_PyXIData_t *data,
+ PyInterpreterState *interp,
+ const size_t size, PyObject *obj,
+ xid_newobjectfunc new_object)
{
assert(size > 0);
// For now we always free the shared data in the same interpreter
// where it was allocated, so the interpreter is required.
assert(interp != NULL);
- _PyCrossInterpreterData_Init(data, interp, NULL, obj, new_object);
+ _PyXIData_Init(data, interp, NULL, obj, new_object);
data->data = PyMem_RawMalloc(size);
if (data->data == NULL) {
return -1;
@@ -164,14 +166,13 @@ _PyCrossInterpreterData_InitWithSize(_PyCrossInterpreterData *data,
}
void
-_PyCrossInterpreterData_Clear(PyInterpreterState *interp,
- _PyCrossInterpreterData *data)
+_PyXIData_Clear(PyInterpreterState *interp, _PyXIData_t *data)
{
assert(data != NULL);
// This must be called in the owning interpreter.
assert(interp == NULL
- || _PyCrossInterpreterData_INTERPID(data) == -1
- || _PyCrossInterpreterData_INTERPID(data) == PyInterpreterState_GetID(interp));
+ || _PyXIData_INTERPID(data) == -1
+ || _PyXIData_INTERPID(data) == PyInterpreterState_GetID(interp));
_xidata_clear(data);
}
@@ -179,13 +180,13 @@ _PyCrossInterpreterData_Clear(PyInterpreterState *interp,
/* using cross-interpreter data */
static int
-_check_xidata(PyThreadState *tstate, _PyCrossInterpreterData *data)
+_check_xidata(PyThreadState *tstate, _PyXIData_t *data)
{
// data->data can be anything, including NULL, so we don't check it.
// data->obj may be NULL, so we don't check it.
- if (_PyCrossInterpreterData_INTERPID(data) < 0) {
+ if (_PyXIData_INTERPID(data) < 0) {
PyErr_SetString(PyExc_SystemError, "missing interp");
return -1;
}
@@ -221,10 +222,10 @@ _set_xid_lookup_failure(PyInterpreterState *interp,
}
int
-_PyObject_CheckCrossInterpreterData(PyObject *obj)
+_PyObject_CheckXIData(PyObject *obj)
{
PyInterpreterState *interp = PyInterpreterState_Get();
- crossinterpdatafunc getdata = lookup_getdata(interp, obj);
+ xidatafunc getdata = lookup_getdata(interp, obj);
if (getdata == NULL) {
if (!PyErr_Occurred()) {
_set_xid_lookup_failure(interp, obj, NULL);
@@ -235,18 +236,18 @@ _PyObject_CheckCrossInterpreterData(PyObject *obj)
}
int
-_PyObject_GetCrossInterpreterData(PyObject *obj, _PyCrossInterpreterData *data)
+_PyObject_GetXIData(PyObject *obj, _PyXIData_t *data)
{
PyThreadState *tstate = PyThreadState_Get();
PyInterpreterState *interp = tstate->interp;
// Reset data before re-populating.
- *data = (_PyCrossInterpreterData){0};
- _PyCrossInterpreterData_INTERPID(data) = -1;
+ *data = (_PyXIData_t){0};
+ _PyXIData_INTERPID(data) = -1;
// Call the "getdata" func for the object.
Py_INCREF(obj);
- crossinterpdatafunc getdata = lookup_getdata(interp, obj);
+ xidatafunc getdata = lookup_getdata(interp, obj);
if (getdata == NULL) {
Py_DECREF(obj);
if (!PyErr_Occurred()) {
@@ -261,9 +262,9 @@ _PyObject_GetCrossInterpreterData(PyObject *obj, _PyCrossInterpreterData *data)
}
// Fill in the blanks and validate the result.
- _PyCrossInterpreterData_INTERPID(data) = PyInterpreterState_GetID(interp);
+ _PyXIData_INTERPID(data) = PyInterpreterState_GetID(interp);
if (_check_xidata(tstate, data) != 0) {
- (void)_PyCrossInterpreterData_Release(data);
+ (void)_PyXIData_Release(data);
return -1;
}
@@ -271,7 +272,7 @@ _PyObject_GetCrossInterpreterData(PyObject *obj, _PyCrossInterpreterData *data)
}
PyObject *
-_PyCrossInterpreterData_NewObject(_PyCrossInterpreterData *data)
+_PyXIData_NewObject(_PyXIData_t *data)
{
return data->new_object(data);
}
@@ -279,12 +280,12 @@ _PyCrossInterpreterData_NewObject(_PyCrossInterpreterData *data)
static int
_call_clear_xidata(void *data)
{
- _xidata_clear((_PyCrossInterpreterData *)data);
+ _xidata_clear((_PyXIData_t *)data);
return 0;
}
static int
-_xidata_release(_PyCrossInterpreterData *data, int rawfree)
+_xidata_release(_PyXIData_t *data, int rawfree)
{
if ((data->data == NULL || data->free == NULL) && data->obj == NULL) {
// Nothing to release!
@@ -299,7 +300,7 @@ _xidata_release(_PyCrossInterpreterData *data, int rawfree)
// Switch to the original interpreter.
PyInterpreterState *interp = _PyInterpreterState_LookUpID(
- _PyCrossInterpreterData_INTERPID(data));
+ _PyXIData_INTERPID(data));
if (interp == NULL) {
// The interpreter was already destroyed.
// This function shouldn't have been called.
@@ -321,13 +322,13 @@ _xidata_release(_PyCrossInterpreterData *data, int rawfree)
}
int
-_PyCrossInterpreterData_Release(_PyCrossInterpreterData *data)
+_PyXIData_Release(_PyXIData_t *data)
{
return _xidata_release(data, 0);
}
int
-_PyCrossInterpreterData_ReleaseAndRawFree(_PyCrossInterpreterData *data)
+_PyXIData_ReleaseAndRawFree(_PyXIData_t *data)
{
return _xidata_release(data, 1);
}
@@ -446,15 +447,15 @@ _format_TracebackException(PyObject *tbexc)
static int
-_release_xid_data(_PyCrossInterpreterData *data, int rawfree)
+_release_xid_data(_PyXIData_t *data, int rawfree)
{
PyObject *exc = PyErr_GetRaisedException();
int res = rawfree
- ? _PyCrossInterpreterData_Release(data)
- : _PyCrossInterpreterData_ReleaseAndRawFree(data);
+ ? _PyXIData_Release(data)
+ : _PyXIData_ReleaseAndRawFree(data);
if (res < 0) {
/* The owning interpreter is already destroyed. */
- _PyCrossInterpreterData_Clear(NULL, data);
+ _PyXIData_Clear(NULL, data);
// XXX Emit a warning?
PyErr_Clear();
}
@@ -1094,8 +1095,8 @@ _PyXI_ApplyError(_PyXI_error *error)
typedef struct _sharednsitem {
const char *name;
- _PyCrossInterpreterData *data;
- // We could have a "PyCrossInterpreterData _data" field, so it would
+ _PyXIData_t *data;
+ // We could have a "PyXIData _data" field, so it would
// be allocated as part of the item and avoid an extra allocation.
// However, doing so adds a bunch of complexity because we must
// ensure the item isn't freed before a pending call might happen
@@ -1131,7 +1132,7 @@ _sharednsitem_has_value(_PyXI_namespace_item *item, int64_t *p_interpid)
return 0;
}
if (p_interpid != NULL) {
- *p_interpid = _PyCrossInterpreterData_INTERPID(item->data);
+ *p_interpid = _PyXIData_INTERPID(item->data);
}
return 1;
}
@@ -1141,12 +1142,12 @@ _sharednsitem_set_value(_PyXI_namespace_item *item, PyObject *value)
{
assert(_sharednsitem_is_initialized(item));
assert(item->data == NULL);
- item->data = PyMem_RawMalloc(sizeof(_PyCrossInterpreterData));
+ item->data = PyMem_RawMalloc(sizeof(_PyXIData_t));
if (item->data == NULL) {
PyErr_NoMemory();
return -1;
}
- if (_PyObject_GetCrossInterpreterData(value, item->data) != 0) {
+ if (_PyObject_GetXIData(value, item->data) != 0) {
PyMem_RawFree(item->data);
item->data = NULL;
// The caller may want to propagate PyExc_NotShareableError
@@ -1159,7 +1160,7 @@ _sharednsitem_set_value(_PyXI_namespace_item *item, PyObject *value)
static void
_sharednsitem_clear_value(_PyXI_namespace_item *item)
{
- _PyCrossInterpreterData *data = item->data;
+ _PyXIData_t *data = item->data;
if (data != NULL) {
item->data = NULL;
int rawfree = 1;
@@ -1205,7 +1206,7 @@ _sharednsitem_apply(_PyXI_namespace_item *item, PyObject *ns, PyObject *dflt)
}
PyObject *value;
if (item->data != NULL) {
- value = _PyCrossInterpreterData_NewObject(item->data);
+ value = _PyXIData_NewObject(item->data);
if (value == NULL) {
Py_DECREF(name);
return -1;
@@ -1776,7 +1777,10 @@ PyStatus
_PyXI_Init(PyInterpreterState *interp)
{
// Initialize the XID lookup state (e.g. registry).
- xid_lookup_init(interp);
+ if (_Py_IsMainInterpreter(interp)) {
+ xid_lookup_init(&_PyXI_GET_GLOBAL_STATE(interp)->data_lookup);
+ }
+ xid_lookup_init(&_PyXI_GET_STATE(interp)->data_lookup);
// Initialize exceptions (heap types).
if (_init_not_shareable_error_type(interp) < 0) {
@@ -1796,7 +1800,10 @@ _PyXI_Fini(PyInterpreterState *interp)
_fini_not_shareable_error_type(interp);
// Finalize the XID lookup state (e.g. registry).
- xid_lookup_fini(interp);
+ xid_lookup_fini(&_PyXI_GET_STATE(interp)->data_lookup);
+ if (_Py_IsMainInterpreter(interp)) {
+ xid_lookup_fini(&_PyXI_GET_GLOBAL_STATE(interp)->data_lookup);
+ }
}
PyStatus
diff --git a/Python/crossinterp_data_lookup.h b/Python/crossinterp_data_lookup.h
index 863919ad42f..88c662a3df0 100644
--- a/Python/crossinterp_data_lookup.h
+++ b/Python/crossinterp_data_lookup.h
@@ -1,8 +1,31 @@
+#include "pycore_weakref.h" // _PyWeakref_GET_REF()
-static crossinterpdatafunc _lookup_getdata_from_registry(
- PyInterpreterState *, PyObject *);
-static crossinterpdatafunc
+typedef struct _xidregistry dlregistry_t;
+typedef struct _xidregitem dlregitem_t;
+
+
+// forward
+static void _xidregistry_init(dlregistry_t *);
+static void _xidregistry_fini(dlregistry_t *);
+static xidatafunc _lookup_getdata_from_registry(PyInterpreterState *, PyObject *);
+
+
+/* used in crossinterp.c */
+
+static void
+xid_lookup_init(_PyXIData_lookup_t *state)
+{
+ _xidregistry_init(&state->registry);
+}
+
+static void
+xid_lookup_fini(_PyXIData_lookup_t *state)
+{
+ _xidregistry_fini(&state->registry);
+}
+
+static xidatafunc
lookup_getdata(PyInterpreterState *interp, PyObject *obj)
{
/* Cross-interpreter objects are looked up by exact match on the class.
@@ -11,8 +34,11 @@ lookup_getdata(PyInterpreterState *interp, PyObject *obj)
return _lookup_getdata_from_registry(interp, obj);
}
-crossinterpdatafunc
-_PyCrossInterpreterData_Lookup(PyObject *obj)
+
+/* exported API */
+
+xidatafunc
+_PyXIData_Lookup(PyObject *obj)
{
PyInterpreterState *interp = PyInterpreterState_Get();
return lookup_getdata(interp, obj);
@@ -20,20 +46,20 @@ _PyCrossInterpreterData_Lookup(PyObject *obj)
/***********************************************/
-/* a registry of {type -> crossinterpdatafunc} */
+/* a registry of {type -> xidatafunc} */
/***********************************************/
/* For now we use a global registry of shareable classes. An
alternative would be to add a tp_* slot for a class's
- crossinterpdatafunc. It would be simpler and more efficient. */
+ xidatafunc. It would be simpler and more efficient. */
/* registry lifecycle */
-static void _register_builtins_for_crossinterpreter_data(struct _xidregistry *);
+static void _register_builtins_for_crossinterpreter_data(dlregistry_t *);
static void
-_xidregistry_init(struct _xidregistry *registry)
+_xidregistry_init(dlregistry_t *registry)
{
if (registry->initialized) {
return;
@@ -47,10 +73,10 @@ _xidregistry_init(struct _xidregistry *registry)
}
}
-static void _xidregistry_clear(struct _xidregistry *);
+static void _xidregistry_clear(dlregistry_t *);
static void
-_xidregistry_fini(struct _xidregistry *registry)
+_xidregistry_fini(dlregistry_t *registry)
{
if (!registry->initialized) {
return;
@@ -60,32 +86,11 @@ _xidregistry_fini(struct _xidregistry *registry)
_xidregistry_clear(registry);
}
-static inline struct _xidregistry * _get_global_xidregistry(_PyRuntimeState *);
-static inline struct _xidregistry * _get_xidregistry(PyInterpreterState *);
-
-static void
-xid_lookup_init(PyInterpreterState *interp)
-{
- if (_Py_IsMainInterpreter(interp)) {
- _xidregistry_init(_get_global_xidregistry(interp->runtime));
- }
- _xidregistry_init(_get_xidregistry(interp));
-}
-
-static void
-xid_lookup_fini(PyInterpreterState *interp)
-{
- _xidregistry_fini(_get_xidregistry(interp));
- if (_Py_IsMainInterpreter(interp)) {
- _xidregistry_fini(_get_global_xidregistry(interp->runtime));
- }
-}
-
/* registry thread safety */
static void
-_xidregistry_lock(struct _xidregistry *registry)
+_xidregistry_lock(dlregistry_t *registry)
{
if (registry->global) {
PyMutex_Lock(®istry->mutex);
@@ -94,7 +99,7 @@ _xidregistry_lock(struct _xidregistry *registry)
}
static void
-_xidregistry_unlock(struct _xidregistry *registry)
+_xidregistry_unlock(dlregistry_t *registry)
{
if (registry->global) {
PyMutex_Unlock(®istry->mutex);
@@ -104,35 +109,34 @@ _xidregistry_unlock(struct _xidregistry *registry)
/* accessing the registry */
-static inline struct _xidregistry *
+static inline dlregistry_t *
_get_global_xidregistry(_PyRuntimeState *runtime)
{
- return &runtime->xi.registry;
+ return &runtime->xi.data_lookup.registry;
}
-static inline struct _xidregistry *
+static inline dlregistry_t *
_get_xidregistry(PyInterpreterState *interp)
{
- return &interp->xi.registry;
+ return &interp->xi.data_lookup.registry;
}
-static inline struct _xidregistry *
+static inline dlregistry_t *
_get_xidregistry_for_type(PyInterpreterState *interp, PyTypeObject *cls)
{
- struct _xidregistry *registry = _get_global_xidregistry(interp->runtime);
+ dlregistry_t *registry = _get_global_xidregistry(interp->runtime);
if (cls->tp_flags & Py_TPFLAGS_HEAPTYPE) {
registry = _get_xidregistry(interp);
}
return registry;
}
-static struct _xidregitem * _xidregistry_remove_entry(
- struct _xidregistry *, struct _xidregitem *);
+static dlregitem_t* _xidregistry_remove_entry(dlregistry_t *, dlregitem_t *);
-static struct _xidregitem *
-_xidregistry_find_type(struct _xidregistry *xidregistry, PyTypeObject *cls)
+static dlregitem_t *
+_xidregistry_find_type(dlregistry_t *xidregistry, PyTypeObject *cls)
{
- struct _xidregitem *cur = xidregistry->head;
+ dlregitem_t *cur = xidregistry->head;
while (cur != NULL) {
if (cur->weakref != NULL) {
// cur is/was a heap type.
@@ -155,16 +159,16 @@ _xidregistry_find_type(struct _xidregistry *xidregistry, PyTypeObject *cls)
return NULL;
}
-static crossinterpdatafunc
+static xidatafunc
_lookup_getdata_from_registry(PyInterpreterState *interp, PyObject *obj)
{
PyTypeObject *cls = Py_TYPE(obj);
- struct _xidregistry *xidregistry = _get_xidregistry_for_type(interp, cls);
+ dlregistry_t *xidregistry = _get_xidregistry_for_type(interp, cls);
_xidregistry_lock(xidregistry);
- struct _xidregitem *matched = _xidregistry_find_type(xidregistry, cls);
- crossinterpdatafunc func = matched != NULL ? matched->getdata : NULL;
+ dlregitem_t *matched = _xidregistry_find_type(xidregistry, cls);
+ xidatafunc func = matched != NULL ? matched->getdata : NULL;
_xidregistry_unlock(xidregistry);
return func;
@@ -174,14 +178,14 @@ _lookup_getdata_from_registry(PyInterpreterState *interp, PyObject *obj)
/* updating the registry */
static int
-_xidregistry_add_type(struct _xidregistry *xidregistry,
- PyTypeObject *cls, crossinterpdatafunc getdata)
+_xidregistry_add_type(dlregistry_t *xidregistry,
+ PyTypeObject *cls, xidatafunc getdata)
{
- struct _xidregitem *newhead = PyMem_RawMalloc(sizeof(struct _xidregitem));
+ dlregitem_t *newhead = PyMem_RawMalloc(sizeof(dlregitem_t));
if (newhead == NULL) {
return -1;
}
- *newhead = (struct _xidregitem){
+ *newhead = (dlregitem_t){
// We do not keep a reference, to avoid keeping the class alive.
.cls = cls,
.refcount = 1,
@@ -203,11 +207,10 @@ _xidregistry_add_type(struct _xidregistry *xidregistry,
return 0;
}
-static struct _xidregitem *
-_xidregistry_remove_entry(struct _xidregistry *xidregistry,
- struct _xidregitem *entry)
+static dlregitem_t *
+_xidregistry_remove_entry(dlregistry_t *xidregistry, dlregitem_t *entry)
{
- struct _xidregitem *next = entry->next;
+ dlregitem_t *next = entry->next;
if (entry->prev != NULL) {
assert(entry->prev->next == entry);
entry->prev->next = next;
@@ -225,12 +228,12 @@ _xidregistry_remove_entry(struct _xidregistry *xidregistry,
}
static void
-_xidregistry_clear(struct _xidregistry *xidregistry)
+_xidregistry_clear(dlregistry_t *xidregistry)
{
- struct _xidregitem *cur = xidregistry->head;
+ dlregitem_t *cur = xidregistry->head;
xidregistry->head = NULL;
while (cur != NULL) {
- struct _xidregitem *next = cur->next;
+ dlregitem_t *next = cur->next;
Py_XDECREF(cur->weakref);
PyMem_RawFree(cur);
cur = next;
@@ -238,8 +241,7 @@ _xidregistry_clear(struct _xidregistry *xidregistry)
}
int
-_PyCrossInterpreterData_RegisterClass(PyTypeObject *cls,
- crossinterpdatafunc getdata)
+_PyXIData_RegisterClass(PyTypeObject *cls, xidatafunc getdata)
{
if (!PyType_Check(cls)) {
PyErr_Format(PyExc_ValueError, "only classes may be registered");
@@ -252,10 +254,10 @@ _PyCrossInterpreterData_RegisterClass(PyTypeObject *cls,
int res = 0;
PyInterpreterState *interp = _PyInterpreterState_GET();
- struct _xidregistry *xidregistry = _get_xidregistry_for_type(interp, cls);
+ dlregistry_t *xidregistry = _get_xidregistry_for_type(interp, cls);
_xidregistry_lock(xidregistry);
- struct _xidregitem *matched = _xidregistry_find_type(xidregistry, cls);
+ dlregitem_t *matched = _xidregistry_find_type(xidregistry, cls);
if (matched != NULL) {
assert(matched->getdata == getdata);
matched->refcount += 1;
@@ -270,14 +272,14 @@ finally:
}
int
-_PyCrossInterpreterData_UnregisterClass(PyTypeObject *cls)
+_PyXIData_UnregisterClass(PyTypeObject *cls)
{
int res = 0;
PyInterpreterState *interp = _PyInterpreterState_GET();
- struct _xidregistry *xidregistry = _get_xidregistry_for_type(interp, cls);
+ dlregistry_t *xidregistry = _get_xidregistry_for_type(interp, cls);
_xidregistry_lock(xidregistry);
- struct _xidregitem *matched = _xidregistry_find_type(xidregistry, cls);
+ dlregitem_t *matched = _xidregistry_find_type(xidregistry, cls);
if (matched != NULL) {
assert(matched->refcount > 0);
matched->refcount -= 1;
@@ -304,17 +306,16 @@ struct _shared_bytes_data {
};
static PyObject *
-_new_bytes_object(_PyCrossInterpreterData *data)
+_new_bytes_object(_PyXIData_t *data)
{
struct _shared_bytes_data *shared = (struct _shared_bytes_data *)(data->data);
return PyBytes_FromStringAndSize(shared->bytes, shared->len);
}
static int
-_bytes_shared(PyThreadState *tstate, PyObject *obj,
- _PyCrossInterpreterData *data)
+_bytes_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data)
{
- if (_PyCrossInterpreterData_InitWithSize(
+ if (_PyXIData_InitWithSize(
data, tstate->interp, sizeof(struct _shared_bytes_data), obj,
_new_bytes_object
) < 0)
@@ -323,7 +324,7 @@ _bytes_shared(PyThreadState *tstate, PyObject *obj,
}
struct _shared_bytes_data *shared = (struct _shared_bytes_data *)data->data;
if (PyBytes_AsStringAndSize(obj, &shared->bytes, &shared->len) < 0) {
- _PyCrossInterpreterData_Clear(tstate->interp, data);
+ _PyXIData_Clear(tstate->interp, data);
return -1;
}
return 0;
@@ -338,17 +339,16 @@ struct _shared_str_data {
};
static PyObject *
-_new_str_object(_PyCrossInterpreterData *data)
+_new_str_object(_PyXIData_t *data)
{
struct _shared_str_data *shared = (struct _shared_str_data *)(data->data);
return PyUnicode_FromKindAndData(shared->kind, shared->buffer, shared->len);
}
static int
-_str_shared(PyThreadState *tstate, PyObject *obj,
- _PyCrossInterpreterData *data)
+_str_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data)
{
- if (_PyCrossInterpreterData_InitWithSize(
+ if (_PyXIData_InitWithSize(
data, tstate->interp, sizeof(struct _shared_str_data), obj,
_new_str_object
) < 0)
@@ -365,14 +365,13 @@ _str_shared(PyThreadState *tstate, PyObject *obj,
// int
static PyObject *
-_new_long_object(_PyCrossInterpreterData *data)
+_new_long_object(_PyXIData_t *data)
{
return PyLong_FromSsize_t((Py_ssize_t)(data->data));
}
static int
-_long_shared(PyThreadState *tstate, PyObject *obj,
- _PyCrossInterpreterData *data)
+_long_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data)
{
/* Note that this means the size of shareable ints is bounded by
* sys.maxsize. Hence on 32-bit architectures that is half the
@@ -385,8 +384,7 @@ _long_shared(PyThreadState *tstate, PyObject *obj,
}
return -1;
}
- _PyCrossInterpreterData_Init(data, tstate->interp, (void *)value, NULL,
- _new_long_object);
+ _PyXIData_Init(data, tstate->interp, (void *)value, NULL, _new_long_object);
// data->obj and data->free remain NULL
return 0;
}
@@ -394,17 +392,16 @@ _long_shared(PyThreadState *tstate, PyObject *obj,
// float
static PyObject *
-_new_float_object(_PyCrossInterpreterData *data)
+_new_float_object(_PyXIData_t *data)
{
double * value_ptr = data->data;
return PyFloat_FromDouble(*value_ptr);
}
static int
-_float_shared(PyThreadState *tstate, PyObject *obj,
- _PyCrossInterpreterData *data)
+_float_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data)
{
- if (_PyCrossInterpreterData_InitWithSize(
+ if (_PyXIData_InitWithSize(
data, tstate->interp, sizeof(double), NULL,
_new_float_object
) < 0)
@@ -419,18 +416,16 @@ _float_shared(PyThreadState *tstate, PyObject *obj,
// None
static PyObject *
-_new_none_object(_PyCrossInterpreterData *data)
+_new_none_object(_PyXIData_t *data)
{
// XXX Singleton refcounts are problematic across interpreters...
return Py_NewRef(Py_None);
}
static int
-_none_shared(PyThreadState *tstate, PyObject *obj,
- _PyCrossInterpreterData *data)
+_none_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data)
{
- _PyCrossInterpreterData_Init(data, tstate->interp, NULL, NULL,
- _new_none_object);
+ _PyXIData_Init(data, tstate->interp, NULL, NULL, _new_none_object);
// data->data, data->obj and data->free remain NULL
return 0;
}
@@ -438,7 +433,7 @@ _none_shared(PyThreadState *tstate, PyObject *obj,
// bool
static PyObject *
-_new_bool_object(_PyCrossInterpreterData *data)
+_new_bool_object(_PyXIData_t *data)
{
if (data->data){
Py_RETURN_TRUE;
@@ -447,10 +442,9 @@ _new_bool_object(_PyCrossInterpreterData *data)
}
static int
-_bool_shared(PyThreadState *tstate, PyObject *obj,
- _PyCrossInterpreterData *data)
+_bool_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data)
{
- _PyCrossInterpreterData_Init(data, tstate->interp,
+ _PyXIData_Init(data, tstate->interp,
(void *) (Py_IsTrue(obj) ? (uintptr_t) 1 : (uintptr_t) 0), NULL,
_new_bool_object);
// data->obj and data->free remain NULL
@@ -461,11 +455,11 @@ _bool_shared(PyThreadState *tstate, PyObject *obj,
struct _shared_tuple_data {
Py_ssize_t len;
- _PyCrossInterpreterData **data;
+ _PyXIData_t **data;
};
static PyObject *
-_new_tuple_object(_PyCrossInterpreterData *data)
+_new_tuple_object(_PyXIData_t *data)
{
struct _shared_tuple_data *shared = (struct _shared_tuple_data *)(data->data);
PyObject *tuple = PyTuple_New(shared->len);
@@ -474,7 +468,7 @@ _new_tuple_object(_PyCrossInterpreterData *data)
}
for (Py_ssize_t i = 0; i < shared->len; i++) {
- PyObject *item = _PyCrossInterpreterData_NewObject(shared->data[i]);
+ PyObject *item = _PyXIData_NewObject(shared->data[i]);
if (item == NULL){
Py_DECREF(tuple);
return NULL;
@@ -493,8 +487,8 @@ _tuple_shared_free(void* data)
#endif
for (Py_ssize_t i = 0; i < shared->len; i++) {
if (shared->data[i] != NULL) {
- assert(_PyCrossInterpreterData_INTERPID(shared->data[i]) == interpid);
- _PyCrossInterpreterData_Release(shared->data[i]);
+ assert(_PyXIData_INTERPID(shared->data[i]) == interpid);
+ _PyXIData_Release(shared->data[i]);
PyMem_RawFree(shared->data[i]);
shared->data[i] = NULL;
}
@@ -504,8 +498,7 @@ _tuple_shared_free(void* data)
}
static int
-_tuple_shared(PyThreadState *tstate, PyObject *obj,
- _PyCrossInterpreterData *data)
+_tuple_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data)
{
Py_ssize_t len = PyTuple_GET_SIZE(obj);
if (len < 0) {
@@ -518,14 +511,14 @@ _tuple_shared(PyThreadState *tstate, PyObject *obj,
}
shared->len = len;
- shared->data = (_PyCrossInterpreterData **) PyMem_Calloc(shared->len, sizeof(_PyCrossInterpreterData *));
+ shared->data = (_PyXIData_t **) PyMem_Calloc(shared->len, sizeof(_PyXIData_t *));
if (shared->data == NULL) {
PyErr_NoMemory();
return -1;
}
for (Py_ssize_t i = 0; i < shared->len; i++) {
- _PyCrossInterpreterData *data = _PyCrossInterpreterData_New();
+ _PyXIData_t *data = _PyXIData_New();
if (data == NULL) {
goto error; // PyErr_NoMemory already set
}
@@ -533,7 +526,7 @@ _tuple_shared(PyThreadState *tstate, PyObject *obj,
int res = -1;
if (!_Py_EnterRecursiveCallTstate(tstate, " while sharing a tuple")) {
- res = _PyObject_GetCrossInterpreterData(item, data);
+ res = _PyObject_GetXIData(item, data);
_Py_LeaveRecursiveCallTstate(tstate);
}
if (res < 0) {
@@ -542,8 +535,7 @@ _tuple_shared(PyThreadState *tstate, PyObject *obj,
}
shared->data[i] = data;
}
- _PyCrossInterpreterData_Init(
- data, tstate->interp, shared, obj, _new_tuple_object);
+ _PyXIData_Init(data, tstate->interp, shared, obj, _new_tuple_object);
data->free = _tuple_shared_free;
return 0;
@@ -555,7 +547,7 @@ error:
// registration
static void
-_register_builtins_for_crossinterpreter_data(struct _xidregistry *xidregistry)
+_register_builtins_for_crossinterpreter_data(dlregistry_t *xidregistry)
{
// None
if (_xidregistry_add_type(xidregistry, (PyTypeObject *)PyObject_Type(Py_None), _none_shared) != 0) {
diff --git a/Python/pystate.c b/Python/pystate.c
index ded5fde9c4b..24ee73c145c 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -396,7 +396,7 @@ _Py_COMP_DIAG_POP
#define LOCKS_INIT(runtime) \
{ \
&(runtime)->interpreters.mutex, \
- &(runtime)->xi.registry.mutex, \
+ &(runtime)->xi.data_lookup.registry.mutex, \
&(runtime)->unicode_state.ids.mutex, \
&(runtime)->imports.extensions.mutex, \
&(runtime)->ceval.pending_mainthread.mutex, \
diff --git a/Tools/c-analyzer/cpython/_parser.py b/Tools/c-analyzer/cpython/_parser.py
index 3a73f65f8ff..21be53e7884 100644
--- a/Tools/c-analyzer/cpython/_parser.py
+++ b/Tools/c-analyzer/cpython/_parser.py
@@ -290,6 +290,7 @@ Modules/_dbmmodule.c HAVE_GDBM_DASH_NDBM_H 1
Modules/_sre/sre_lib.h LOCAL(type) static inline type
Modules/_sre/sre_lib.h SRE(F) sre_ucs2_##F
Objects/stringlib/codecs.h STRINGLIB_IS_UNICODE 1
+Include/internal/pycore_crossinterp_data_registry.h Py_CORE_CROSSINTERP_DATA_REGISTRY_H 1
# @end=tsv@
''')[1:]