Content-Length: 574605 | pFad | http://github.com/python/cpython/pull/111530/commits/2edcb49c64cb941e84e52eff46c88f9fe51ce454

60 gh-76785: Crossinterp utils additions by ericsnowcurrently · Pull Request #111530 · python/cpython · GitHub
Skip to content

gh-76785: Crossinterp utils additions #111530

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
67a88c2
Factor out _Py_excinfo.
ericsnowcurrently Oct 24, 2023
a9ea9ac
Extract _PyXI_errcode.
ericsnowcurrently Oct 25, 2023
33d91af
Extract _PyXI_exception_info.
ericsnowcurrently Oct 25, 2023
2424e33
Extract _PyXI_namespace.
ericsnowcurrently Oct 25, 2023
23d6959
Factor out _enter_interpreter(), _exit_interpreter(), etc.
ericsnowcurrently Oct 23, 2023
b08249f
Move enter/exit to crossinterp.c.
ericsnowcurrently Oct 27, 2023
773f5ab
Factor out _sharednsitem_set_value().
ericsnowcurrently Oct 23, 2023
cf7354e
Add _PyXI_NamespaceFromNames().
ericsnowcurrently Oct 31, 2023
6b43620
Add a default arg to _PyXI_ApplyNamespace().
ericsnowcurrently Oct 31, 2023
caef717
Allocate xid dynamically when in target interpreter.
ericsnowcurrently Oct 31, 2023
0bd42e0
Add _PyXI_FillNamespaceFromDict().
ericsnowcurrently Oct 31, 2023
a230f77
Add xid_state structs and lifecycle funcs.
ericsnowcurrently Oct 31, 2023
5675f86
Add PyExc_NotShareableError.
ericsnowcurrently Oct 31, 2023
45488f2
Propagate the ValueError when a value is not shareable.
ericsnowcurrently Oct 31, 2023
6f07364
Propagate errors in _PyXI_Enter() directly.
ericsnowcurrently Oct 31, 2023
0201b7f
Factor out _init_not_shareable_error_type() and _fini_not_shareable_e…
ericsnowcurrently Nov 1, 2023
d32a918
Drop some duplicate lines.
ericsnowcurrently Nov 1, 2023
1d4fc87
Fix a comment.
ericsnowcurrently Nov 1, 2023
88c9d54
Call _PyXI_Fini() *before* the interpreter is cleared.
ericsnowcurrently Nov 1, 2023
2edcb49
Fix init/fini.
ericsnowcurrently Nov 1, 2023
8e53752
Add _get_not_shareable_error_type().
ericsnowcurrently Nov 1, 2023
53764c1
Export fewer symbols.
ericsnowcurrently Nov 1, 2023
cacf969
Merge branch 'main' into crossinterp-utils-additions
ericsnowcurrently Nov 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Fix init/fini.
  • Loading branch information
ericsnowcurrently committed Nov 1, 2023
commit 2edcb49c64cb941e84e52eff46c88f9fe51ce454
2 changes: 2 additions & 0 deletions Include/internal/pycore_crossinterp.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ struct _xidregitem {
};

struct _xidregistry {
int global; /* builtin types or heap types */
int initialized;
PyThread_type_lock mutex;
struct _xidregitem *head;
};
Expand Down
5 changes: 5 additions & 0 deletions Include/internal/pycore_runtime_init.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ extern PyTypeObject _PyExc_MemoryError;
until _PyInterpreterState_Enable() is called. */ \
.next_id = -1, \
}, \
.xi = { \
.registry = { \
.global = 1, \
}, \
}, \
/* A TSS key must be initialized with Py_tss_NEEDS_INIT \
in accordance with the specification. */ \
.autoTSSkey = Py_tss_NEEDS_INIT, \
Expand Down
152 changes: 108 additions & 44 deletions Python/crossinterp.c
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,28 @@ _PyCrossInterpreterData_ReleaseAndRawFree(_PyCrossInterpreterData *data)
alternative would be to add a tp_* slot for a class's
crossinterpdatafunc. It would be simpler and more efficient. */

static inline struct _xidregistry *
_get_global_xidregistry(_PyRuntimeState *runtime)
{
return &runtime->xi.registry;
}

static inline struct _xidregistry *
_get_xidregistry(PyInterpreterState *interp)
{
return &interp->xi.registry;
}

static inline struct _xidregistry *
_get_xidregistry_for_type(PyInterpreterState *interp, PyTypeObject *cls)
{
struct _xidregistry *registry = _get_global_xidregistry(interp->runtime);
if (cls->tp_flags & Py_TPFLAGS_HEAPTYPE) {
registry = _get_xidregistry(interp);
}
return registry;
}

static int
_xidregistry_add_type(struct _xidregistry *xidregistry,
PyTypeObject *cls, crossinterpdatafunc getdata)
Expand Down Expand Up @@ -409,10 +431,8 @@ _xidregistry_remove_entry(struct _xidregistry *xidregistry,
return next;
}

// This is used in pystate.c (for now).
// XXX Call this is _PyXI_Fini() instead of _PyRuntimeState_Fini()?
void
_Py_xidregistry_clear(struct _xidregistry *xidregistry)
static void
_xidregistry_clear(struct _xidregistry *xidregistry)
{
struct _xidregitem *cur = xidregistry->head;
xidregistry->head = NULL;
Expand All @@ -424,6 +444,22 @@ _Py_xidregistry_clear(struct _xidregistry *xidregistry)
}
}

static void
_xidregistry_lock(struct _xidregistry *registry)
{
if (registry->mutex != NULL) {
PyThread_acquire_lock(registry->mutex, WAIT_LOCK);
}
}

static void
_xidregistry_unlock(struct _xidregistry *registry)
{
if (registry->mutex != NULL) {
PyThread_release_lock(registry->mutex);
}
}

static struct _xidregitem *
_xidregistry_find_type(struct _xidregistry *xidregistry, PyTypeObject *cls)
{
Expand All @@ -450,30 +486,6 @@ _xidregistry_find_type(struct _xidregistry *xidregistry, PyTypeObject *cls)
return NULL;
}

static inline struct _xidregistry *
_get_xidregistry(PyInterpreterState *interp, PyTypeObject *cls)
{
struct _xidregistry *xidregistry = &interp->runtime->xi.registry;
if (cls->tp_flags & Py_TPFLAGS_HEAPTYPE) {
assert(interp->xi.registry.mutex == xidregistry->mutex);
xidregistry = &interp->xi.registry;
}
return xidregistry;
}

static void _register_builtins_for_crossinterpreter_data(struct _xidregistry *xidregistry);

static inline void
_ensure_builtins_xid(PyInterpreterState *interp, struct _xidregistry *xidregistry)
{
if (xidregistry != &interp->xi.registry) {
assert(xidregistry == &interp->runtime->xi.registry);
if (xidregistry->head == NULL) {
_register_builtins_for_crossinterpreter_data(xidregistry);
}
}
}

int
_PyCrossInterpreterData_RegisterClass(PyTypeObject *cls,
crossinterpdatafunc getdata)
Expand All @@ -489,11 +501,8 @@ _PyCrossInterpreterData_RegisterClass(PyTypeObject *cls,

int res = 0;
PyInterpreterState *interp = _PyInterpreterState_GET();
struct _xidregistry *xidregistry = _get_xidregistry(interp, cls);
PyThread_acquire_lock(xidregistry->mutex, WAIT_LOCK);

// XXX Do this once in _PyXI_Init()?
_ensure_builtins_xid(interp, xidregistry);
struct _xidregistry *xidregistry = _get_xidregistry_for_type(interp, cls);
_xidregistry_lock(xidregistry);

struct _xidregitem *matched = _xidregistry_find_type(xidregistry, cls);
if (matched != NULL) {
Expand All @@ -505,7 +514,7 @@ _PyCrossInterpreterData_RegisterClass(PyTypeObject *cls,
res = _xidregistry_add_type(xidregistry, cls, getdata);

finally:
PyThread_release_lock(xidregistry->mutex);
_xidregistry_unlock(xidregistry);
return res;
}

Expand All @@ -514,8 +523,8 @@ _PyCrossInterpreterData_UnregisterClass(PyTypeObject *cls)
{
int res = 0;
PyInterpreterState *interp = _PyInterpreterState_GET();
struct _xidregistry *xidregistry = _get_xidregistry(interp, cls);
PyThread_acquire_lock(xidregistry->mutex, WAIT_LOCK);
struct _xidregistry *xidregistry = _get_xidregistry_for_type(interp, cls);
_xidregistry_lock(xidregistry);

struct _xidregitem *matched = _xidregistry_find_type(xidregistry, cls);
if (matched != NULL) {
Expand All @@ -527,7 +536,7 @@ _PyCrossInterpreterData_UnregisterClass(PyTypeObject *cls)
res = 1;
}

PyThread_release_lock(xidregistry->mutex);
_xidregistry_unlock(xidregistry);
return res;
}

Expand All @@ -536,15 +545,13 @@ _lookup_getdata_from_registry(PyInterpreterState *interp, PyObject *obj)
{
PyTypeObject *cls = Py_TYPE(obj);

struct _xidregistry *xidregistry = _get_xidregistry(interp, cls);
PyThread_acquire_lock(xidregistry->mutex, WAIT_LOCK);

_ensure_builtins_xid(interp, xidregistry);
struct _xidregistry *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;

PyThread_release_lock(xidregistry->mutex);
_xidregistry_unlock(xidregistry);
return func;
}

Expand Down Expand Up @@ -680,6 +687,55 @@ _register_builtins_for_crossinterpreter_data(struct _xidregistry *xidregistry)
}
}

/* registry lifecycle */

static void
_xidregistry_init(struct _xidregistry *registry)
{
if (registry->initialized) {
return;
}
registry->initialized = 1;

if (registry->global) {
// We manage the mutex lifecycle in pystate.c.
assert(registry->mutex != NULL);

// Registering the builtins is cheap so we don't bother doing it lazily.
assert(registry->head == NULL);
_register_builtins_for_crossinterpreter_data(registry);
}
else {
// Within an interpreter we rely on the GIL instead of a separate lock.
assert(registry->mutex == NULL);

// There's nothing else to initialize.
}
}

static void
_xidregistry_fini(struct _xidregistry *registry)
{
if (!registry->initialized) {
return;
}
registry->initialized = 0;

_xidregistry_clear(registry);

if (registry->global) {
// We manage the mutex lifecycle in pystate.c.
assert(registry->mutex != NULL);
}
else {
// There's nothing else to finalize.

// Within an interpreter we rely on the GIL instead of a separate lock.
assert(registry->mutex == NULL);
}
}


/*************************/
/* convenience utilities */
/*************************/
Expand Down Expand Up @@ -1408,7 +1464,11 @@ _PyXI_Init(PyInterpreterState *interp)
{
PyStatus status;

// XXX Initialize xidregistry.
// Initialize the XID registry.
if (_Py_IsMainInterpreter(interp)) {
_xidregistry_init(_get_global_xidregistry(interp->runtime));
}
_xidregistry_init(_get_xidregistry(interp));

// Initialize exceptions (heap types).
status = _init_not_shareable_error_type(interp);
Expand All @@ -1428,5 +1488,9 @@ _PyXI_Fini(PyInterpreterState *interp)
// Finalize exceptions (heap types).
_fini_not_shareable_error_type(interp);

// XXX Clear xidregistry.
// Finalize the XID registry.
_xidregistry_fini(_get_xidregistry(interp));
if (_Py_IsMainInterpreter(interp)) {
_xidregistry_fini(_get_global_xidregistry(interp->runtime));
}
}
17 changes: 0 additions & 17 deletions Python/pystate.c
Original file line number Diff line number Diff line change
Expand Up @@ -494,9 +494,6 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime)
return _PyStatus_OK();
}

// This is defined in crossinterp.c (for now).
extern void _Py_xidregistry_clear(struct _xidregistry *);

void
_PyRuntimeState_Fini(_PyRuntimeState *runtime)
{
Expand All @@ -505,8 +502,6 @@ _PyRuntimeState_Fini(_PyRuntimeState *runtime)
assert(runtime->object_state.interpreter_leaks == 0);
#endif

_Py_xidregistry_clear(&runtime->xi.registry);

if (gilstate_tss_initialized(runtime)) {
gilstate_tss_fini(runtime);
}
Expand Down Expand Up @@ -552,11 +547,6 @@ _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime)
for (int i = 0; i < NUMLOCKS; i++) {
reinit_err += _PyThread_at_fork_reinit(lockptrs[i]);
}
/* PyOS_AfterFork_Child(), which calls this function, later calls
_PyInterpreterState_DeleteExceptMain(), so we only need to update
the main interpreter here. */
assert(runtime->interpreters.main != NULL);
runtime->interpreters.main->xi.registry.mutex = runtime->xi.registry.mutex;

PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);

Expand Down Expand Up @@ -720,9 +710,6 @@ init_interpreter(PyInterpreterState *interp,
}
interp->f_opcode_trace_set = false;

assert(runtime->xi.registry.mutex != NULL);
interp->xi.registry.mutex = runtime->xi.registry.mutex;

interp->_initialized = 1;
return _PyStatus_OK();
}
Expand Down Expand Up @@ -948,10 +935,6 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate)
Py_CLEAR(interp->sysdict);
Py_CLEAR(interp->builtins);

_Py_xidregistry_clear(&interp->xi.registry);
/* The lock is owned by the runtime, so we don't free it here. */
interp->xi.registry.mutex = NULL;

if (tstate->interp == interp) {
/* We are now safe to fix tstate->_status.cleared. */
// XXX Do this (much) earlier?
Expand Down








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/python/cpython/pull/111530/commits/2edcb49c64cb941e84e52eff46c88f9fe51ce454

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy