gh-110310: Add a Per-Interpreter XID Registry for Heap Types (gh-110311)

We do the following:

* add a per-interpreter XID registry (PyInterpreterState.xidregistry)
* put heap types there (keep static types in _PyRuntimeState.xidregistry)
* clear the registries during interpreter/runtime finalization
* avoid duplicate entries in the registry (when _PyCrossInterpreterData_RegisterClass() is called more than once for a type)
* use Py_TYPE() instead of PyObject_Type() in _PyCrossInterpreterData_Lookup()

The per-interpreter registry helps preserve isolation between interpreters.  This is important when heap types are registered, which is something we haven't been doing yet but I will likely do soon.
This commit is contained in:
Eric Snow 2023-10-04 16:35:27 -06:00 • committed by GitHub
parent e561e98058
commit 80dc39e1dc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 148 additions and 58 deletions

View file

@ -39,6 +39,32 @@ struct _Py_long_state {
int max_str_digits;
};
/* 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. */
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 {
PyThread_type_lock mutex;
struct _xidregitem *head;
};
/* interpreter state */
/* PyInterpreterState holds the global state for one of the runtime's
@ -149,6 +175,9 @@ struct _is {
Py_ssize_t co_extra_user_count;
freefunc co_extra_freefuncs[MAX_CO_EXTRA_USERS];
// XXX Remove this field once we have a tp_* slot.
struct _xidregistry xidregistry;
#ifdef HAVE_FORK
PyObject *before_forkers;
PyObject *after_forkers_parent;
@ -238,21 +267,6 @@ _PyInterpreterState_SetFinalizing(PyInterpreterState *interp, PyThreadState *tst
}
/* 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. */
struct _xidregitem;
struct _xidregitem {
struct _xidregitem *prev;
struct _xidregitem *next;
PyObject *cls; // weakref to a PyTypeObject
crossinterpdatafunc getdata;
};
extern PyInterpreterState* _PyInterpreterState_LookUpID(int64_t);
extern int _PyInterpreterState_IDInitref(PyInterpreterState *);

View file

@ -201,10 +201,7 @@ typedef struct pyruntimestate {
tools. */
// XXX Remove this field once we have a tp_* slot.
struct _xidregistry {
PyThread_type_lock mutex;
struct _xidregitem *head;
} xidregistry;
struct _xidregistry xidregistry;
struct _pymem_allocators allocators;
struct _obmalloc_global_state obmalloc;