mirror of
https://github.com/python/cpython.git
synced 2025-10-17 20:28:43 +00:00
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:
parent
3d9f9ae5a7
commit
9357fdcaf0
15 changed files with 343 additions and 337 deletions
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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, \
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue