mirror of https://github.com/python/cpython
gh-76785: Improved Subinterpreters Compatibility with 3.12 (2/2) (gh-126707)
These changes makes it easier to backport the _interpreters, _interpqueues, and _interpchannels modules to Python 3.12. This involves the following: * add the _PyXI_GET_STATE() and _PyXI_GET_GLOBAL_STATE() macros * add _PyXIData_lookup_context_t and _PyXIData_GetLookupContext() * add _Py_xi_state_init() and _Py_xi_state_fini()
This commit is contained in:
parent
6b2a19681e
commit
73cf069099
|
@ -100,9 +100,26 @@ typedef int (*xidatafunc)(PyThreadState *tstate, PyObject *, _PyXIData_t *);
|
||||||
|
|
||||||
typedef struct _xid_lookup_state _PyXIData_lookup_t;
|
typedef struct _xid_lookup_state _PyXIData_lookup_t;
|
||||||
|
|
||||||
PyAPI_FUNC(xidatafunc) _PyXIData_Lookup(PyObject *);
|
typedef struct {
|
||||||
PyAPI_FUNC(int) _PyObject_CheckXIData(PyObject *);
|
_PyXIData_lookup_t *global;
|
||||||
PyAPI_FUNC(int) _PyObject_GetXIData(PyObject *, _PyXIData_t *);
|
_PyXIData_lookup_t *local;
|
||||||
|
PyObject *PyExc_NotShareableError;
|
||||||
|
} _PyXIData_lookup_context_t;
|
||||||
|
|
||||||
|
PyAPI_FUNC(int) _PyXIData_GetLookupContext(
|
||||||
|
PyInterpreterState *,
|
||||||
|
_PyXIData_lookup_context_t *);
|
||||||
|
|
||||||
|
PyAPI_FUNC(xidatafunc) _PyXIData_Lookup(
|
||||||
|
_PyXIData_lookup_context_t *,
|
||||||
|
PyObject *);
|
||||||
|
PyAPI_FUNC(int) _PyObject_CheckXIData(
|
||||||
|
_PyXIData_lookup_context_t *,
|
||||||
|
PyObject *);
|
||||||
|
PyAPI_FUNC(int) _PyObject_GetXIData(
|
||||||
|
_PyXIData_lookup_context_t *,
|
||||||
|
PyObject *,
|
||||||
|
_PyXIData_t *);
|
||||||
|
|
||||||
|
|
||||||
/* using cross-interpreter data */
|
/* using cross-interpreter data */
|
||||||
|
@ -173,12 +190,20 @@ typedef struct {
|
||||||
} exceptions;
|
} exceptions;
|
||||||
} _PyXI_state_t;
|
} _PyXI_state_t;
|
||||||
|
|
||||||
|
#define _PyXI_GET_GLOBAL_STATE(interp) (&(interp)->runtime->xi)
|
||||||
|
#define _PyXI_GET_STATE(interp) (&(interp)->xi)
|
||||||
|
|
||||||
|
#ifndef Py_BUILD_CORE_MODULE
|
||||||
extern PyStatus _PyXI_Init(PyInterpreterState *interp);
|
extern PyStatus _PyXI_Init(PyInterpreterState *interp);
|
||||||
extern void _PyXI_Fini(PyInterpreterState *interp);
|
extern void _PyXI_Fini(PyInterpreterState *interp);
|
||||||
extern PyStatus _PyXI_InitTypes(PyInterpreterState *interp);
|
extern PyStatus _PyXI_InitTypes(PyInterpreterState *interp);
|
||||||
extern void _PyXI_FiniTypes(PyInterpreterState *interp);
|
extern void _PyXI_FiniTypes(PyInterpreterState *interp);
|
||||||
|
#endif // Py_BUILD_CORE_MODULE
|
||||||
|
|
||||||
#define _PyInterpreterState_GetXIState(interp) (&(interp)->xi)
|
int _Py_xi_global_state_init(_PyXI_global_state_t *);
|
||||||
|
void _Py_xi_global_state_fini(_PyXI_global_state_t *);
|
||||||
|
int _Py_xi_state_init(_PyXI_state_t *, PyInterpreterState *);
|
||||||
|
void _Py_xi_state_fini(_PyXI_state_t *, PyInterpreterState *);
|
||||||
|
|
||||||
|
|
||||||
/***************************/
|
/***************************/
|
||||||
|
|
|
@ -27,8 +27,13 @@ typedef struct {
|
||||||
_PyXIData_regitem_t *head;
|
_PyXIData_regitem_t *head;
|
||||||
} _PyXIData_registry_t;
|
} _PyXIData_registry_t;
|
||||||
|
|
||||||
PyAPI_FUNC(int) _PyXIData_RegisterClass(PyTypeObject *, xidatafunc);
|
PyAPI_FUNC(int) _PyXIData_RegisterClass(
|
||||||
PyAPI_FUNC(int) _PyXIData_UnregisterClass(PyTypeObject *);
|
_PyXIData_lookup_context_t *,
|
||||||
|
PyTypeObject *,
|
||||||
|
xidatafunc);
|
||||||
|
PyAPI_FUNC(int) _PyXIData_UnregisterClass(
|
||||||
|
_PyXIData_lookup_context_t *,
|
||||||
|
PyTypeObject *);
|
||||||
|
|
||||||
struct _xid_lookup_state {
|
struct _xid_lookup_state {
|
||||||
// XXX Remove this field once we have a tp_* slot.
|
// XXX Remove this field once we have a tp_* slot.
|
||||||
|
|
|
@ -1758,6 +1758,11 @@ channel_send(_channels *channels, int64_t cid, PyObject *obj,
|
||||||
}
|
}
|
||||||
int64_t interpid = PyInterpreterState_GetID(interp);
|
int64_t interpid = PyInterpreterState_GetID(interp);
|
||||||
|
|
||||||
|
_PyXIData_lookup_context_t ctx;
|
||||||
|
if (_PyXIData_GetLookupContext(interp, &ctx) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// Look up the channel.
|
// Look up the channel.
|
||||||
PyThread_type_lock mutex = NULL;
|
PyThread_type_lock mutex = NULL;
|
||||||
_channel_state *chan = NULL;
|
_channel_state *chan = NULL;
|
||||||
|
@ -1779,7 +1784,7 @@ channel_send(_channels *channels, int64_t cid, PyObject *obj,
|
||||||
PyThread_release_lock(mutex);
|
PyThread_release_lock(mutex);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (_PyObject_GetXIData(obj, data) != 0) {
|
if (_PyObject_GetXIData(&ctx, obj, data) != 0) {
|
||||||
PyThread_release_lock(mutex);
|
PyThread_release_lock(mutex);
|
||||||
GLOBAL_FREE(data);
|
GLOBAL_FREE(data);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -1127,6 +1127,12 @@ queue_destroy(_queues *queues, int64_t qid)
|
||||||
static int
|
static int
|
||||||
queue_put(_queues *queues, int64_t qid, PyObject *obj, int fmt, int unboundop)
|
queue_put(_queues *queues, int64_t qid, PyObject *obj, int fmt, int unboundop)
|
||||||
{
|
{
|
||||||
|
PyInterpreterState *interp = PyInterpreterState_Get();
|
||||||
|
_PyXIData_lookup_context_t ctx;
|
||||||
|
if (_PyXIData_GetLookupContext(interp, &ctx) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// Look up the queue.
|
// Look up the queue.
|
||||||
_queue *queue = NULL;
|
_queue *queue = NULL;
|
||||||
int err = _queues_lookup(queues, qid, &queue);
|
int err = _queues_lookup(queues, qid, &queue);
|
||||||
|
@ -1141,13 +1147,12 @@ queue_put(_queues *queues, int64_t qid, PyObject *obj, int fmt, int unboundop)
|
||||||
_queue_unmark_waiter(queue, queues->mutex);
|
_queue_unmark_waiter(queue, queues->mutex);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (_PyObject_GetXIData(obj, data) != 0) {
|
if (_PyObject_GetXIData(&ctx, obj, data) != 0) {
|
||||||
_queue_unmark_waiter(queue, queues->mutex);
|
_queue_unmark_waiter(queue, queues->mutex);
|
||||||
GLOBAL_FREE(data);
|
GLOBAL_FREE(data);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
assert(_PyXIData_INTERPID(data) == \
|
assert(_PyXIData_INTERPID(data) == PyInterpreterState_GetID(interp));
|
||||||
PyInterpreterState_GetID(PyInterpreterState_Get()));
|
|
||||||
|
|
||||||
// Add the data to the queue.
|
// Add the data to the queue.
|
||||||
int64_t interpid = -1; // _queueitem_init() will set it.
|
int64_t interpid = -1; // _queueitem_init() will set it.
|
||||||
|
|
|
@ -8,15 +8,24 @@
|
||||||
static int
|
static int
|
||||||
ensure_xid_class(PyTypeObject *cls, xidatafunc getdata)
|
ensure_xid_class(PyTypeObject *cls, xidatafunc getdata)
|
||||||
{
|
{
|
||||||
//assert(cls->tp_flags & Py_TPFLAGS_HEAPTYPE);
|
PyInterpreterState *interp = PyInterpreterState_Get();
|
||||||
return _PyXIData_RegisterClass(cls, getdata);
|
_PyXIData_lookup_context_t ctx;
|
||||||
|
if (_PyXIData_GetLookupContext(interp, &ctx) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return _PyXIData_RegisterClass(&ctx, cls, getdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef REGISTERS_HEAP_TYPES
|
#ifdef REGISTERS_HEAP_TYPES
|
||||||
static int
|
static int
|
||||||
clear_xid_class(PyTypeObject *cls)
|
clear_xid_class(PyTypeObject *cls)
|
||||||
{
|
{
|
||||||
return _PyXIData_UnregisterClass(cls);
|
PyInterpreterState *interp = PyInterpreterState_Get();
|
||||||
|
_PyXIData_lookup_context_t ctx;
|
||||||
|
if (_PyXIData_GetLookupContext(interp, &ctx) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return _PyXIData_UnregisterClass(&ctx, cls);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1186,7 +1186,13 @@ object_is_shareable(PyObject *self, PyObject *args, PyObject *kwds)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_PyObject_CheckXIData(obj) == 0) {
|
PyInterpreterState *interp = PyInterpreterState_Get();
|
||||||
|
_PyXIData_lookup_context_t ctx;
|
||||||
|
if (_PyXIData_GetLookupContext(interp, &ctx) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_PyObject_CheckXIData(&ctx, obj) == 0) {
|
||||||
Py_RETURN_TRUE;
|
Py_RETURN_TRUE;
|
||||||
}
|
}
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
|
@ -1485,6 +1491,11 @@ module_exec(PyObject *mod)
|
||||||
PyInterpreterState *interp = PyInterpreterState_Get();
|
PyInterpreterState *interp = PyInterpreterState_Get();
|
||||||
module_state *state = get_module_state(mod);
|
module_state *state = get_module_state(mod);
|
||||||
|
|
||||||
|
_PyXIData_lookup_context_t ctx;
|
||||||
|
if (_PyXIData_GetLookupContext(interp, &ctx) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
#define ADD_WHENCE(NAME) \
|
#define ADD_WHENCE(NAME) \
|
||||||
if (PyModule_AddIntConstant(mod, "WHENCE_" #NAME, \
|
if (PyModule_AddIntConstant(mod, "WHENCE_" #NAME, \
|
||||||
_PyInterpreterState_WHENCE_##NAME) < 0) \
|
_PyInterpreterState_WHENCE_##NAME) < 0) \
|
||||||
|
@ -1506,9 +1517,7 @@ module_exec(PyObject *mod)
|
||||||
if (PyModule_AddType(mod, (PyTypeObject *)PyExc_InterpreterNotFoundError) < 0) {
|
if (PyModule_AddType(mod, (PyTypeObject *)PyExc_InterpreterNotFoundError) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
PyObject *PyExc_NotShareableError = \
|
if (PyModule_AddType(mod, (PyTypeObject *)ctx.PyExc_NotShareableError) < 0) {
|
||||||
_PyInterpreterState_GetXIState(interp)->exceptions.PyExc_NotShareableError;
|
|
||||||
if (PyModule_AddType(mod, (PyTypeObject *)PyExc_NotShareableError) < 0) {
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1797,6 +1797,12 @@ _xid_capsule_destructor(PyObject *capsule)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
get_crossinterp_data(PyObject *self, PyObject *args)
|
get_crossinterp_data(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
|
PyInterpreterState *interp = PyInterpreterState_Get();
|
||||||
|
_PyXIData_lookup_context_t ctx;
|
||||||
|
if (_PyXIData_GetLookupContext(interp, &ctx) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
PyObject *obj = NULL;
|
PyObject *obj = NULL;
|
||||||
if (!PyArg_ParseTuple(args, "O:get_crossinterp_data", &obj)) {
|
if (!PyArg_ParseTuple(args, "O:get_crossinterp_data", &obj)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1806,7 +1812,7 @@ get_crossinterp_data(PyObject *self, PyObject *args)
|
||||||
if (data == NULL) {
|
if (data == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (_PyObject_GetXIData(obj, data) != 0) {
|
if (_PyObject_GetXIData(&ctx, obj, data) != 0) {
|
||||||
_PyXIData_Free(data);
|
_PyXIData_Free(data);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,6 @@
|
||||||
#include "pycore_pyerrors.h" // _PyErr_Clear()
|
#include "pycore_pyerrors.h" // _PyErr_Clear()
|
||||||
|
|
||||||
|
|
||||||
#define _PyXI_GET_GLOBAL_STATE(interp) (&(interp)->runtime->xi)
|
|
||||||
#define _PyXI_GET_STATE(interp) (&(interp)->xi)
|
|
||||||
|
|
||||||
|
|
||||||
/**************/
|
/**************/
|
||||||
/* exceptions */
|
/* exceptions */
|
||||||
/**************/
|
/**************/
|
||||||
|
@ -68,7 +64,7 @@ _Py_CallInInterpreterAndRawFree(PyInterpreterState *interp,
|
||||||
|
|
||||||
static void xid_lookup_init(_PyXIData_lookup_t *);
|
static void xid_lookup_init(_PyXIData_lookup_t *);
|
||||||
static void xid_lookup_fini(_PyXIData_lookup_t *);
|
static void xid_lookup_fini(_PyXIData_lookup_t *);
|
||||||
static xidatafunc lookup_getdata(PyInterpreterState *, PyObject *);
|
static xidatafunc lookup_getdata(_PyXIData_lookup_context_t *, PyObject *);
|
||||||
#include "crossinterp_data_lookup.h"
|
#include "crossinterp_data_lookup.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -202,9 +198,9 @@ _check_xidata(PyThreadState *tstate, _PyXIData_t *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
_set_xid_lookup_failure(_PyXI_state_t *state, PyObject *obj, const char *msg)
|
_set_xid_lookup_failure(dlcontext_t *ctx, PyObject *obj, const char *msg)
|
||||||
{
|
{
|
||||||
PyObject *exctype = state->exceptions.PyExc_NotShareableError;
|
PyObject *exctype = ctx->PyExc_NotShareableError;
|
||||||
assert(exctype != NULL);
|
assert(exctype != NULL);
|
||||||
if (msg != NULL) {
|
if (msg != NULL) {
|
||||||
assert(obj == NULL);
|
assert(obj == NULL);
|
||||||
|
@ -221,14 +217,12 @@ _set_xid_lookup_failure(_PyXI_state_t *state, PyObject *obj, const char *msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
_PyObject_CheckXIData(PyObject *obj)
|
_PyObject_CheckXIData(_PyXIData_lookup_context_t *ctx, PyObject *obj)
|
||||||
{
|
{
|
||||||
PyInterpreterState *interp = PyInterpreterState_Get();
|
xidatafunc getdata = lookup_getdata(ctx, obj);
|
||||||
_PyXI_state_t *state = _PyXI_GET_STATE(interp);
|
|
||||||
xidatafunc getdata = lookup_getdata(interp, obj);
|
|
||||||
if (getdata == NULL) {
|
if (getdata == NULL) {
|
||||||
if (!PyErr_Occurred()) {
|
if (!PyErr_Occurred()) {
|
||||||
_set_xid_lookup_failure(state, obj, NULL);
|
_set_xid_lookup_failure(ctx, obj, NULL);
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -236,11 +230,11 @@ _PyObject_CheckXIData(PyObject *obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
_PyObject_GetXIData(PyObject *obj, _PyXIData_t *data)
|
_PyObject_GetXIData(_PyXIData_lookup_context_t *ctx,
|
||||||
|
PyObject *obj, _PyXIData_t *data)
|
||||||
{
|
{
|
||||||
PyThreadState *tstate = PyThreadState_Get();
|
PyThreadState *tstate = PyThreadState_Get();
|
||||||
PyInterpreterState *interp = tstate->interp;
|
PyInterpreterState *interp = tstate->interp;
|
||||||
_PyXI_state_t *state = _PyXI_GET_STATE(interp);
|
|
||||||
|
|
||||||
// Reset data before re-populating.
|
// Reset data before re-populating.
|
||||||
*data = (_PyXIData_t){0};
|
*data = (_PyXIData_t){0};
|
||||||
|
@ -248,11 +242,11 @@ _PyObject_GetXIData(PyObject *obj, _PyXIData_t *data)
|
||||||
|
|
||||||
// Call the "getdata" func for the object.
|
// Call the "getdata" func for the object.
|
||||||
Py_INCREF(obj);
|
Py_INCREF(obj);
|
||||||
xidatafunc getdata = lookup_getdata(interp, obj);
|
xidatafunc getdata = lookup_getdata(ctx, obj);
|
||||||
if (getdata == NULL) {
|
if (getdata == NULL) {
|
||||||
Py_DECREF(obj);
|
Py_DECREF(obj);
|
||||||
if (!PyErr_Occurred()) {
|
if (!PyErr_Occurred()) {
|
||||||
_set_xid_lookup_failure(state, obj, NULL);
|
_set_xid_lookup_failure(ctx, obj, NULL);
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -969,7 +963,8 @@ _PyXI_ClearExcInfo(_PyXI_excinfo *info)
|
||||||
static int
|
static int
|
||||||
_PyXI_ApplyErrorCode(_PyXI_errcode code, PyInterpreterState *interp)
|
_PyXI_ApplyErrorCode(_PyXI_errcode code, PyInterpreterState *interp)
|
||||||
{
|
{
|
||||||
_PyXI_state_t *state;
|
dlcontext_t ctx;
|
||||||
|
|
||||||
assert(!PyErr_Occurred());
|
assert(!PyErr_Occurred());
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case _PyXI_ERR_NO_ERROR: _Py_FALLTHROUGH;
|
case _PyXI_ERR_NO_ERROR: _Py_FALLTHROUGH;
|
||||||
|
@ -1000,8 +995,10 @@ _PyXI_ApplyErrorCode(_PyXI_errcode code, PyInterpreterState *interp)
|
||||||
"failed to apply namespace to __main__");
|
"failed to apply namespace to __main__");
|
||||||
break;
|
break;
|
||||||
case _PyXI_ERR_NOT_SHAREABLE:
|
case _PyXI_ERR_NOT_SHAREABLE:
|
||||||
state = _PyXI_GET_STATE(interp);
|
if (_PyXIData_GetLookupContext(interp, &ctx) < 0) {
|
||||||
_set_xid_lookup_failure(state, NULL, NULL);
|
return -1;
|
||||||
|
}
|
||||||
|
_set_xid_lookup_failure(&ctx, NULL, NULL);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
#ifdef Py_DEBUG
|
#ifdef Py_DEBUG
|
||||||
|
@ -1063,8 +1060,11 @@ _PyXI_ApplyError(_PyXI_error *error)
|
||||||
}
|
}
|
||||||
else if (error->code == _PyXI_ERR_NOT_SHAREABLE) {
|
else if (error->code == _PyXI_ERR_NOT_SHAREABLE) {
|
||||||
// Propagate the exception directly.
|
// Propagate the exception directly.
|
||||||
_PyXI_state_t *state = _PyXI_GET_STATE(error->interp);
|
dlcontext_t ctx;
|
||||||
_set_xid_lookup_failure(state, NULL, error->uncaught.msg);
|
if (_PyXIData_GetLookupContext(error->interp, &ctx) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
_set_xid_lookup_failure(&ctx, NULL, error->uncaught.msg);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Raise an exception corresponding to the code.
|
// Raise an exception corresponding to the code.
|
||||||
|
@ -1151,7 +1151,12 @@ _sharednsitem_set_value(_PyXI_namespace_item *item, PyObject *value)
|
||||||
PyErr_NoMemory();
|
PyErr_NoMemory();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (_PyObject_GetXIData(value, item->data) != 0) {
|
PyInterpreterState *interp = PyInterpreterState_Get();
|
||||||
|
dlcontext_t ctx;
|
||||||
|
if (_PyXIData_GetLookupContext(interp, &ctx) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (_PyObject_GetXIData(&ctx, value, item->data) != 0) {
|
||||||
PyMem_RawFree(item->data);
|
PyMem_RawFree(item->data);
|
||||||
item->data = NULL;
|
item->data = NULL;
|
||||||
// The caller may want to propagate PyExc_NotShareableError
|
// The caller may want to propagate PyExc_NotShareableError
|
||||||
|
@ -1609,9 +1614,13 @@ _propagate_not_shareable_error(_PyXI_session *session)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PyInterpreterState *interp = PyInterpreterState_Get();
|
PyInterpreterState *interp = PyInterpreterState_Get();
|
||||||
_PyXI_state_t *state = _PyXI_GET_STATE(interp);
|
dlcontext_t ctx;
|
||||||
assert(state->exceptions.PyExc_NotShareableError != NULL);
|
if (_PyXIData_GetLookupContext(interp, &ctx) < 0) {
|
||||||
if (PyErr_ExceptionMatches(state->exceptions.PyExc_NotShareableError)) {
|
PyErr_FormatUnraisable(
|
||||||
|
"Exception ignored while propagating not shareable error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (PyErr_ExceptionMatches(ctx.PyExc_NotShareableError)) {
|
||||||
// We want to propagate the exception directly.
|
// We want to propagate the exception directly.
|
||||||
session->_error_override = _PyXI_ERR_NOT_SHAREABLE;
|
session->_error_override = _PyXI_ERR_NOT_SHAREABLE;
|
||||||
session->error_override = &session->_error_override;
|
session->error_override = &session->_error_override;
|
||||||
|
@ -1779,22 +1788,87 @@ _PyXI_Exit(_PyXI_session *session)
|
||||||
/* runtime lifecycle */
|
/* runtime lifecycle */
|
||||||
/*********************/
|
/*********************/
|
||||||
|
|
||||||
|
int
|
||||||
|
_Py_xi_global_state_init(_PyXI_global_state_t *state)
|
||||||
|
{
|
||||||
|
assert(state != NULL);
|
||||||
|
xid_lookup_init(&state->data_lookup);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_Py_xi_global_state_fini(_PyXI_global_state_t *state)
|
||||||
|
{
|
||||||
|
assert(state != NULL);
|
||||||
|
xid_lookup_fini(&state->data_lookup);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_Py_xi_state_init(_PyXI_state_t *state, PyInterpreterState *interp)
|
||||||
|
{
|
||||||
|
assert(state != NULL);
|
||||||
|
assert(interp == NULL || state == _PyXI_GET_STATE(interp));
|
||||||
|
|
||||||
|
xid_lookup_init(&state->data_lookup);
|
||||||
|
|
||||||
|
// Initialize exceptions.
|
||||||
|
if (interp != NULL) {
|
||||||
|
if (init_static_exctypes(&state->exceptions, interp) < 0) {
|
||||||
|
fini_heap_exctypes(&state->exceptions);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (init_heap_exctypes(&state->exceptions) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_Py_xi_state_fini(_PyXI_state_t *state, PyInterpreterState *interp)
|
||||||
|
{
|
||||||
|
assert(state != NULL);
|
||||||
|
assert(interp == NULL || state == _PyXI_GET_STATE(interp));
|
||||||
|
|
||||||
|
fini_heap_exctypes(&state->exceptions);
|
||||||
|
if (interp != NULL) {
|
||||||
|
fini_static_exctypes(&state->exceptions, interp);
|
||||||
|
}
|
||||||
|
|
||||||
|
xid_lookup_fini(&state->data_lookup);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PyStatus
|
PyStatus
|
||||||
_PyXI_Init(PyInterpreterState *interp)
|
_PyXI_Init(PyInterpreterState *interp)
|
||||||
{
|
{
|
||||||
_PyXI_state_t *state = _PyXI_GET_STATE(interp);
|
|
||||||
|
|
||||||
// Initialize the XID lookup state (e.g. registry).
|
|
||||||
if (_Py_IsMainInterpreter(interp)) {
|
if (_Py_IsMainInterpreter(interp)) {
|
||||||
xid_lookup_init(&_PyXI_GET_GLOBAL_STATE(interp)->data_lookup);
|
_PyXI_global_state_t *global_state = _PyXI_GET_GLOBAL_STATE(interp);
|
||||||
|
if (global_state == NULL) {
|
||||||
|
PyErr_PrintEx(0);
|
||||||
|
return _PyStatus_ERR(
|
||||||
|
"failed to get global cross-interpreter state");
|
||||||
|
}
|
||||||
|
if (_Py_xi_global_state_init(global_state) < 0) {
|
||||||
|
PyErr_PrintEx(0);
|
||||||
|
return _PyStatus_ERR(
|
||||||
|
"failed to initialize global cross-interpreter state");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
xid_lookup_init(&state->data_lookup);
|
|
||||||
|
|
||||||
// Initialize exceptions.(heap types).
|
_PyXI_state_t *state = _PyXI_GET_STATE(interp);
|
||||||
// See _PyXI_InitTypes() for the static types.
|
if (state == NULL) {
|
||||||
if (init_heap_exctypes(&_PyXI_GET_STATE(interp)->exceptions) < 0) {
|
|
||||||
PyErr_PrintEx(0);
|
PyErr_PrintEx(0);
|
||||||
return _PyStatus_ERR("failed to initialize exceptions");
|
return _PyStatus_ERR(
|
||||||
|
"failed to get interpreter's cross-interpreter state");
|
||||||
|
}
|
||||||
|
// The static types were already initialized in _PyXI_InitTypes(),
|
||||||
|
// so we pass in NULL here to avoid initializing them again.
|
||||||
|
if (_Py_xi_state_init(state, NULL) < 0) {
|
||||||
|
PyErr_PrintEx(0);
|
||||||
|
return _PyStatus_ERR(
|
||||||
|
"failed to initialize interpreter's cross-interpreter state");
|
||||||
}
|
}
|
||||||
|
|
||||||
return _PyStatus_OK();
|
return _PyStatus_OK();
|
||||||
|
@ -1807,15 +1881,19 @@ void
|
||||||
_PyXI_Fini(PyInterpreterState *interp)
|
_PyXI_Fini(PyInterpreterState *interp)
|
||||||
{
|
{
|
||||||
_PyXI_state_t *state = _PyXI_GET_STATE(interp);
|
_PyXI_state_t *state = _PyXI_GET_STATE(interp);
|
||||||
|
#ifndef NDEBUG
|
||||||
|
if (state == NULL) {
|
||||||
|
PyErr_PrintEx(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// The static types will be finalized soon in _PyXI_FiniTypes(),
|
||||||
|
// so we pass in NULL here to avoid finalizing them right now.
|
||||||
|
_Py_xi_state_fini(state, NULL);
|
||||||
|
|
||||||
// Finalize exceptions (heap types).
|
|
||||||
// See _PyXI_FiniTypes() for the static types.
|
|
||||||
fini_heap_exctypes(&_PyXI_GET_STATE(interp)->exceptions);
|
|
||||||
|
|
||||||
// Finalize the XID lookup state (e.g. registry).
|
|
||||||
xid_lookup_fini(&state->data_lookup);
|
|
||||||
if (_Py_IsMainInterpreter(interp)) {
|
if (_Py_IsMainInterpreter(interp)) {
|
||||||
xid_lookup_fini(&_PyXI_GET_GLOBAL_STATE(interp)->data_lookup);
|
_PyXI_global_state_t *global_state = _PyXI_GET_GLOBAL_STATE(interp);
|
||||||
|
_Py_xi_global_state_fini(global_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1824,7 +1902,8 @@ _PyXI_InitTypes(PyInterpreterState *interp)
|
||||||
{
|
{
|
||||||
if (init_static_exctypes(&_PyXI_GET_STATE(interp)->exceptions, interp) < 0) {
|
if (init_static_exctypes(&_PyXI_GET_STATE(interp)->exceptions, interp) < 0) {
|
||||||
PyErr_PrintEx(0);
|
PyErr_PrintEx(0);
|
||||||
return _PyStatus_ERR("failed to initialize an exception type");
|
return _PyStatus_ERR(
|
||||||
|
"failed to initialize the cross-interpreter exception types");
|
||||||
}
|
}
|
||||||
// We would initialize heap types here too but that leads to ref leaks.
|
// We would initialize heap types here too but that leads to ref leaks.
|
||||||
// Instead, we intialize them in _PyXI_Init().
|
// Instead, we intialize them in _PyXI_Init().
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "pycore_weakref.h" // _PyWeakref_GET_REF()
|
#include "pycore_weakref.h" // _PyWeakref_GET_REF()
|
||||||
|
|
||||||
|
|
||||||
|
typedef _PyXIData_lookup_context_t dlcontext_t;
|
||||||
typedef _PyXIData_registry_t dlregistry_t;
|
typedef _PyXIData_registry_t dlregistry_t;
|
||||||
typedef _PyXIData_regitem_t dlregitem_t;
|
typedef _PyXIData_regitem_t dlregitem_t;
|
||||||
|
|
||||||
|
@ -8,7 +9,7 @@ typedef _PyXIData_regitem_t dlregitem_t;
|
||||||
// forward
|
// forward
|
||||||
static void _xidregistry_init(dlregistry_t *);
|
static void _xidregistry_init(dlregistry_t *);
|
||||||
static void _xidregistry_fini(dlregistry_t *);
|
static void _xidregistry_fini(dlregistry_t *);
|
||||||
static xidatafunc _lookup_getdata_from_registry(PyInterpreterState *, PyObject *);
|
static xidatafunc _lookup_getdata_from_registry(dlcontext_t *, PyObject *);
|
||||||
|
|
||||||
|
|
||||||
/* used in crossinterp.c */
|
/* used in crossinterp.c */
|
||||||
|
@ -26,22 +27,43 @@ xid_lookup_fini(_PyXIData_lookup_t *state)
|
||||||
}
|
}
|
||||||
|
|
||||||
static xidatafunc
|
static xidatafunc
|
||||||
lookup_getdata(PyInterpreterState *interp, PyObject *obj)
|
lookup_getdata(dlcontext_t *ctx, PyObject *obj)
|
||||||
{
|
{
|
||||||
/* Cross-interpreter objects are looked up by exact match on the class.
|
/* Cross-interpreter objects are looked up by exact match on the class.
|
||||||
We can reassess this policy when we move from a global registry to a
|
We can reassess this policy when we move from a global registry to a
|
||||||
tp_* slot. */
|
tp_* slot. */
|
||||||
return _lookup_getdata_from_registry(interp, obj);
|
return _lookup_getdata_from_registry(ctx, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* exported API */
|
/* exported API */
|
||||||
|
|
||||||
xidatafunc
|
int
|
||||||
_PyXIData_Lookup(PyObject *obj)
|
_PyXIData_GetLookupContext(PyInterpreterState *interp,
|
||||||
|
_PyXIData_lookup_context_t *res)
|
||||||
{
|
{
|
||||||
PyInterpreterState *interp = PyInterpreterState_Get();
|
_PyXI_global_state_t *global = _PyXI_GET_GLOBAL_STATE(interp);
|
||||||
return lookup_getdata(interp, obj);
|
if (global == NULL) {
|
||||||
|
assert(PyErr_Occurred());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
_PyXI_state_t *local = _PyXI_GET_STATE(interp);
|
||||||
|
if (local == NULL) {
|
||||||
|
assert(PyErr_Occurred());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*res = (dlcontext_t){
|
||||||
|
.global = &global->data_lookup,
|
||||||
|
.local = &local->data_lookup,
|
||||||
|
.PyExc_NotShareableError = local->exceptions.PyExc_NotShareableError,
|
||||||
|
};
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
xidatafunc
|
||||||
|
_PyXIData_Lookup(_PyXIData_lookup_context_t *ctx, PyObject *obj)
|
||||||
|
{
|
||||||
|
return lookup_getdata(ctx, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -110,25 +132,12 @@ _xidregistry_unlock(dlregistry_t *registry)
|
||||||
/* accessing the registry */
|
/* accessing the registry */
|
||||||
|
|
||||||
static inline dlregistry_t *
|
static inline dlregistry_t *
|
||||||
_get_global_xidregistry(_PyRuntimeState *runtime)
|
_get_xidregistry_for_type(dlcontext_t *ctx, PyTypeObject *cls)
|
||||||
{
|
{
|
||||||
return &runtime->xi.data_lookup.registry;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline dlregistry_t *
|
|
||||||
_get_xidregistry(PyInterpreterState *interp)
|
|
||||||
{
|
|
||||||
return &interp->xi.data_lookup.registry;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline dlregistry_t *
|
|
||||||
_get_xidregistry_for_type(PyInterpreterState *interp, PyTypeObject *cls)
|
|
||||||
{
|
|
||||||
dlregistry_t *registry = _get_global_xidregistry(interp->runtime);
|
|
||||||
if (cls->tp_flags & Py_TPFLAGS_HEAPTYPE) {
|
if (cls->tp_flags & Py_TPFLAGS_HEAPTYPE) {
|
||||||
registry = _get_xidregistry(interp);
|
return &ctx->local->registry;
|
||||||
}
|
}
|
||||||
return registry;
|
return &ctx->global->registry;
|
||||||
}
|
}
|
||||||
|
|
||||||
static dlregitem_t* _xidregistry_remove_entry(dlregistry_t *, dlregitem_t *);
|
static dlregitem_t* _xidregistry_remove_entry(dlregistry_t *, dlregitem_t *);
|
||||||
|
@ -160,11 +169,11 @@ _xidregistry_find_type(dlregistry_t *xidregistry, PyTypeObject *cls)
|
||||||
}
|
}
|
||||||
|
|
||||||
static xidatafunc
|
static xidatafunc
|
||||||
_lookup_getdata_from_registry(PyInterpreterState *interp, PyObject *obj)
|
_lookup_getdata_from_registry(dlcontext_t *ctx, PyObject *obj)
|
||||||
{
|
{
|
||||||
PyTypeObject *cls = Py_TYPE(obj);
|
PyTypeObject *cls = Py_TYPE(obj);
|
||||||
|
|
||||||
dlregistry_t *xidregistry = _get_xidregistry_for_type(interp, cls);
|
dlregistry_t *xidregistry = _get_xidregistry_for_type(ctx, cls);
|
||||||
_xidregistry_lock(xidregistry);
|
_xidregistry_lock(xidregistry);
|
||||||
|
|
||||||
dlregitem_t *matched = _xidregistry_find_type(xidregistry, cls);
|
dlregitem_t *matched = _xidregistry_find_type(xidregistry, cls);
|
||||||
|
@ -241,7 +250,8 @@ _xidregistry_clear(dlregistry_t *xidregistry)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
_PyXIData_RegisterClass(PyTypeObject *cls, xidatafunc getdata)
|
_PyXIData_RegisterClass(_PyXIData_lookup_context_t *ctx,
|
||||||
|
PyTypeObject *cls, xidatafunc getdata)
|
||||||
{
|
{
|
||||||
if (!PyType_Check(cls)) {
|
if (!PyType_Check(cls)) {
|
||||||
PyErr_Format(PyExc_ValueError, "only classes may be registered");
|
PyErr_Format(PyExc_ValueError, "only classes may be registered");
|
||||||
|
@ -253,8 +263,7 @@ _PyXIData_RegisterClass(PyTypeObject *cls, xidatafunc getdata)
|
||||||
}
|
}
|
||||||
|
|
||||||
int res = 0;
|
int res = 0;
|
||||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
dlregistry_t *xidregistry = _get_xidregistry_for_type(ctx, cls);
|
||||||
dlregistry_t *xidregistry = _get_xidregistry_for_type(interp, cls);
|
|
||||||
_xidregistry_lock(xidregistry);
|
_xidregistry_lock(xidregistry);
|
||||||
|
|
||||||
dlregitem_t *matched = _xidregistry_find_type(xidregistry, cls);
|
dlregitem_t *matched = _xidregistry_find_type(xidregistry, cls);
|
||||||
|
@ -272,11 +281,10 @@ finally:
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
_PyXIData_UnregisterClass(PyTypeObject *cls)
|
_PyXIData_UnregisterClass(_PyXIData_lookup_context_t *ctx, PyTypeObject *cls)
|
||||||
{
|
{
|
||||||
int res = 0;
|
int res = 0;
|
||||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
dlregistry_t *xidregistry = _get_xidregistry_for_type(ctx, cls);
|
||||||
dlregistry_t *xidregistry = _get_xidregistry_for_type(interp, cls);
|
|
||||||
_xidregistry_lock(xidregistry);
|
_xidregistry_lock(xidregistry);
|
||||||
|
|
||||||
dlregitem_t *matched = _xidregistry_find_type(xidregistry, cls);
|
dlregitem_t *matched = _xidregistry_find_type(xidregistry, cls);
|
||||||
|
@ -500,6 +508,11 @@ _tuple_shared_free(void* data)
|
||||||
static int
|
static int
|
||||||
_tuple_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data)
|
_tuple_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data)
|
||||||
{
|
{
|
||||||
|
dlcontext_t ctx;
|
||||||
|
if (_PyXIData_GetLookupContext(tstate->interp, &ctx) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
Py_ssize_t len = PyTuple_GET_SIZE(obj);
|
Py_ssize_t len = PyTuple_GET_SIZE(obj);
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -526,7 +539,7 @@ _tuple_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data)
|
||||||
|
|
||||||
int res = -1;
|
int res = -1;
|
||||||
if (!_Py_EnterRecursiveCallTstate(tstate, " while sharing a tuple")) {
|
if (!_Py_EnterRecursiveCallTstate(tstate, " while sharing a tuple")) {
|
||||||
res = _PyObject_GetXIData(item, data);
|
res = _PyObject_GetXIData(&ctx, item, data);
|
||||||
_Py_LeaveRecursiveCallTstate(tstate);
|
_Py_LeaveRecursiveCallTstate(tstate);
|
||||||
}
|
}
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
|
|
Loading…
Reference in New Issue