mirror of
https://github.com/python/cpython.git
synced 2026-01-21 06:40:15 +00:00
bpo-32604: Remove xid registry. (#6813)
Remove the interpreters testing helper (and xid registry).
This commit is contained in:
parent
5c7e079158
commit
6bd0c476c5
9 changed files with 5 additions and 4219 deletions
258
Python/pystate.c
258
Python/pystate.c
|
|
@ -56,11 +56,6 @@ _PyRuntimeState_Init_impl(_PyRuntimeState *runtime)
|
|||
}
|
||||
runtime->interpreters.next_id = -1;
|
||||
|
||||
runtime->xidregistry.mutex = PyThread_allocate_lock();
|
||||
if (runtime->xidregistry.mutex == NULL) {
|
||||
return _Py_INIT_ERR("Can't initialize threads for cross-interpreter data registry");
|
||||
}
|
||||
|
||||
return _Py_INIT_OK();
|
||||
}
|
||||
|
||||
|
|
@ -1128,259 +1123,6 @@ PyGILState_Release(PyGILState_STATE oldstate)
|
|||
}
|
||||
|
||||
|
||||
/**************************/
|
||||
/* cross-interpreter data */
|
||||
/**************************/
|
||||
|
||||
/* cross-interpreter data */
|
||||
|
||||
crossinterpdatafunc _PyCrossInterpreterData_Lookup(PyObject *);
|
||||
|
||||
/* This is a separate func from _PyCrossInterpreterData_Lookup in order
|
||||
to keep the registry code separate. */
|
||||
static crossinterpdatafunc
|
||||
_lookup_getdata(PyObject *obj)
|
||||
{
|
||||
crossinterpdatafunc getdata = _PyCrossInterpreterData_Lookup(obj);
|
||||
if (getdata == NULL && PyErr_Occurred() == 0)
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"%S does not support cross-interpreter data", obj);
|
||||
return getdata;
|
||||
}
|
||||
|
||||
int
|
||||
_PyObject_CheckCrossInterpreterData(PyObject *obj)
|
||||
{
|
||||
crossinterpdatafunc getdata = _lookup_getdata(obj);
|
||||
if (getdata == NULL) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_check_xidata(_PyCrossInterpreterData *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 (data->interp < 0) {
|
||||
PyErr_SetString(PyExc_SystemError, "missing interp");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (data->new_object == NULL) {
|
||||
PyErr_SetString(PyExc_SystemError, "missing new_object func");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// data->free may be NULL, so we don't check it.
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_PyObject_GetCrossInterpreterData(PyObject *obj, _PyCrossInterpreterData *data)
|
||||
{
|
||||
PyThreadState *tstate = PyThreadState_Get();
|
||||
// PyThreadState_Get() aborts if lookup fails, so we don't need
|
||||
// to check the result for NULL.
|
||||
PyInterpreterState *interp = tstate->interp;
|
||||
|
||||
// Reset data before re-populating.
|
||||
*data = (_PyCrossInterpreterData){0};
|
||||
data->free = PyMem_RawFree; // Set a default that may be overridden.
|
||||
|
||||
// Call the "getdata" func for the object.
|
||||
Py_INCREF(obj);
|
||||
crossinterpdatafunc getdata = _lookup_getdata(obj);
|
||||
if (getdata == NULL) {
|
||||
Py_DECREF(obj);
|
||||
return -1;
|
||||
}
|
||||
int res = getdata(obj, data);
|
||||
Py_DECREF(obj);
|
||||
if (res != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Fill in the blanks and validate the result.
|
||||
Py_XINCREF(data->obj);
|
||||
data->interp = interp->id;
|
||||
if (_check_xidata(data) != 0) {
|
||||
_PyCrossInterpreterData_Release(data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
_PyCrossInterpreterData_Release(_PyCrossInterpreterData *data)
|
||||
{
|
||||
if (data->data == NULL && data->obj == NULL) {
|
||||
// Nothing to release!
|
||||
return;
|
||||
}
|
||||
|
||||
// Switch to the original interpreter.
|
||||
PyInterpreterState *interp = _PyInterpreterState_LookUpID(data->interp);
|
||||
if (interp == NULL) {
|
||||
// The intepreter was already destroyed.
|
||||
if (data->free != NULL) {
|
||||
// XXX Someone leaked some memory...
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
PyThreadState *save_tstate = NULL;
|
||||
if (interp != PyThreadState_Get()->interp) {
|
||||
// XXX Using the "head" thread isn't strictly correct.
|
||||
PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
|
||||
// XXX Possible GILState issues?
|
||||
save_tstate = PyThreadState_Swap(tstate);
|
||||
}
|
||||
|
||||
// "Release" the data and/or the object.
|
||||
if (data->free != NULL) {
|
||||
data->free(data->data);
|
||||
}
|
||||
Py_XDECREF(data->obj);
|
||||
|
||||
// Switch back.
|
||||
if (save_tstate != NULL) {
|
||||
PyThreadState_Swap(save_tstate);
|
||||
}
|
||||
}
|
||||
|
||||
PyObject *
|
||||
_PyCrossInterpreterData_NewObject(_PyCrossInterpreterData *data)
|
||||
{
|
||||
return data->new_object(data);
|
||||
}
|
||||
|
||||
/* registry of {type -> crossinterpdatafunc} */
|
||||
|
||||
/* 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. */
|
||||
|
||||
static int
|
||||
_register_xidata(PyTypeObject *cls, crossinterpdatafunc getdata)
|
||||
{
|
||||
// Note that we effectively replace already registered classes
|
||||
// rather than failing.
|
||||
struct _xidregitem *newhead = PyMem_RawMalloc(sizeof(struct _xidregitem));
|
||||
if (newhead == NULL)
|
||||
return -1;
|
||||
newhead->cls = cls;
|
||||
newhead->getdata = getdata;
|
||||
newhead->next = _PyRuntime.xidregistry.head;
|
||||
_PyRuntime.xidregistry.head = newhead;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _register_builtins_for_crossinterpreter_data(void);
|
||||
|
||||
int
|
||||
_PyCrossInterpreterData_Register_Class(PyTypeObject *cls,
|
||||
crossinterpdatafunc getdata)
|
||||
{
|
||||
if (!PyType_Check(cls)) {
|
||||
PyErr_Format(PyExc_ValueError, "only classes may be registered");
|
||||
return -1;
|
||||
}
|
||||
if (getdata == NULL) {
|
||||
PyErr_Format(PyExc_ValueError, "missing 'getdata' func");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Make sure the class isn't ever deallocated.
|
||||
Py_INCREF((PyObject *)cls);
|
||||
|
||||
PyThread_acquire_lock(_PyRuntime.xidregistry.mutex, WAIT_LOCK);
|
||||
if (_PyRuntime.xidregistry.head == NULL) {
|
||||
_register_builtins_for_crossinterpreter_data();
|
||||
}
|
||||
int res = _register_xidata(cls, getdata);
|
||||
PyThread_release_lock(_PyRuntime.xidregistry.mutex);
|
||||
return res;
|
||||
}
|
||||
|
||||
crossinterpdatafunc
|
||||
_PyCrossInterpreterData_Lookup(PyObject *obj)
|
||||
{
|
||||
PyObject *cls = PyObject_Type(obj);
|
||||
crossinterpdatafunc getdata = NULL;
|
||||
PyThread_acquire_lock(_PyRuntime.xidregistry.mutex, WAIT_LOCK);
|
||||
struct _xidregitem *cur = _PyRuntime.xidregistry.head;
|
||||
if (cur == NULL) {
|
||||
_register_builtins_for_crossinterpreter_data();
|
||||
cur = _PyRuntime.xidregistry.head;
|
||||
}
|
||||
for(; cur != NULL; cur = cur->next) {
|
||||
if (cur->cls == (PyTypeObject *)cls) {
|
||||
getdata = cur->getdata;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Py_DECREF(cls);
|
||||
PyThread_release_lock(_PyRuntime.xidregistry.mutex);
|
||||
return getdata;
|
||||
}
|
||||
|
||||
/* cross-interpreter data for builtin types */
|
||||
|
||||
static PyObject *
|
||||
_new_bytes_object(_PyCrossInterpreterData *data)
|
||||
{
|
||||
return PyBytes_FromString((char *)(data->data));
|
||||
}
|
||||
|
||||
static int
|
||||
_bytes_shared(PyObject *obj, _PyCrossInterpreterData *data)
|
||||
{
|
||||
data->data = (void *)(PyBytes_AS_STRING(obj));
|
||||
data->obj = obj; // Will be "released" (decref'ed) when data released.
|
||||
data->new_object = _new_bytes_object;
|
||||
data->free = NULL; // Do not free the data (it belongs to the object).
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
_new_none_object(_PyCrossInterpreterData *data)
|
||||
{
|
||||
// XXX Singleton refcounts are problematic across interpreters...
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static int
|
||||
_none_shared(PyObject *obj, _PyCrossInterpreterData *data)
|
||||
{
|
||||
data->data = NULL;
|
||||
// data->obj remains NULL
|
||||
data->new_object = _new_none_object;
|
||||
data->free = NULL; // There is nothing to free.
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_register_builtins_for_crossinterpreter_data(void)
|
||||
{
|
||||
// None
|
||||
if (_register_xidata((PyTypeObject *)PyObject_Type(Py_None), _none_shared) != 0) {
|
||||
Py_FatalError("could not register None for cross-interpreter sharing");
|
||||
}
|
||||
|
||||
// bytes
|
||||
if (_register_xidata(&PyBytes_Type, _bytes_shared) != 0) {
|
||||
Py_FatalError("could not register bytes for cross-interpreter sharing");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue