From 9357fdcaf0b08dac9396c17e8695b420fad887f8 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Thu, 7 Nov 2024 09:32:42 -0700 Subject: [PATCH] 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 --- Include/internal/pycore_crossinterp.h | 114 ++++------ .../pycore_crossinterp_data_registry.h | 36 +++ Include/internal/pycore_runtime_init.h | 6 +- Makefile.pre.in | 1 + Modules/_interpchannelsmodule.c | 70 +++--- Modules/_interpqueuesmodule.c | 53 ++--- Modules/_interpreters_common.h | 10 +- Modules/_interpretersmodule.c | 24 +- Modules/_testinternalcapi.c | 22 +- PCbuild/pythoncore.vcxproj | 1 + PCbuild/pythoncore.vcxproj.filters | 3 + Python/crossinterp.c | 131 +++++------ Python/crossinterp_data_lookup.h | 206 +++++++++--------- Python/pystate.c | 2 +- Tools/c-analyzer/cpython/_parser.py | 1 + 15 files changed, 343 insertions(+), 337 deletions(-) create mode 100644 Include/internal/pycore_crossinterp_data_registry.h 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:]