gh-76785: Minor Cleanup of "Cross-interpreter" Code (gh-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
This commit is contained in:
Eric Snow 2024-11-07 09:32:42 -07:00 committed by GitHub
parent 3d9f9ae5a7
commit 9357fdcaf0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 343 additions and 337 deletions

View File

@ -38,28 +38,28 @@ extern int _Py_CallInInterpreterAndRawFree(
/* cross-interpreter data */ /* cross-interpreter data */
/**************************/ /**************************/
typedef struct _xid _PyCrossInterpreterData; typedef struct _xid _PyXIData_t;
typedef PyObject *(*xid_newobjectfunc)(_PyCrossInterpreterData *); typedef PyObject *(*xid_newobjectfunc)(_PyXIData_t *);
typedef void (*xid_freefunc)(void *); 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 // opaque struct that holds data outside the object machinery. This
// is necessary to pass safely between interpreters in the same process. // is necessary to pass safely between interpreters in the same process.
struct _xid { struct _xid {
// data is the cross-interpreter-safe derivation of a Python object // 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. // new_object func (below) encodes the data.
void *data; void *data;
// obj is the Python object from which the data was derived. This // 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 // 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 // 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, // 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). // ensuring it owns the reference (i.e. incref).
PyObject *obj; PyObject *obj;
// interp is the ID of the owning interpreter of the original // interp is the ID of the owning interpreter of the original
// object. It corresponds to the active interpreter when // 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. // be set by the cross-interpreter machinery.
// //
// We use the ID rather than the PyInterpreterState to avoid issues // 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 // okay (e.g. bytes) and for those types this field should be set
// to NULL. However, for most the data was allocated just for // to NULL. However, for most the data was allocated just for
// cross-interpreter use, so it must be freed when // 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 // leak. In that case, at the very least this field should be set
// to PyMem_RawFree (the default if not explicitly set to NULL). // to PyMem_RawFree (the default if not explicitly set to NULL).
// The call will happen with the original interpreter activated. // The call will happen with the original interpreter activated.
xid_freefunc free; xid_freefunc free;
}; };
PyAPI_FUNC(_PyCrossInterpreterData *) _PyCrossInterpreterData_New(void); PyAPI_FUNC(_PyXIData_t *) _PyXIData_New(void);
PyAPI_FUNC(void) _PyCrossInterpreterData_Free(_PyCrossInterpreterData *data); PyAPI_FUNC(void) _PyXIData_Free(_PyXIData_t *data);
#define _PyCrossInterpreterData_DATA(DATA) ((DATA)->data) #define _PyXIData_DATA(DATA) ((DATA)->data)
#define _PyCrossInterpreterData_OBJ(DATA) ((DATA)->obj) #define _PyXIData_OBJ(DATA) ((DATA)->obj)
#define _PyCrossInterpreterData_INTERPID(DATA) ((DATA)->interpid) #define _PyXIData_INTERPID(DATA) ((DATA)->interpid)
// Users should not need getters for "new_object" or "free". // 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 */ /* defining cross-interpreter data */
PyAPI_FUNC(void) _PyCrossInterpreterData_Init( PyAPI_FUNC(void) _PyXIData_Init(
_PyCrossInterpreterData *data, _PyXIData_t *data,
PyInterpreterState *interp, void *shared, PyObject *obj, PyInterpreterState *interp, void *shared, PyObject *obj,
xid_newobjectfunc new_object); xid_newobjectfunc new_object);
PyAPI_FUNC(int) _PyCrossInterpreterData_InitWithSize( PyAPI_FUNC(int) _PyXIData_InitWithSize(
_PyCrossInterpreterData *, _PyXIData_t *,
PyInterpreterState *interp, const size_t, PyObject *, PyInterpreterState *interp, const size_t, PyObject *,
xid_newobjectfunc); xid_newobjectfunc);
PyAPI_FUNC(void) _PyCrossInterpreterData_Clear( PyAPI_FUNC(void) _PyXIData_Clear( PyInterpreterState *, _PyXIData_t *);
PyInterpreterState *, _PyCrossInterpreterData *);
// Normally the Init* functions are sufficient. The only time // Normally the Init* functions are sufficient. The only time
// additional initialization might be needed is to set the "free" func, // additional initialization might be needed is to set the "free" func,
// though that should be infrequent. // though that should be infrequent.
#define _PyCrossInterpreterData_SET_FREE(DATA, FUNC) \ #define _PyXIData_SET_FREE(DATA, FUNC) \
do { \ do { \
(DATA)->free = (FUNC); \ (DATA)->free = (FUNC); \
} while (0) } while (0)
// Additionally, some shareable types are essentially light wrappers // 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 // can often be implemented by calling the wrapped object's
// crossinterpdatafunc and then changing the "new_object" function. // xidatafunc and then changing the "new_object" function.
// We have _PyCrossInterpreterData_SET_NEW_OBJECT() here for that, // We have _PyXIData_SET_NEW_OBJECT() here for that,
// but might be better to have a function like // but might be better to have a function like
// _PyCrossInterpreterData_AdaptToWrapper() instead. // _PyXIData_AdaptToWrapper() instead.
#define _PyCrossInterpreterData_SET_NEW_OBJECT(DATA, FUNC) \ #define _PyXIData_SET_NEW_OBJECT(DATA, FUNC) \
do { \ do { \
(DATA)->new_object = (FUNC); \ (DATA)->new_object = (FUNC); \
} while (0) } 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 */ /* cross-interpreter data registry */
// For now we use a global registry of shareable classes. An #define Py_CORE_CROSSINTERP_DATA_REGISTRY_H
// alternative would be to add a tp_* slot for a class's #include "pycore_crossinterp_data_registry.h"
// crossinterpdatafunc. It would be simpler and more efficient. #undef Py_CORE_CROSSINTERP_DATA_REGISTRY_H
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 *);
/*****************************/ /*****************************/
@ -175,14 +156,12 @@ PyAPI_FUNC(crossinterpdatafunc) _PyCrossInterpreterData_Lookup(PyObject *);
struct _xi_runtime_state { struct _xi_runtime_state {
// builtin types // builtin types
// XXX Remove this field once we have a tp_* slot. _PyXIData_lookup_t data_lookup;
struct _xidregistry registry;
}; };
struct _xi_state { struct _xi_state {
// heap types // heap types
// XXX Remove this field once we have a tp_* slot. _PyXIData_lookup_t data_lookup;
struct _xidregistry registry;
// heap types // heap types
PyObject *PyExc_NotShareableError; PyObject *PyExc_NotShareableError;
@ -190,7 +169,6 @@ struct _xi_state {
extern PyStatus _PyXI_Init(PyInterpreterState *interp); extern PyStatus _PyXI_Init(PyInterpreterState *interp);
extern void _PyXI_Fini(PyInterpreterState *interp); extern void _PyXI_Fini(PyInterpreterState *interp);
extern PyStatus _PyXI_InitTypes(PyInterpreterState *interp); extern PyStatus _PyXI_InitTypes(PyInterpreterState *interp);
extern void _PyXI_FiniTypes(PyInterpreterState *interp); extern void _PyXI_FiniTypes(PyInterpreterState *interp);

View File

@ -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;
};

View File

@ -50,10 +50,12 @@ extern PyTypeObject _PyExc_MemoryError;
.next_id = -1, \ .next_id = -1, \
}, \ }, \
.xi = { \ .xi = { \
.data_lookup = { \
.registry = { \ .registry = { \
.global = 1, \ .global = 1, \
}, \ }, \
}, \ }, \
}, \
/* A TSS key must be initialized with Py_tss_NEEDS_INIT \ /* A TSS key must be initialized with Py_tss_NEEDS_INIT \
in accordance with the specification. */ \ in accordance with the specification. */ \
.autoTSSkey = Py_tss_NEEDS_INIT, \ .autoTSSkey = Py_tss_NEEDS_INIT, \

View File

@ -1203,6 +1203,7 @@ PYTHON_HEADERS= \
$(srcdir)/Include/internal/pycore_context.h \ $(srcdir)/Include/internal/pycore_context.h \
$(srcdir)/Include/internal/pycore_critical_section.h \ $(srcdir)/Include/internal/pycore_critical_section.h \
$(srcdir)/Include/internal/pycore_crossinterp.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_debug_offsets.h \
$(srcdir)/Include/internal/pycore_descrobject.h \ $(srcdir)/Include/internal/pycore_descrobject.h \
$(srcdir)/Include/internal/pycore_dict.h \ $(srcdir)/Include/internal/pycore_dict.h \

View File

@ -6,7 +6,7 @@
#endif #endif
#include "Python.h" #include "Python.h"
#include "pycore_crossinterp.h" // struct _xid #include "pycore_crossinterp.h" // _PyXIData_t
#include "pycore_interp.h" // _PyInterpreterState_LookUpID() #include "pycore_interp.h" // _PyInterpreterState_LookUpID()
#include "pycore_pystate.h" // _PyInterpreterState_GetIDObject() #include "pycore_pystate.h" // _PyInterpreterState_GetIDObject()
@ -59,7 +59,7 @@ _globals (static struct globals):
first (struct _channelitem *): first (struct _channelitem *):
next (struct _channelitem *): next (struct _channelitem *):
... ...
data (_PyCrossInterpreterData *): data (_PyXIData_t *):
data (void *) data (void *)
obj (PyObject *) obj (PyObject *)
interpid (int64_t) interpid (int64_t)
@ -80,10 +80,10 @@ The above state includes the following allocations by the module:
* 1 struct _channelqueue * 1 struct _channelqueue
* for each item in each channel: * for each item in each channel:
* 1 struct _channelitem * 1 struct _channelitem
* 1 _PyCrossInterpreterData * 1 _PyXIData_t
The only objects in that global state are the references held by each 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. 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 #define XID_FREE 2
static int static int
_release_xid_data(_PyCrossInterpreterData *data, int flags) _release_xid_data(_PyXIData_t *data, int flags)
{ {
int ignoreexc = flags & XID_IGNORE_EXC; int ignoreexc = flags & XID_IGNORE_EXC;
PyObject *exc; PyObject *exc;
@ -111,10 +111,10 @@ _release_xid_data(_PyCrossInterpreterData *data, int flags)
} }
int res; int res;
if (flags & XID_FREE) { if (flags & XID_FREE) {
res = _PyCrossInterpreterData_ReleaseAndRawFree(data); res = _PyXIData_ReleaseAndRawFree(data);
} }
else { else {
res = _PyCrossInterpreterData_Release(data); res = _PyXIData_Release(data);
} }
if (res < 0) { if (res < 0) {
/* The owning interpreter is already destroyed. */ /* The owning interpreter is already destroyed. */
@ -519,7 +519,7 @@ typedef struct _channelitem {
This is necessary because item->data might be NULL, This is necessary because item->data might be NULL,
meaning the interpreter has been destroyed. */ meaning the interpreter has been destroyed. */
int64_t interpid; int64_t interpid;
_PyCrossInterpreterData *data; _PyXIData_t *data;
_waiting_t *waiting; _waiting_t *waiting;
int unboundop; int unboundop;
struct _channelitem *next; struct _channelitem *next;
@ -533,7 +533,7 @@ _channelitem_ID(_channelitem *item)
static void static void
_channelitem_init(_channelitem *item, _channelitem_init(_channelitem *item,
int64_t interpid, _PyCrossInterpreterData *data, int64_t interpid, _PyXIData_t *data,
_waiting_t *waiting, int unboundop) _waiting_t *waiting, int unboundop)
{ {
if (interpid < 0) { if (interpid < 0) {
@ -541,8 +541,8 @@ _channelitem_init(_channelitem *item,
} }
else { else {
assert(data == NULL assert(data == NULL
|| _PyCrossInterpreterData_INTERPID(data) < 0 || _PyXIData_INTERPID(data) < 0
|| interpid == _PyCrossInterpreterData_INTERPID(data)); || interpid == _PyXIData_INTERPID(data));
} }
*item = (_channelitem){ *item = (_channelitem){
.interpid = interpid, .interpid = interpid,
@ -580,7 +580,7 @@ _channelitem_clear(_channelitem *item)
} }
static _channelitem * static _channelitem *
_channelitem_new(int64_t interpid, _PyCrossInterpreterData *data, _channelitem_new(int64_t interpid, _PyXIData_t *data,
_waiting_t *waiting, int unboundop) _waiting_t *waiting, int unboundop)
{ {
_channelitem *item = GLOBAL_MALLOC(_channelitem); _channelitem *item = GLOBAL_MALLOC(_channelitem);
@ -611,7 +611,7 @@ _channelitem_free_all(_channelitem *item)
static void static void
_channelitem_popped(_channelitem *item, _channelitem_popped(_channelitem *item,
_PyCrossInterpreterData **p_data, _waiting_t **p_waiting, _PyXIData_t **p_data, _waiting_t **p_waiting,
int *p_unboundop) int *p_unboundop)
{ {
assert(item->waiting == NULL || item->waiting->status == WAITING_ACQUIRED); assert(item->waiting == NULL || item->waiting->status == WAITING_ACQUIRED);
@ -634,7 +634,7 @@ _channelitem_clear_interpreter(_channelitem *item)
assert(item->unboundop != UNBOUND_REMOVE); assert(item->unboundop != UNBOUND_REMOVE);
return 0; return 0;
} }
assert(_PyCrossInterpreterData_INTERPID(item->data) == item->interpid); assert(_PyXIData_INTERPID(item->data) == item->interpid);
switch (item->unboundop) { switch (item->unboundop) {
case UNBOUND_REMOVE: case UNBOUND_REMOVE:
@ -691,7 +691,7 @@ _channelqueue_free(_channelqueue *queue)
static int static int
_channelqueue_put(_channelqueue *queue, _channelqueue_put(_channelqueue *queue,
int64_t interpid, _PyCrossInterpreterData *data, int64_t interpid, _PyXIData_t *data,
_waiting_t *waiting, int unboundop) _waiting_t *waiting, int unboundop)
{ {
_channelitem *item = _channelitem_new(interpid, data, waiting, unboundop); _channelitem *item = _channelitem_new(interpid, data, waiting, unboundop);
@ -717,7 +717,7 @@ _channelqueue_put(_channelqueue *queue,
static int static int
_channelqueue_get(_channelqueue *queue, _channelqueue_get(_channelqueue *queue,
_PyCrossInterpreterData **p_data, _waiting_t **p_waiting, _PyXIData_t **p_data, _waiting_t **p_waiting,
int *p_unboundop) int *p_unboundop)
{ {
_channelitem *item = queue->first; _channelitem *item = queue->first;
@ -769,7 +769,7 @@ _channelqueue_find(_channelqueue *queue, _channelitem_id_t itemid,
static void static void
_channelqueue_remove(_channelqueue *queue, _channelitem_id_t itemid, _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 *prev = NULL;
_channelitem *item = NULL; _channelitem *item = NULL;
@ -1128,8 +1128,7 @@ _channel_free(_channel_state *chan)
static int static int
_channel_add(_channel_state *chan, int64_t interpid, _channel_add(_channel_state *chan, int64_t interpid,
_PyCrossInterpreterData *data, _waiting_t *waiting, _PyXIData_t *data, _waiting_t *waiting, int unboundop)
int unboundop)
{ {
int res = -1; int res = -1;
PyThread_acquire_lock(chan->mutex, WAIT_LOCK); PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
@ -1156,8 +1155,7 @@ done:
static int static int
_channel_next(_channel_state *chan, int64_t interpid, _channel_next(_channel_state *chan, int64_t interpid,
_PyCrossInterpreterData **p_data, _waiting_t **p_waiting, _PyXIData_t **p_data, _waiting_t **p_waiting, int *p_unboundop)
int *p_unboundop)
{ {
int err = 0; int err = 0;
PyThread_acquire_lock(chan->mutex, WAIT_LOCK); PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
@ -1193,7 +1191,7 @@ done:
static void static void
_channel_remove(_channel_state *chan, _channelitem_id_t itemid) _channel_remove(_channel_state *chan, _channelitem_id_t itemid)
{ {
_PyCrossInterpreterData *data = NULL; _PyXIData_t *data = NULL;
_waiting_t *waiting = NULL; _waiting_t *waiting = NULL;
PyThread_acquire_lock(chan->mutex, WAIT_LOCK); 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. // Convert the object to cross-interpreter data.
_PyCrossInterpreterData *data = GLOBAL_MALLOC(_PyCrossInterpreterData); _PyXIData_t *data = GLOBAL_MALLOC(_PyXIData_t);
if (data == NULL) { if (data == NULL) {
PyThread_release_lock(mutex); PyThread_release_lock(mutex);
return -1; return -1;
} }
if (_PyObject_GetCrossInterpreterData(obj, data) != 0) { if (_PyObject_GetXIData(obj, data) != 0) {
PyThread_release_lock(mutex); PyThread_release_lock(mutex);
GLOBAL_FREE(data); GLOBAL_FREE(data);
return -1; 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. // Past this point we are responsible for releasing the mutex.
// Pop off the next item from the channel. // Pop off the next item from the channel.
_PyCrossInterpreterData *data = NULL; _PyXIData_t *data = NULL;
_waiting_t *waiting = NULL; _waiting_t *waiting = NULL;
err = _channel_next(chan, interpid, &data, &waiting, p_unboundop); err = _channel_next(chan, interpid, &data, &waiting, p_unboundop);
PyThread_release_lock(mutex); 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. // Convert the data back to an object.
PyObject *obj = _PyCrossInterpreterData_NewObject(data); PyObject *obj = _PyXIData_NewObject(data);
if (obj == NULL) { if (obj == NULL) {
assert(PyErr_Occurred()); assert(PyErr_Occurred());
// It was allocated in channel_send(), so we free it. // It was allocated in channel_send(), so we free it.
@ -2545,10 +2543,9 @@ struct _channelid_xid {
}; };
static PyObject * static PyObject *
_channelid_from_xid(_PyCrossInterpreterData *data) _channelid_from_xid(_PyXIData_t *data)
{ {
struct _channelid_xid *xid = \ struct _channelid_xid *xid = (struct _channelid_xid *)_PyXIData_DATA(data);
(struct _channelid_xid *)_PyCrossInterpreterData_DATA(data);
// It might not be imported yet, so we can't use _get_current_module(). // It might not be imported yet, so we can't use _get_current_module().
PyObject *mod = PyImport_ImportModule(MODULE_NAME_STR); PyObject *mod = PyImport_ImportModule(MODULE_NAME_STR);
@ -2594,18 +2591,16 @@ done:
} }
static int static int
_channelid_shared(PyThreadState *tstate, PyObject *obj, _channelid_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data)
_PyCrossInterpreterData *data)
{ {
if (_PyCrossInterpreterData_InitWithSize( if (_PyXIData_InitWithSize(
data, tstate->interp, sizeof(struct _channelid_xid), obj, data, tstate->interp, sizeof(struct _channelid_xid), obj,
_channelid_from_xid _channelid_from_xid
) < 0) ) < 0)
{ {
return -1; return -1;
} }
struct _channelid_xid *xid = \ struct _channelid_xid *xid = (struct _channelid_xid *)_PyXIData_DATA(data);
(struct _channelid_xid *)_PyCrossInterpreterData_DATA(data);
xid->cid = ((channelid *)obj)->cid; xid->cid = ((channelid *)obj)->cid;
xid->end = ((channelid *)obj)->end; xid->end = ((channelid *)obj)->end;
xid->resolve = ((channelid *)obj)->resolve; xid->resolve = ((channelid *)obj)->resolve;
@ -2745,7 +2740,7 @@ _get_current_channelend_type(int end)
} }
static PyObject * static PyObject *
_channelend_from_xid(_PyCrossInterpreterData *data) _channelend_from_xid(_PyXIData_t *data)
{ {
channelid *cidobj = (channelid *)_channelid_from_xid(data); channelid *cidobj = (channelid *)_channelid_from_xid(data);
if (cidobj == NULL) { if (cidobj == NULL) {
@ -2762,8 +2757,7 @@ _channelend_from_xid(_PyCrossInterpreterData *data)
} }
static int static int
_channelend_shared(PyThreadState *tstate, PyObject *obj, _channelend_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data)
_PyCrossInterpreterData *data)
{ {
PyObject *cidobj = PyObject_GetAttrString(obj, "_id"); PyObject *cidobj = PyObject_GetAttrString(obj, "_id");
if (cidobj == NULL) { if (cidobj == NULL) {
@ -2774,7 +2768,7 @@ _channelend_shared(PyThreadState *tstate, PyObject *obj,
if (res < 0) { if (res < 0) {
return -1; return -1;
} }
_PyCrossInterpreterData_SET_NEW_OBJECT(data, _channelend_from_xid); _PyXIData_SET_NEW_OBJECT(data, _channelend_from_xid);
return 0; return 0;
} }

View File

@ -6,7 +6,7 @@
#endif #endif
#include "Python.h" #include "Python.h"
#include "pycore_crossinterp.h" // struct _xid #include "pycore_crossinterp.h" // _PyXIData_t
#define REGISTERS_HEAP_TYPES #define REGISTERS_HEAP_TYPES
#define HAS_UNBOUND_ITEMS #define HAS_UNBOUND_ITEMS
@ -30,7 +30,7 @@
#define XID_FREE 2 #define XID_FREE 2
static int static int
_release_xid_data(_PyCrossInterpreterData *data, int flags) _release_xid_data(_PyXIData_t *data, int flags)
{ {
int ignoreexc = flags & XID_IGNORE_EXC; int ignoreexc = flags & XID_IGNORE_EXC;
PyObject *exc; PyObject *exc;
@ -39,10 +39,10 @@ _release_xid_data(_PyCrossInterpreterData *data, int flags)
} }
int res; int res;
if (flags & XID_FREE) { if (flags & XID_FREE) {
res = _PyCrossInterpreterData_ReleaseAndRawFree(data); res = _PyXIData_ReleaseAndRawFree(data);
} }
else { else {
res = _PyCrossInterpreterData_Release(data); res = _PyXIData_Release(data);
} }
if (res < 0) { if (res < 0) {
/* The owning interpreter is already destroyed. */ /* The owning interpreter is already destroyed. */
@ -400,7 +400,7 @@ typedef struct _queueitem {
This is necessary because item->data might be NULL, This is necessary because item->data might be NULL,
meaning the interpreter has been destroyed. */ meaning the interpreter has been destroyed. */
int64_t interpid; int64_t interpid;
_PyCrossInterpreterData *data; _PyXIData_t *data;
int fmt; int fmt;
int unboundop; int unboundop;
struct _queueitem *next; struct _queueitem *next;
@ -408,16 +408,15 @@ typedef struct _queueitem {
static void static void
_queueitem_init(_queueitem *item, _queueitem_init(_queueitem *item,
int64_t interpid, _PyCrossInterpreterData *data, int64_t interpid, _PyXIData_t *data, int fmt, int unboundop)
int fmt, int unboundop)
{ {
if (interpid < 0) { if (interpid < 0) {
interpid = _get_interpid(data); interpid = _get_interpid(data);
} }
else { else {
assert(data == NULL assert(data == NULL
|| _PyCrossInterpreterData_INTERPID(data) < 0 || _PyXIData_INTERPID(data) < 0
|| interpid == _PyCrossInterpreterData_INTERPID(data)); || interpid == _PyXIData_INTERPID(data));
} }
assert(check_unbound(unboundop)); assert(check_unbound(unboundop));
*item = (_queueitem){ *item = (_queueitem){
@ -447,8 +446,7 @@ _queueitem_clear(_queueitem *item)
} }
static _queueitem * static _queueitem *
_queueitem_new(int64_t interpid, _PyCrossInterpreterData *data, _queueitem_new(int64_t interpid, _PyXIData_t *data, int fmt, int unboundop)
int fmt, int unboundop)
{ {
_queueitem *item = GLOBAL_MALLOC(_queueitem); _queueitem *item = GLOBAL_MALLOC(_queueitem);
if (item == NULL) { if (item == NULL) {
@ -478,7 +476,7 @@ _queueitem_free_all(_queueitem *item)
static void static void
_queueitem_popped(_queueitem *item, _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_data = item->data;
*p_fmt = item->fmt; *p_fmt = item->fmt;
@ -498,7 +496,7 @@ _queueitem_clear_interpreter(_queueitem *item)
assert(item->unboundop != UNBOUND_REMOVE); assert(item->unboundop != UNBOUND_REMOVE);
return 0; return 0;
} }
assert(_PyCrossInterpreterData_INTERPID(item->data) == item->interpid); assert(_PyXIData_INTERPID(item->data) == item->interpid);
switch (item->unboundop) { switch (item->unboundop) {
case UNBOUND_REMOVE: case UNBOUND_REMOVE:
@ -633,7 +631,7 @@ _queue_unlock(_queue *queue)
} }
static int 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 fmt, int unboundop)
{ {
int err = _queue_lock(queue); int err = _queue_lock(queue);
@ -671,7 +669,7 @@ _queue_add(_queue *queue, int64_t interpid, _PyCrossInterpreterData *data,
static int static int
_queue_next(_queue *queue, _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); int err = _queue_lock(queue);
if (err < 0) { if (err < 0) {
@ -1138,17 +1136,17 @@ queue_put(_queues *queues, int64_t qid, PyObject *obj, int fmt, int unboundop)
assert(queue != NULL); assert(queue != NULL);
// Convert the object to cross-interpreter data. // Convert the object to cross-interpreter data.
_PyCrossInterpreterData *data = GLOBAL_MALLOC(_PyCrossInterpreterData); _PyXIData_t *data = GLOBAL_MALLOC(_PyXIData_t);
if (data == NULL) { if (data == NULL) {
_queue_unmark_waiter(queue, queues->mutex); _queue_unmark_waiter(queue, queues->mutex);
return -1; return -1;
} }
if (_PyObject_GetCrossInterpreterData(obj, data) != 0) { if (_PyObject_GetXIData(obj, data) != 0) {
_queue_unmark_waiter(queue, queues->mutex); _queue_unmark_waiter(queue, queues->mutex);
GLOBAL_FREE(data); GLOBAL_FREE(data);
return -1; return -1;
} }
assert(_PyCrossInterpreterData_INTERPID(data) == \ assert(_PyXIData_INTERPID(data) == \
PyInterpreterState_GetID(PyInterpreterState_Get())); PyInterpreterState_GetID(PyInterpreterState_Get()));
// Add the data to the queue. // Add the data to the queue.
@ -1184,7 +1182,7 @@ queue_get(_queues *queues, int64_t qid,
assert(queue != NULL); assert(queue != NULL);
// Pop off the next item from the queue. // Pop off the next item from the queue.
_PyCrossInterpreterData *data = NULL; _PyXIData_t *data = NULL;
err = _queue_next(queue, &data, p_fmt, p_unboundop); err = _queue_next(queue, &data, p_fmt, p_unboundop);
_queue_unmark_waiter(queue, queues->mutex); _queue_unmark_waiter(queue, queues->mutex);
if (err != 0) { if (err != 0) {
@ -1196,7 +1194,7 @@ queue_get(_queues *queues, int64_t qid,
} }
// Convert the data back to an object. // Convert the data back to an object.
PyObject *obj = _PyCrossInterpreterData_NewObject(data); PyObject *obj = _PyXIData_NewObject(data);
if (obj == NULL) { if (obj == NULL) {
assert(PyErr_Occurred()); assert(PyErr_Occurred());
// It was allocated in queue_put(), so we free it. // 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 ***************************************************/ /* external Queue objects ***************************************************/
static int _queueobj_shared(PyThreadState *, static int _queueobj_shared(PyThreadState *, PyObject *, _PyXIData_t *);
PyObject *, _PyCrossInterpreterData *);
static int static int
set_external_queue_type(module_state *state, PyTypeObject *queue_type) set_external_queue_type(module_state *state, PyTypeObject *queue_type)
@ -1339,9 +1336,9 @@ _queueid_xid_free(void *data)
} }
static PyObject * 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); PyObject *qidobj = PyLong_FromLongLong(qid);
if (qidobj == NULL) { if (qidobj == NULL) {
return NULL; return NULL;
@ -1367,8 +1364,7 @@ _queueobj_from_xid(_PyCrossInterpreterData *data)
} }
static int static int
_queueobj_shared(PyThreadState *tstate, PyObject *queueobj, _queueobj_shared(PyThreadState *tstate, PyObject *queueobj, _PyXIData_t *data)
_PyCrossInterpreterData *data)
{ {
PyObject *qidobj = PyObject_GetAttrString(queueobj, "_id"); PyObject *qidobj = PyObject_GetAttrString(queueobj, "_id");
if (qidobj == NULL) { if (qidobj == NULL) {
@ -1388,9 +1384,8 @@ _queueobj_shared(PyThreadState *tstate, PyObject *queueobj,
if (raw == NULL) { if (raw == NULL) {
return -1; return -1;
} }
_PyCrossInterpreterData_Init(data, tstate->interp, raw, NULL, _PyXIData_Init(data, tstate->interp, raw, NULL, _queueobj_from_xid);
_queueobj_from_xid); _PyXIData_SET_FREE(data, _queueid_xid_free);
_PyCrossInterpreterData_SET_FREE(data, _queueid_xid_free);
return 0; return 0;
} }

View File

@ -6,27 +6,27 @@
static int static int
ensure_xid_class(PyTypeObject *cls, crossinterpdatafunc getdata) ensure_xid_class(PyTypeObject *cls, xidatafunc getdata)
{ {
//assert(cls->tp_flags & Py_TPFLAGS_HEAPTYPE); //assert(cls->tp_flags & Py_TPFLAGS_HEAPTYPE);
return _PyCrossInterpreterData_RegisterClass(cls, getdata); return _PyXIData_RegisterClass(cls, getdata);
} }
#ifdef REGISTERS_HEAP_TYPES #ifdef REGISTERS_HEAP_TYPES
static int static int
clear_xid_class(PyTypeObject *cls) clear_xid_class(PyTypeObject *cls)
{ {
return _PyCrossInterpreterData_UnregisterClass(cls); return _PyXIData_UnregisterClass(cls);
} }
#endif #endif
static inline int64_t static inline int64_t
_get_interpid(_PyCrossInterpreterData *data) _get_interpid(_PyXIData_t *data)
{ {
int64_t interpid; int64_t interpid;
if (data != NULL) { if (data != NULL) {
interpid = _PyCrossInterpreterData_INTERPID(data); interpid = _PyXIData_INTERPID(data);
assert(!PyErr_Occurred()); assert(!PyErr_Occurred());
} }
else { else {

View File

@ -7,7 +7,7 @@
#include "Python.h" #include "Python.h"
#include "pycore_abstract.h" // _PyIndex_Check() #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_interp.h" // _PyInterpreterState_IDIncref()
#include "pycore_initconfig.h" // _PyErr_SetFromPyStatus() #include "pycore_initconfig.h" // _PyErr_SetFromPyStatus()
#include "pycore_modsupport.h" // _PyArg_BadArgument() #include "pycore_modsupport.h" // _PyArg_BadArgument()
@ -84,18 +84,18 @@ typedef struct {
} XIBufferViewObject; } XIBufferViewObject;
static PyObject * static PyObject *
xibufferview_from_xid(PyTypeObject *cls, _PyCrossInterpreterData *data) xibufferview_from_xid(PyTypeObject *cls, _PyXIData_t *data)
{ {
assert(_PyCrossInterpreterData_DATA(data) != NULL); assert(_PyXIData_DATA(data) != NULL);
assert(_PyCrossInterpreterData_OBJ(data) == NULL); assert(_PyXIData_OBJ(data) == NULL);
assert(_PyCrossInterpreterData_INTERPID(data) >= 0); assert(_PyXIData_INTERPID(data) >= 0);
XIBufferViewObject *self = PyObject_Malloc(sizeof(XIBufferViewObject)); XIBufferViewObject *self = PyObject_Malloc(sizeof(XIBufferViewObject));
if (self == NULL) { if (self == NULL) {
return NULL; return NULL;
} }
PyObject_Init((PyObject *)self, cls); PyObject_Init((PyObject *)self, cls);
self->view = (Py_buffer *)_PyCrossInterpreterData_DATA(data); self->view = (Py_buffer *)_PyXIData_DATA(data);
self->interpid = _PyCrossInterpreterData_INTERPID(data); self->interpid = _PyXIData_INTERPID(data);
return (PyObject *)self; return (PyObject *)self;
} }
@ -154,7 +154,7 @@ static PyType_Spec XIBufferViewType_spec = {
static PyTypeObject * _get_current_xibufferview_type(void); static PyTypeObject * _get_current_xibufferview_type(void);
static PyObject * static PyObject *
_memoryview_from_xid(_PyCrossInterpreterData *data) _memoryview_from_xid(_PyXIData_t *data)
{ {
PyTypeObject *cls = _get_current_xibufferview_type(); PyTypeObject *cls = _get_current_xibufferview_type();
if (cls == NULL) { if (cls == NULL) {
@ -168,8 +168,7 @@ _memoryview_from_xid(_PyCrossInterpreterData *data)
} }
static int static int
_memoryview_shared(PyThreadState *tstate, PyObject *obj, _memoryview_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data)
_PyCrossInterpreterData *data)
{ {
Py_buffer *view = PyMem_RawMalloc(sizeof(Py_buffer)); Py_buffer *view = PyMem_RawMalloc(sizeof(Py_buffer));
if (view == NULL) { if (view == NULL) {
@ -179,8 +178,7 @@ _memoryview_shared(PyThreadState *tstate, PyObject *obj,
PyMem_RawFree(view); PyMem_RawFree(view);
return -1; return -1;
} }
_PyCrossInterpreterData_Init(data, tstate->interp, view, NULL, _PyXIData_Init(data, tstate->interp, view, NULL, _memoryview_from_xid);
_memoryview_from_xid);
return 0; return 0;
} }
@ -1183,7 +1181,7 @@ object_is_shareable(PyObject *self, PyObject *args, PyObject *kwds)
return NULL; return NULL;
} }
if (_PyObject_CheckCrossInterpreterData(obj) == 0) { if (_PyObject_CheckXIData(obj) == 0) {
Py_RETURN_TRUE; Py_RETURN_TRUE;
} }
PyErr_Clear(); PyErr_Clear();

View File

@ -1787,11 +1787,10 @@ interpreter_refcount_linked(PyObject *self, PyObject *idobj)
static void static void
_xid_capsule_destructor(PyObject *capsule) _xid_capsule_destructor(PyObject *capsule)
{ {
_PyCrossInterpreterData *data = \ _PyXIData_t *data = (_PyXIData_t *)PyCapsule_GetPointer(capsule, NULL);
(_PyCrossInterpreterData *)PyCapsule_GetPointer(capsule, NULL);
if (data != NULL) { if (data != NULL) {
assert(_PyCrossInterpreterData_Release(data) == 0); assert(_PyXIData_Release(data) == 0);
_PyCrossInterpreterData_Free(data); _PyXIData_Free(data);
} }
} }
@ -1803,18 +1802,18 @@ get_crossinterp_data(PyObject *self, PyObject *args)
return NULL; return NULL;
} }
_PyCrossInterpreterData *data = _PyCrossInterpreterData_New(); _PyXIData_t *data = _PyXIData_New();
if (data == NULL) { if (data == NULL) {
return NULL; return NULL;
} }
if (_PyObject_GetCrossInterpreterData(obj, data) != 0) { if (_PyObject_GetXIData(obj, data) != 0) {
_PyCrossInterpreterData_Free(data); _PyXIData_Free(data);
return NULL; return NULL;
} }
PyObject *capsule = PyCapsule_New(data, NULL, _xid_capsule_destructor); PyObject *capsule = PyCapsule_New(data, NULL, _xid_capsule_destructor);
if (capsule == NULL) { if (capsule == NULL) {
assert(_PyCrossInterpreterData_Release(data) == 0); assert(_PyXIData_Release(data) == 0);
_PyCrossInterpreterData_Free(data); _PyXIData_Free(data);
} }
return capsule; return capsule;
} }
@ -1827,12 +1826,11 @@ restore_crossinterp_data(PyObject *self, PyObject *args)
return NULL; return NULL;
} }
_PyCrossInterpreterData *data = \ _PyXIData_t *data = (_PyXIData_t *)PyCapsule_GetPointer(capsule, NULL);
(_PyCrossInterpreterData *)PyCapsule_GetPointer(capsule, NULL);
if (data == NULL) { if (data == NULL) {
return NULL; return NULL;
} }
return _PyCrossInterpreterData_NewObject(data); return _PyXIData_NewObject(data);
} }

View File

@ -229,6 +229,7 @@
<ClInclude Include="..\Include\internal\pycore_context.h" /> <ClInclude Include="..\Include\internal\pycore_context.h" />
<ClInclude Include="..\Include\internal\pycore_critical_section.h" /> <ClInclude Include="..\Include\internal\pycore_critical_section.h" />
<ClInclude Include="..\Include\internal\pycore_crossinterp.h" /> <ClInclude Include="..\Include\internal\pycore_crossinterp.h" />
<ClInclude Include="..\Include\internal\pycore_crossinterp_data_registry.h" />
<ClInclude Include="..\Include\internal\pycore_debug_offsets.h" /> <ClInclude Include="..\Include\internal\pycore_debug_offsets.h" />
<ClInclude Include="..\Include\internal\pycore_descrobject.h" /> <ClInclude Include="..\Include\internal\pycore_descrobject.h" />
<ClInclude Include="..\Include\internal\pycore_dict.h" /> <ClInclude Include="..\Include\internal\pycore_dict.h" />

View File

@ -609,6 +609,9 @@
<ClInclude Include="..\Include\internal\pycore_crossinterp.h"> <ClInclude Include="..\Include\internal\pycore_crossinterp.h">
<Filter>Include\internal</Filter> <Filter>Include\internal</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\Include\internal\pycore_crossinterp_data_registry.h">
<Filter>Include\internal</Filter>
</ClInclude>
<ClInclude Include="..\Include\internal\pycore_debug_offsets.h"> <ClInclude Include="..\Include\internal\pycore_debug_offsets.h">
<Filter>Include\internal</Filter> <Filter>Include\internal</Filter>
</ClInclude> </ClInclude>

View File

@ -3,11 +3,14 @@
#include "Python.h" #include "Python.h"
#include "pycore_ceval.h" // _Py_simple_func #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_initconfig.h" // _PyStatus_OK()
#include "pycore_namespace.h" //_PyNamespace_New() #include "pycore_namespace.h" //_PyNamespace_New()
#include "pycore_pyerrors.h" // _PyErr_Clear() #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 */ /* cross-interpreter data */
/**************************/ /**************************/
/* registry of {type -> crossinterpdatafunc} */ /* registry of {type -> xidatafunc} */
/* For now we use a global registry of shareable classes. An /* For now we use a global registry of shareable classes. An
alternative would be to add a tp_* slot for a class's 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_init(_PyXIData_lookup_t *);
static void xid_lookup_fini(PyInterpreterState *); static void xid_lookup_fini(_PyXIData_lookup_t *);
static crossinterpdatafunc lookup_getdata(PyInterpreterState *, PyObject *); static xidatafunc lookup_getdata(PyInterpreterState *, PyObject *);
#include "crossinterp_data_lookup.h" #include "crossinterp_data_lookup.h"
/* lifecycle */ /* lifecycle */
_PyCrossInterpreterData * _PyXIData_t *
_PyCrossInterpreterData_New(void) _PyXIData_New(void)
{ {
_PyCrossInterpreterData *xid = PyMem_RawMalloc( _PyXIData_t *xid = PyMem_RawMalloc(sizeof(_PyXIData_t));
sizeof(_PyCrossInterpreterData));
if (xid == NULL) { if (xid == NULL) {
PyErr_NoMemory(); PyErr_NoMemory();
} }
@ -83,10 +85,10 @@ _PyCrossInterpreterData_New(void)
} }
void void
_PyCrossInterpreterData_Free(_PyCrossInterpreterData *xid) _PyXIData_Free(_PyXIData_t *xid)
{ {
PyInterpreterState *interp = PyInterpreterState_Get(); PyInterpreterState *interp = PyInterpreterState_Get();
_PyCrossInterpreterData_Clear(interp, xid); _PyXIData_Clear(interp, xid);
PyMem_RawFree(xid); PyMem_RawFree(xid);
} }
@ -94,20 +96,20 @@ _PyCrossInterpreterData_Free(_PyCrossInterpreterData *xid)
/* defining cross-interpreter data */ /* defining cross-interpreter data */
static inline void static inline void
_xidata_init(_PyCrossInterpreterData *data) _xidata_init(_PyXIData_t *data)
{ {
// If the value is being reused // If the value is being reused
// then _xidata_clear() should have been called already. // then _xidata_clear() should have been called already.
assert(data->data == NULL); assert(data->data == NULL);
assert(data->obj == NULL); assert(data->obj == NULL);
*data = (_PyCrossInterpreterData){0}; *data = (_PyXIData_t){0};
_PyCrossInterpreterData_INTERPID(data) = -1; _PyXIData_INTERPID(data) = -1;
} }
static inline void 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. // cleaned up, if set: "data" must be freed and "obj" must be decref'ed.
// In both cases the original (owning) interpreter must be used, // In both cases the original (owning) interpreter must be used,
// which is the caller's responsibility to ensure. // which is the caller's responsibility to ensure.
@ -121,7 +123,7 @@ _xidata_clear(_PyCrossInterpreterData *data)
} }
void void
_PyCrossInterpreterData_Init(_PyCrossInterpreterData *data, _PyXIData_Init(_PyXIData_t *data,
PyInterpreterState *interp, PyInterpreterState *interp,
void *shared, PyObject *obj, void *shared, PyObject *obj,
xid_newobjectfunc new_object) xid_newobjectfunc new_object)
@ -132,20 +134,20 @@ _PyCrossInterpreterData_Init(_PyCrossInterpreterData *data,
data->data = shared; data->data = shared;
if (obj != NULL) { if (obj != NULL) {
assert(interp != NULL); assert(interp != NULL);
// released in _PyCrossInterpreterData_Clear() // released in _PyXIData_Clear()
data->obj = Py_NewRef(obj); data->obj = Py_NewRef(obj);
} }
// Ideally every object would know its owning interpreter. // Ideally every object would know its owning interpreter.
// Until then, we have to rely on the caller to identify it // Until then, we have to rely on the caller to identify it
// (but we don't need it in all cases). // (but we don't need it in all cases).
_PyCrossInterpreterData_INTERPID(data) = (interp != NULL) _PyXIData_INTERPID(data) = (interp != NULL)
? PyInterpreterState_GetID(interp) ? PyInterpreterState_GetID(interp)
: -1; : -1;
data->new_object = new_object; data->new_object = new_object;
} }
int int
_PyCrossInterpreterData_InitWithSize(_PyCrossInterpreterData *data, _PyXIData_InitWithSize(_PyXIData_t *data,
PyInterpreterState *interp, PyInterpreterState *interp,
const size_t size, PyObject *obj, const size_t size, PyObject *obj,
xid_newobjectfunc new_object) xid_newobjectfunc new_object)
@ -154,7 +156,7 @@ _PyCrossInterpreterData_InitWithSize(_PyCrossInterpreterData *data,
// For now we always free the shared data in the same interpreter // For now we always free the shared data in the same interpreter
// where it was allocated, so the interpreter is required. // where it was allocated, so the interpreter is required.
assert(interp != NULL); assert(interp != NULL);
_PyCrossInterpreterData_Init(data, interp, NULL, obj, new_object); _PyXIData_Init(data, interp, NULL, obj, new_object);
data->data = PyMem_RawMalloc(size); data->data = PyMem_RawMalloc(size);
if (data->data == NULL) { if (data->data == NULL) {
return -1; return -1;
@ -164,14 +166,13 @@ _PyCrossInterpreterData_InitWithSize(_PyCrossInterpreterData *data,
} }
void void
_PyCrossInterpreterData_Clear(PyInterpreterState *interp, _PyXIData_Clear(PyInterpreterState *interp, _PyXIData_t *data)
_PyCrossInterpreterData *data)
{ {
assert(data != NULL); assert(data != NULL);
// This must be called in the owning interpreter. // This must be called in the owning interpreter.
assert(interp == NULL assert(interp == NULL
|| _PyCrossInterpreterData_INTERPID(data) == -1 || _PyXIData_INTERPID(data) == -1
|| _PyCrossInterpreterData_INTERPID(data) == PyInterpreterState_GetID(interp)); || _PyXIData_INTERPID(data) == PyInterpreterState_GetID(interp));
_xidata_clear(data); _xidata_clear(data);
} }
@ -179,13 +180,13 @@ _PyCrossInterpreterData_Clear(PyInterpreterState *interp,
/* using cross-interpreter data */ /* using cross-interpreter data */
static int 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->data can be anything, including NULL, so we don't check it.
// data->obj may be 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"); PyErr_SetString(PyExc_SystemError, "missing interp");
return -1; return -1;
} }
@ -221,10 +222,10 @@ _set_xid_lookup_failure(PyInterpreterState *interp,
} }
int int
_PyObject_CheckCrossInterpreterData(PyObject *obj) _PyObject_CheckXIData(PyObject *obj)
{ {
PyInterpreterState *interp = PyInterpreterState_Get(); PyInterpreterState *interp = PyInterpreterState_Get();
crossinterpdatafunc getdata = lookup_getdata(interp, obj); xidatafunc getdata = lookup_getdata(interp, obj);
if (getdata == NULL) { if (getdata == NULL) {
if (!PyErr_Occurred()) { if (!PyErr_Occurred()) {
_set_xid_lookup_failure(interp, obj, NULL); _set_xid_lookup_failure(interp, obj, NULL);
@ -235,18 +236,18 @@ _PyObject_CheckCrossInterpreterData(PyObject *obj)
} }
int int
_PyObject_GetCrossInterpreterData(PyObject *obj, _PyCrossInterpreterData *data) _PyObject_GetXIData(PyObject *obj, _PyXIData_t *data)
{ {
PyThreadState *tstate = PyThreadState_Get(); PyThreadState *tstate = PyThreadState_Get();
PyInterpreterState *interp = tstate->interp; PyInterpreterState *interp = tstate->interp;
// Reset data before re-populating. // Reset data before re-populating.
*data = (_PyCrossInterpreterData){0}; *data = (_PyXIData_t){0};
_PyCrossInterpreterData_INTERPID(data) = -1; _PyXIData_INTERPID(data) = -1;
// Call the "getdata" func for the object. // Call the "getdata" func for the object.
Py_INCREF(obj); Py_INCREF(obj);
crossinterpdatafunc getdata = lookup_getdata(interp, obj); xidatafunc getdata = lookup_getdata(interp, obj);
if (getdata == NULL) { if (getdata == NULL) {
Py_DECREF(obj); Py_DECREF(obj);
if (!PyErr_Occurred()) { if (!PyErr_Occurred()) {
@ -261,9 +262,9 @@ _PyObject_GetCrossInterpreterData(PyObject *obj, _PyCrossInterpreterData *data)
} }
// Fill in the blanks and validate the result. // 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) { if (_check_xidata(tstate, data) != 0) {
(void)_PyCrossInterpreterData_Release(data); (void)_PyXIData_Release(data);
return -1; return -1;
} }
@ -271,7 +272,7 @@ _PyObject_GetCrossInterpreterData(PyObject *obj, _PyCrossInterpreterData *data)
} }
PyObject * PyObject *
_PyCrossInterpreterData_NewObject(_PyCrossInterpreterData *data) _PyXIData_NewObject(_PyXIData_t *data)
{ {
return data->new_object(data); return data->new_object(data);
} }
@ -279,12 +280,12 @@ _PyCrossInterpreterData_NewObject(_PyCrossInterpreterData *data)
static int static int
_call_clear_xidata(void *data) _call_clear_xidata(void *data)
{ {
_xidata_clear((_PyCrossInterpreterData *)data); _xidata_clear((_PyXIData_t *)data);
return 0; return 0;
} }
static int 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) { if ((data->data == NULL || data->free == NULL) && data->obj == NULL) {
// Nothing to release! // Nothing to release!
@ -299,7 +300,7 @@ _xidata_release(_PyCrossInterpreterData *data, int rawfree)
// Switch to the original interpreter. // Switch to the original interpreter.
PyInterpreterState *interp = _PyInterpreterState_LookUpID( PyInterpreterState *interp = _PyInterpreterState_LookUpID(
_PyCrossInterpreterData_INTERPID(data)); _PyXIData_INTERPID(data));
if (interp == NULL) { if (interp == NULL) {
// The interpreter was already destroyed. // The interpreter was already destroyed.
// This function shouldn't have been called. // This function shouldn't have been called.
@ -321,13 +322,13 @@ _xidata_release(_PyCrossInterpreterData *data, int rawfree)
} }
int int
_PyCrossInterpreterData_Release(_PyCrossInterpreterData *data) _PyXIData_Release(_PyXIData_t *data)
{ {
return _xidata_release(data, 0); return _xidata_release(data, 0);
} }
int int
_PyCrossInterpreterData_ReleaseAndRawFree(_PyCrossInterpreterData *data) _PyXIData_ReleaseAndRawFree(_PyXIData_t *data)
{ {
return _xidata_release(data, 1); return _xidata_release(data, 1);
} }
@ -446,15 +447,15 @@ _format_TracebackException(PyObject *tbexc)
static int static int
_release_xid_data(_PyCrossInterpreterData *data, int rawfree) _release_xid_data(_PyXIData_t *data, int rawfree)
{ {
PyObject *exc = PyErr_GetRaisedException(); PyObject *exc = PyErr_GetRaisedException();
int res = rawfree int res = rawfree
? _PyCrossInterpreterData_Release(data) ? _PyXIData_Release(data)
: _PyCrossInterpreterData_ReleaseAndRawFree(data); : _PyXIData_ReleaseAndRawFree(data);
if (res < 0) { if (res < 0) {
/* The owning interpreter is already destroyed. */ /* The owning interpreter is already destroyed. */
_PyCrossInterpreterData_Clear(NULL, data); _PyXIData_Clear(NULL, data);
// XXX Emit a warning? // XXX Emit a warning?
PyErr_Clear(); PyErr_Clear();
} }
@ -1094,8 +1095,8 @@ _PyXI_ApplyError(_PyXI_error *error)
typedef struct _sharednsitem { typedef struct _sharednsitem {
const char *name; const char *name;
_PyCrossInterpreterData *data; _PyXIData_t *data;
// We could have a "PyCrossInterpreterData _data" field, so it would // We could have a "PyXIData _data" field, so it would
// be allocated as part of the item and avoid an extra allocation. // be allocated as part of the item and avoid an extra allocation.
// However, doing so adds a bunch of complexity because we must // However, doing so adds a bunch of complexity because we must
// ensure the item isn't freed before a pending call might happen // 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; return 0;
} }
if (p_interpid != NULL) { if (p_interpid != NULL) {
*p_interpid = _PyCrossInterpreterData_INTERPID(item->data); *p_interpid = _PyXIData_INTERPID(item->data);
} }
return 1; return 1;
} }
@ -1141,12 +1142,12 @@ _sharednsitem_set_value(_PyXI_namespace_item *item, PyObject *value)
{ {
assert(_sharednsitem_is_initialized(item)); assert(_sharednsitem_is_initialized(item));
assert(item->data == NULL); assert(item->data == NULL);
item->data = PyMem_RawMalloc(sizeof(_PyCrossInterpreterData)); item->data = PyMem_RawMalloc(sizeof(_PyXIData_t));
if (item->data == NULL) { if (item->data == NULL) {
PyErr_NoMemory(); PyErr_NoMemory();
return -1; return -1;
} }
if (_PyObject_GetCrossInterpreterData(value, item->data) != 0) { if (_PyObject_GetXIData(value, item->data) != 0) {
PyMem_RawFree(item->data); PyMem_RawFree(item->data);
item->data = NULL; item->data = NULL;
// The caller may want to propagate PyExc_NotShareableError // The caller may want to propagate PyExc_NotShareableError
@ -1159,7 +1160,7 @@ _sharednsitem_set_value(_PyXI_namespace_item *item, PyObject *value)
static void static void
_sharednsitem_clear_value(_PyXI_namespace_item *item) _sharednsitem_clear_value(_PyXI_namespace_item *item)
{ {
_PyCrossInterpreterData *data = item->data; _PyXIData_t *data = item->data;
if (data != NULL) { if (data != NULL) {
item->data = NULL; item->data = NULL;
int rawfree = 1; int rawfree = 1;
@ -1205,7 +1206,7 @@ _sharednsitem_apply(_PyXI_namespace_item *item, PyObject *ns, PyObject *dflt)
} }
PyObject *value; PyObject *value;
if (item->data != NULL) { if (item->data != NULL) {
value = _PyCrossInterpreterData_NewObject(item->data); value = _PyXIData_NewObject(item->data);
if (value == NULL) { if (value == NULL) {
Py_DECREF(name); Py_DECREF(name);
return -1; return -1;
@ -1776,7 +1777,10 @@ PyStatus
_PyXI_Init(PyInterpreterState *interp) _PyXI_Init(PyInterpreterState *interp)
{ {
// Initialize the XID lookup state (e.g. registry). // 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). // Initialize exceptions (heap types).
if (_init_not_shareable_error_type(interp) < 0) { if (_init_not_shareable_error_type(interp) < 0) {
@ -1796,7 +1800,10 @@ _PyXI_Fini(PyInterpreterState *interp)
_fini_not_shareable_error_type(interp); _fini_not_shareable_error_type(interp);
// Finalize the XID lookup state (e.g. registry). // 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 PyStatus

View File

@ -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) lookup_getdata(PyInterpreterState *interp, PyObject *obj)
{ {
/* Cross-interpreter objects are looked up by exact match on the class. /* 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); return _lookup_getdata_from_registry(interp, obj);
} }
crossinterpdatafunc
_PyCrossInterpreterData_Lookup(PyObject *obj) /* exported API */
xidatafunc
_PyXIData_Lookup(PyObject *obj)
{ {
PyInterpreterState *interp = PyInterpreterState_Get(); PyInterpreterState *interp = PyInterpreterState_Get();
return lookup_getdata(interp, obj); 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 /* For now we use a global registry of shareable classes. An
alternative would be to add a tp_* slot for a class's 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 */ /* registry lifecycle */
static void _register_builtins_for_crossinterpreter_data(struct _xidregistry *); static void _register_builtins_for_crossinterpreter_data(dlregistry_t *);
static void static void
_xidregistry_init(struct _xidregistry *registry) _xidregistry_init(dlregistry_t *registry)
{ {
if (registry->initialized) { if (registry->initialized) {
return; return;
@ -47,10 +73,10 @@ _xidregistry_init(struct _xidregistry *registry)
} }
} }
static void _xidregistry_clear(struct _xidregistry *); static void _xidregistry_clear(dlregistry_t *);
static void static void
_xidregistry_fini(struct _xidregistry *registry) _xidregistry_fini(dlregistry_t *registry)
{ {
if (!registry->initialized) { if (!registry->initialized) {
return; return;
@ -60,32 +86,11 @@ _xidregistry_fini(struct _xidregistry *registry)
_xidregistry_clear(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 */ /* registry thread safety */
static void static void
_xidregistry_lock(struct _xidregistry *registry) _xidregistry_lock(dlregistry_t *registry)
{ {
if (registry->global) { if (registry->global) {
PyMutex_Lock(&registry->mutex); PyMutex_Lock(&registry->mutex);
@ -94,7 +99,7 @@ _xidregistry_lock(struct _xidregistry *registry)
} }
static void static void
_xidregistry_unlock(struct _xidregistry *registry) _xidregistry_unlock(dlregistry_t *registry)
{ {
if (registry->global) { if (registry->global) {
PyMutex_Unlock(&registry->mutex); PyMutex_Unlock(&registry->mutex);
@ -104,35 +109,34 @@ _xidregistry_unlock(struct _xidregistry *registry)
/* accessing the registry */ /* accessing the registry */
static inline struct _xidregistry * static inline dlregistry_t *
_get_global_xidregistry(_PyRuntimeState *runtime) _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) _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) _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) { if (cls->tp_flags & Py_TPFLAGS_HEAPTYPE) {
registry = _get_xidregistry(interp); registry = _get_xidregistry(interp);
} }
return registry; return registry;
} }
static struct _xidregitem * _xidregistry_remove_entry( static dlregitem_t* _xidregistry_remove_entry(dlregistry_t *, dlregitem_t *);
struct _xidregistry *, struct _xidregitem *);
static struct _xidregitem * static dlregitem_t *
_xidregistry_find_type(struct _xidregistry *xidregistry, PyTypeObject *cls) _xidregistry_find_type(dlregistry_t *xidregistry, PyTypeObject *cls)
{ {
struct _xidregitem *cur = xidregistry->head; dlregitem_t *cur = xidregistry->head;
while (cur != NULL) { while (cur != NULL) {
if (cur->weakref != NULL) { if (cur->weakref != NULL) {
// cur is/was a heap type. // cur is/was a heap type.
@ -155,16 +159,16 @@ _xidregistry_find_type(struct _xidregistry *xidregistry, PyTypeObject *cls)
return NULL; return NULL;
} }
static crossinterpdatafunc static xidatafunc
_lookup_getdata_from_registry(PyInterpreterState *interp, PyObject *obj) _lookup_getdata_from_registry(PyInterpreterState *interp, PyObject *obj)
{ {
PyTypeObject *cls = Py_TYPE(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); _xidregistry_lock(xidregistry);
struct _xidregitem *matched = _xidregistry_find_type(xidregistry, cls); dlregitem_t *matched = _xidregistry_find_type(xidregistry, cls);
crossinterpdatafunc func = matched != NULL ? matched->getdata : NULL; xidatafunc func = matched != NULL ? matched->getdata : NULL;
_xidregistry_unlock(xidregistry); _xidregistry_unlock(xidregistry);
return func; return func;
@ -174,14 +178,14 @@ _lookup_getdata_from_registry(PyInterpreterState *interp, PyObject *obj)
/* updating the registry */ /* updating the registry */
static int static int
_xidregistry_add_type(struct _xidregistry *xidregistry, _xidregistry_add_type(dlregistry_t *xidregistry,
PyTypeObject *cls, crossinterpdatafunc getdata) PyTypeObject *cls, xidatafunc getdata)
{ {
struct _xidregitem *newhead = PyMem_RawMalloc(sizeof(struct _xidregitem)); dlregitem_t *newhead = PyMem_RawMalloc(sizeof(dlregitem_t));
if (newhead == NULL) { if (newhead == NULL) {
return -1; return -1;
} }
*newhead = (struct _xidregitem){ *newhead = (dlregitem_t){
// We do not keep a reference, to avoid keeping the class alive. // We do not keep a reference, to avoid keeping the class alive.
.cls = cls, .cls = cls,
.refcount = 1, .refcount = 1,
@ -203,11 +207,10 @@ _xidregistry_add_type(struct _xidregistry *xidregistry,
return 0; return 0;
} }
static struct _xidregitem * static dlregitem_t *
_xidregistry_remove_entry(struct _xidregistry *xidregistry, _xidregistry_remove_entry(dlregistry_t *xidregistry, dlregitem_t *entry)
struct _xidregitem *entry)
{ {
struct _xidregitem *next = entry->next; dlregitem_t *next = entry->next;
if (entry->prev != NULL) { if (entry->prev != NULL) {
assert(entry->prev->next == entry); assert(entry->prev->next == entry);
entry->prev->next = next; entry->prev->next = next;
@ -225,12 +228,12 @@ _xidregistry_remove_entry(struct _xidregistry *xidregistry,
} }
static void 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; xidregistry->head = NULL;
while (cur != NULL) { while (cur != NULL) {
struct _xidregitem *next = cur->next; dlregitem_t *next = cur->next;
Py_XDECREF(cur->weakref); Py_XDECREF(cur->weakref);
PyMem_RawFree(cur); PyMem_RawFree(cur);
cur = next; cur = next;
@ -238,8 +241,7 @@ _xidregistry_clear(struct _xidregistry *xidregistry)
} }
int int
_PyCrossInterpreterData_RegisterClass(PyTypeObject *cls, _PyXIData_RegisterClass(PyTypeObject *cls, xidatafunc getdata)
crossinterpdatafunc getdata)
{ {
if (!PyType_Check(cls)) { if (!PyType_Check(cls)) {
PyErr_Format(PyExc_ValueError, "only classes may be registered"); PyErr_Format(PyExc_ValueError, "only classes may be registered");
@ -252,10 +254,10 @@ _PyCrossInterpreterData_RegisterClass(PyTypeObject *cls,
int res = 0; int res = 0;
PyInterpreterState *interp = _PyInterpreterState_GET(); 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); _xidregistry_lock(xidregistry);
struct _xidregitem *matched = _xidregistry_find_type(xidregistry, cls); dlregitem_t *matched = _xidregistry_find_type(xidregistry, cls);
if (matched != NULL) { if (matched != NULL) {
assert(matched->getdata == getdata); assert(matched->getdata == getdata);
matched->refcount += 1; matched->refcount += 1;
@ -270,14 +272,14 @@ finally:
} }
int int
_PyCrossInterpreterData_UnregisterClass(PyTypeObject *cls) _PyXIData_UnregisterClass(PyTypeObject *cls)
{ {
int res = 0; int res = 0;
PyInterpreterState *interp = _PyInterpreterState_GET(); 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); _xidregistry_lock(xidregistry);
struct _xidregitem *matched = _xidregistry_find_type(xidregistry, cls); dlregitem_t *matched = _xidregistry_find_type(xidregistry, cls);
if (matched != NULL) { if (matched != NULL) {
assert(matched->refcount > 0); assert(matched->refcount > 0);
matched->refcount -= 1; matched->refcount -= 1;
@ -304,17 +306,16 @@ struct _shared_bytes_data {
}; };
static PyObject * static PyObject *
_new_bytes_object(_PyCrossInterpreterData *data) _new_bytes_object(_PyXIData_t *data)
{ {
struct _shared_bytes_data *shared = (struct _shared_bytes_data *)(data->data); struct _shared_bytes_data *shared = (struct _shared_bytes_data *)(data->data);
return PyBytes_FromStringAndSize(shared->bytes, shared->len); return PyBytes_FromStringAndSize(shared->bytes, shared->len);
} }
static int static int
_bytes_shared(PyThreadState *tstate, PyObject *obj, _bytes_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data)
_PyCrossInterpreterData *data)
{ {
if (_PyCrossInterpreterData_InitWithSize( if (_PyXIData_InitWithSize(
data, tstate->interp, sizeof(struct _shared_bytes_data), obj, data, tstate->interp, sizeof(struct _shared_bytes_data), obj,
_new_bytes_object _new_bytes_object
) < 0) ) < 0)
@ -323,7 +324,7 @@ _bytes_shared(PyThreadState *tstate, PyObject *obj,
} }
struct _shared_bytes_data *shared = (struct _shared_bytes_data *)data->data; struct _shared_bytes_data *shared = (struct _shared_bytes_data *)data->data;
if (PyBytes_AsStringAndSize(obj, &shared->bytes, &shared->len) < 0) { if (PyBytes_AsStringAndSize(obj, &shared->bytes, &shared->len) < 0) {
_PyCrossInterpreterData_Clear(tstate->interp, data); _PyXIData_Clear(tstate->interp, data);
return -1; return -1;
} }
return 0; return 0;
@ -338,17 +339,16 @@ struct _shared_str_data {
}; };
static PyObject * static PyObject *
_new_str_object(_PyCrossInterpreterData *data) _new_str_object(_PyXIData_t *data)
{ {
struct _shared_str_data *shared = (struct _shared_str_data *)(data->data); struct _shared_str_data *shared = (struct _shared_str_data *)(data->data);
return PyUnicode_FromKindAndData(shared->kind, shared->buffer, shared->len); return PyUnicode_FromKindAndData(shared->kind, shared->buffer, shared->len);
} }
static int static int
_str_shared(PyThreadState *tstate, PyObject *obj, _str_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data)
_PyCrossInterpreterData *data)
{ {
if (_PyCrossInterpreterData_InitWithSize( if (_PyXIData_InitWithSize(
data, tstate->interp, sizeof(struct _shared_str_data), obj, data, tstate->interp, sizeof(struct _shared_str_data), obj,
_new_str_object _new_str_object
) < 0) ) < 0)
@ -365,14 +365,13 @@ _str_shared(PyThreadState *tstate, PyObject *obj,
// int // int
static PyObject * static PyObject *
_new_long_object(_PyCrossInterpreterData *data) _new_long_object(_PyXIData_t *data)
{ {
return PyLong_FromSsize_t((Py_ssize_t)(data->data)); return PyLong_FromSsize_t((Py_ssize_t)(data->data));
} }
static int static int
_long_shared(PyThreadState *tstate, PyObject *obj, _long_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data)
_PyCrossInterpreterData *data)
{ {
/* Note that this means the size of shareable ints is bounded by /* Note that this means the size of shareable ints is bounded by
* sys.maxsize. Hence on 32-bit architectures that is half the * sys.maxsize. Hence on 32-bit architectures that is half the
@ -385,8 +384,7 @@ _long_shared(PyThreadState *tstate, PyObject *obj,
} }
return -1; return -1;
} }
_PyCrossInterpreterData_Init(data, tstate->interp, (void *)value, NULL, _PyXIData_Init(data, tstate->interp, (void *)value, NULL, _new_long_object);
_new_long_object);
// data->obj and data->free remain NULL // data->obj and data->free remain NULL
return 0; return 0;
} }
@ -394,17 +392,16 @@ _long_shared(PyThreadState *tstate, PyObject *obj,
// float // float
static PyObject * static PyObject *
_new_float_object(_PyCrossInterpreterData *data) _new_float_object(_PyXIData_t *data)
{ {
double * value_ptr = data->data; double * value_ptr = data->data;
return PyFloat_FromDouble(*value_ptr); return PyFloat_FromDouble(*value_ptr);
} }
static int static int
_float_shared(PyThreadState *tstate, PyObject *obj, _float_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data)
_PyCrossInterpreterData *data)
{ {
if (_PyCrossInterpreterData_InitWithSize( if (_PyXIData_InitWithSize(
data, tstate->interp, sizeof(double), NULL, data, tstate->interp, sizeof(double), NULL,
_new_float_object _new_float_object
) < 0) ) < 0)
@ -419,18 +416,16 @@ _float_shared(PyThreadState *tstate, PyObject *obj,
// None // None
static PyObject * static PyObject *
_new_none_object(_PyCrossInterpreterData *data) _new_none_object(_PyXIData_t *data)
{ {
// XXX Singleton refcounts are problematic across interpreters... // XXX Singleton refcounts are problematic across interpreters...
return Py_NewRef(Py_None); return Py_NewRef(Py_None);
} }
static int static int
_none_shared(PyThreadState *tstate, PyObject *obj, _none_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data)
_PyCrossInterpreterData *data)
{ {
_PyCrossInterpreterData_Init(data, tstate->interp, NULL, NULL, _PyXIData_Init(data, tstate->interp, NULL, NULL, _new_none_object);
_new_none_object);
// data->data, data->obj and data->free remain NULL // data->data, data->obj and data->free remain NULL
return 0; return 0;
} }
@ -438,7 +433,7 @@ _none_shared(PyThreadState *tstate, PyObject *obj,
// bool // bool
static PyObject * static PyObject *
_new_bool_object(_PyCrossInterpreterData *data) _new_bool_object(_PyXIData_t *data)
{ {
if (data->data){ if (data->data){
Py_RETURN_TRUE; Py_RETURN_TRUE;
@ -447,10 +442,9 @@ _new_bool_object(_PyCrossInterpreterData *data)
} }
static int static int
_bool_shared(PyThreadState *tstate, PyObject *obj, _bool_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data)
_PyCrossInterpreterData *data)
{ {
_PyCrossInterpreterData_Init(data, tstate->interp, _PyXIData_Init(data, tstate->interp,
(void *) (Py_IsTrue(obj) ? (uintptr_t) 1 : (uintptr_t) 0), NULL, (void *) (Py_IsTrue(obj) ? (uintptr_t) 1 : (uintptr_t) 0), NULL,
_new_bool_object); _new_bool_object);
// data->obj and data->free remain NULL // data->obj and data->free remain NULL
@ -461,11 +455,11 @@ _bool_shared(PyThreadState *tstate, PyObject *obj,
struct _shared_tuple_data { struct _shared_tuple_data {
Py_ssize_t len; Py_ssize_t len;
_PyCrossInterpreterData **data; _PyXIData_t **data;
}; };
static PyObject * static PyObject *
_new_tuple_object(_PyCrossInterpreterData *data) _new_tuple_object(_PyXIData_t *data)
{ {
struct _shared_tuple_data *shared = (struct _shared_tuple_data *)(data->data); struct _shared_tuple_data *shared = (struct _shared_tuple_data *)(data->data);
PyObject *tuple = PyTuple_New(shared->len); 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++) { 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){ if (item == NULL){
Py_DECREF(tuple); Py_DECREF(tuple);
return NULL; return NULL;
@ -493,8 +487,8 @@ _tuple_shared_free(void* data)
#endif #endif
for (Py_ssize_t i = 0; i < shared->len; i++) { for (Py_ssize_t i = 0; i < shared->len; i++) {
if (shared->data[i] != NULL) { if (shared->data[i] != NULL) {
assert(_PyCrossInterpreterData_INTERPID(shared->data[i]) == interpid); assert(_PyXIData_INTERPID(shared->data[i]) == interpid);
_PyCrossInterpreterData_Release(shared->data[i]); _PyXIData_Release(shared->data[i]);
PyMem_RawFree(shared->data[i]); PyMem_RawFree(shared->data[i]);
shared->data[i] = NULL; shared->data[i] = NULL;
} }
@ -504,8 +498,7 @@ _tuple_shared_free(void* data)
} }
static int static int
_tuple_shared(PyThreadState *tstate, PyObject *obj, _tuple_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data)
_PyCrossInterpreterData *data)
{ {
Py_ssize_t len = PyTuple_GET_SIZE(obj); Py_ssize_t len = PyTuple_GET_SIZE(obj);
if (len < 0) { if (len < 0) {
@ -518,14 +511,14 @@ _tuple_shared(PyThreadState *tstate, PyObject *obj,
} }
shared->len = len; 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) { if (shared->data == NULL) {
PyErr_NoMemory(); PyErr_NoMemory();
return -1; return -1;
} }
for (Py_ssize_t i = 0; i < shared->len; i++) { for (Py_ssize_t i = 0; i < shared->len; i++) {
_PyCrossInterpreterData *data = _PyCrossInterpreterData_New(); _PyXIData_t *data = _PyXIData_New();
if (data == NULL) { if (data == NULL) {
goto error; // PyErr_NoMemory already set goto error; // PyErr_NoMemory already set
} }
@ -533,7 +526,7 @@ _tuple_shared(PyThreadState *tstate, PyObject *obj,
int res = -1; int res = -1;
if (!_Py_EnterRecursiveCallTstate(tstate, " while sharing a tuple")) { if (!_Py_EnterRecursiveCallTstate(tstate, " while sharing a tuple")) {
res = _PyObject_GetCrossInterpreterData(item, data); res = _PyObject_GetXIData(item, data);
_Py_LeaveRecursiveCallTstate(tstate); _Py_LeaveRecursiveCallTstate(tstate);
} }
if (res < 0) { if (res < 0) {
@ -542,8 +535,7 @@ _tuple_shared(PyThreadState *tstate, PyObject *obj,
} }
shared->data[i] = data; shared->data[i] = data;
} }
_PyCrossInterpreterData_Init( _PyXIData_Init(data, tstate->interp, shared, obj, _new_tuple_object);
data, tstate->interp, shared, obj, _new_tuple_object);
data->free = _tuple_shared_free; data->free = _tuple_shared_free;
return 0; return 0;
@ -555,7 +547,7 @@ error:
// registration // registration
static void static void
_register_builtins_for_crossinterpreter_data(struct _xidregistry *xidregistry) _register_builtins_for_crossinterpreter_data(dlregistry_t *xidregistry)
{ {
// None // None
if (_xidregistry_add_type(xidregistry, (PyTypeObject *)PyObject_Type(Py_None), _none_shared) != 0) { if (_xidregistry_add_type(xidregistry, (PyTypeObject *)PyObject_Type(Py_None), _none_shared) != 0) {

View File

@ -396,7 +396,7 @@ _Py_COMP_DIAG_POP
#define LOCKS_INIT(runtime) \ #define LOCKS_INIT(runtime) \
{ \ { \
&(runtime)->interpreters.mutex, \ &(runtime)->interpreters.mutex, \
&(runtime)->xi.registry.mutex, \ &(runtime)->xi.data_lookup.registry.mutex, \
&(runtime)->unicode_state.ids.mutex, \ &(runtime)->unicode_state.ids.mutex, \
&(runtime)->imports.extensions.mutex, \ &(runtime)->imports.extensions.mutex, \
&(runtime)->ceval.pending_mainthread.mutex, \ &(runtime)->ceval.pending_mainthread.mutex, \

View File

@ -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 LOCAL(type) static inline type
Modules/_sre/sre_lib.h SRE(F) sre_ucs2_##F Modules/_sre/sre_lib.h SRE(F) sre_ucs2_##F
Objects/stringlib/codecs.h STRINGLIB_IS_UNICODE 1 Objects/stringlib/codecs.h STRINGLIB_IS_UNICODE 1
Include/internal/pycore_crossinterp_data_registry.h Py_CORE_CROSSINTERP_DATA_REGISTRY_H 1
# @end=tsv@ # @end=tsv@
''')[1:] ''')[1:]