Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

gh-125286: Share the Main Refchain With Legacy Interpreters#125709

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 ourterms of service andprivacy 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 fromall commits
Commits
Show all changes
16 commits
Select commitHold shift + click to select a range
53cfb82
Share the main refchain with legacy interpreters.
ericsnowcurrentlyOct 18, 2024
b2bf609
Add a has_own_refchain() helper function.
ericsnowcurrentlyOct 18, 2024
203c112
Drop _Py_NormalizeImmortalReference().
ericsnowcurrentlyOct 21, 2024
ffe2633
Drop has_own_refchain() calls where not needed.
ericsnowcurrentlyOct 21, 2024
8d52258
Call _PyObject_InitState() *after* computing the feature flags.
ericsnowcurrentlyOct 21, 2024
216dde2
Revert "Call _PyObject_InitState() *after* computing the feature flags."
ericsnowcurrentlyOct 21, 2024
fbc4e2d
Revert "Drop has_own_refchain() calls where not needed."
ericsnowcurrentlyOct 21, 2024
cb06847
has_own_refchain() -> maybe_fix_refchain()
ericsnowcurrentlyOct 21, 2024
7aa33a9
Handle late runtime fini correctly.
ericsnowcurrentlyOct 21, 2024
3421a19
Pass the interpreter config to init_interpreter().
ericsnowcurrentlyOct 22, 2024
b276454
Revert "Pass the interpreter config to init_interpreter()."
ericsnowcurrentlyOct 22, 2024
7ab086c
Move the _PyObject_InitState() call out of init_interpreter().
ericsnowcurrentlyOct 22, 2024
9d539f6
Add docs and a What's New entry
encukouOct 22, 2024
d80fe6a
Fix typos.
ericsnowcurrentlyOct 22, 2024
1360d86
Do not try to destroy the refchain if it is NULL.
ericsnowcurrentlyOct 22, 2024
090b528
Docs: Link to the new sys.getobjects() docs
encukouOct 23, 2024
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
29 changes: 29 additions & 0 deletionsDoc/library/sys.rst
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -920,6 +920,35 @@ always available.
It is not guaranteed to exist in all implementations of Python.


.. function:: getobjects(limit[, type])

This function only exists if CPython was built using the
specialized configure option :option:`--with-trace-refs`.
It is intended only for debugging garbage-collection issues.

Return a list of up to *limit* dynamically allocated Python objects.
If *type* is given, only objects of that exact type (not subtypes)
are included.

Objects from the list are not safe to use.
Specifically, the result will include objects from all interpreters that
share their object allocator state (that is, ones created with
:c:member:`PyInterpreterConfig.use_main_obmalloc` set to 1
or using :c:func:`Py_NewInterpreter`, and the
:ref:`main interpreter <sub-interpreter-support>`).
Mixing objects from different interpreters may lead to crashes
or other unexpected behavior.

.. impl-detail::

This function should be used for specialized purposes only.
It is not guaranteed to exist in all implementations of Python.

.. versionchanged:: next

The result may include objects from other interpreters.


.. function:: getprofile()

.. index::
Expand Down
2 changes: 1 addition & 1 deletionDoc/using/configure.rst
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -702,7 +702,7 @@ Debug options
Effects:

* Define the ``Py_TRACE_REFS`` macro.
* Add :func:`!sys.getobjects` function.
* Add :func:`sys.getobjects` function.
* Add :envvar:`PYTHONDUMPREFS` environment variable.

The :envvar:`PYTHONDUMPREFS` environment variable can be used to dump
Expand Down
9 changes: 9 additions & 0 deletionsDoc/whatsnew/3.14.rst
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -407,6 +407,15 @@ symtable

(Contributed by Bénédikt Tran in :gh:`120029`.)


sys
---

* The previously undocumented special function :func:`sys.getobjects`,
which only exists in specialized builds of Python, may now return objects
from other interpreters than the one it's called in.


unicodedata
-----------

Expand Down
92 changes: 44 additions & 48 deletionsObjects/object.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -171,6 +171,48 @@ _PyDebug_PrintTotalRefs(void) {
#define REFCHAIN(interp) interp->object_state.refchain
#define REFCHAIN_VALUE ((void*)(uintptr_t)1)

static inline int
has_own_refchain(PyInterpreterState *interp)
{
if (interp->feature_flags & Py_RTFLAGS_USE_MAIN_OBMALLOC) {
return (_Py_IsMainInterpreter(interp)
|| _PyInterpreterState_Main() == NULL);
}
return 1;
}

static int
refchain_init(PyInterpreterState *interp)
{
if (!has_own_refchain(interp)) {
// Legacy subinterpreters share a refchain with the main interpreter.
REFCHAIN(interp) = REFCHAIN(_PyInterpreterState_Main());
return 0;
}
_Py_hashtable_allocator_t alloc = {
// Don't use default PyMem_Malloc() and PyMem_Free() which
// require the caller to hold the GIL.
.malloc = PyMem_RawMalloc,
.free = PyMem_RawFree,
};
REFCHAIN(interp) = _Py_hashtable_new_full(
_Py_hashtable_hash_ptr, _Py_hashtable_compare_direct,
NULL, NULL, &alloc);
if (REFCHAIN(interp) == NULL) {
return -1;
}
return 0;
}

static void
refchain_fini(PyInterpreterState *interp)
{
if (has_own_refchain(interp) && REFCHAIN(interp) != NULL) {
_Py_hashtable_destroy(REFCHAIN(interp));
}
REFCHAIN(interp) = NULL;
}

bool
_PyRefchain_IsTraced(PyInterpreterState *interp, PyObject *obj)
{
Expand DownExpand Up@@ -2191,16 +2233,7 @@ PyStatus
_PyObject_InitState(PyInterpreterState *interp)
{
#ifdef Py_TRACE_REFS
_Py_hashtable_allocator_t alloc = {
// Don't use default PyMem_Malloc() and PyMem_Free() which
// require the caller to hold the GIL.
.malloc = PyMem_RawMalloc,
.free = PyMem_RawFree,
};
REFCHAIN(interp) = _Py_hashtable_new_full(
_Py_hashtable_hash_ptr, _Py_hashtable_compare_direct,
NULL, NULL, &alloc);
if (REFCHAIN(interp) == NULL) {
if (refchain_init(interp) < 0) {
return _PyStatus_NO_MEMORY();
}
#endif
Expand All@@ -2211,8 +2244,7 @@ void
_PyObject_FiniState(PyInterpreterState *interp)
{
#ifdef Py_TRACE_REFS
_Py_hashtable_destroy(REFCHAIN(interp));
REFCHAIN(interp) = NULL;
refchain_fini(interp);
#endif
}

Expand DownExpand Up@@ -2501,42 +2533,6 @@ _Py_ResurrectReference(PyObject *op)


#ifdef Py_TRACE_REFS
/* Make sure the ref is associated with the right interpreter.
* This only needs special attention for heap-allocated objects
* that have been immortalized, and only when the object might
* outlive the interpreter where it was created. That means the
* object was necessarily created using a global allocator
* (i.e. from the main interpreter). Thus in that specific case
* we move the object over to the main interpreter's refchain.
*
* This was added for the sake of the immortal interned strings,
* where legacy subinterpreters share the main interpreter's
* interned dict (and allocator), and therefore the strings can
* outlive the subinterpreter.
*
* It may make sense to fold this into _Py_SetImmortalUntracked(),
* but that requires further investigation. In the meantime, it is
* up to the caller to know if this is needed. There should be
* very few cases.
*/
void
_Py_NormalizeImmortalReference(PyObject *op)
{
assert(_Py_IsImmortal(op));
PyInterpreterState *interp = _PyInterpreterState_GET();
if (!_PyRefchain_IsTraced(interp, op)) {
return;
}
PyInterpreterState *main_interp = _PyInterpreterState_Main();
if (interp != main_interp
&& interp->feature_flags & Py_RTFLAGS_USE_MAIN_OBMALLOC)
{
assert(!_PyRefchain_IsTraced(main_interp, op));
_PyRefchain_Remove(interp, op);
_PyRefchain_Trace(main_interp, op);
}
}

void
_Py_ForgetReference(PyObject *op)
{
Expand Down
8 changes: 0 additions & 8 deletionsObjects/unicodeobject.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -15444,10 +15444,6 @@ _PyUnicode_InternStatic(PyInterpreterState *interp, PyObject **p)
assert(*p);
}

#ifdef Py_TRACE_REFS
extern void _Py_NormalizeImmortalReference(PyObject *);
#endif

static void
immortalize_interned(PyObject *s)
{
Expand All@@ -15463,10 +15459,6 @@ immortalize_interned(PyObject *s)
#endif
_PyUnicode_STATE(s).interned = SSTATE_INTERNED_IMMORTAL;
_Py_SetImmortal(s);
#ifdef Py_TRACE_REFS
/* Make sure the ref is associated with the right interpreter. */
_Py_NormalizeImmortalReference(s);
#endif
}

static /* non-null */ PyObject*
Expand Down
14 changes: 14 additions & 0 deletionsPython/pylifecycle.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -674,6 +674,13 @@ pycore_create_interpreter(_PyRuntimeState *runtime,
return status;
}

// This could be done in init_interpreter() (in pystate.c) if it
// didn't depend on interp->feature_flags being set already.
status = _PyObject_InitState(interp);
if (_PyStatus_EXCEPTION(status)) {
return status;
}

// initialize the interp->obmalloc state. This must be done after
// the settings are loaded (so that feature_flags are set) but before
// any calls are made to obmalloc functions.
Expand DownExpand Up@@ -2297,6 +2304,13 @@ new_interpreter(PyThreadState **tstate_p,
goto error;
}

// This could be done in init_interpreter() (in pystate.c) if it
// didn't depend on interp->feature_flags being set already.
status = _PyObject_InitState(interp);
if (_PyStatus_EXCEPTION(status)) {
return status;
}

// initialize the interp->obmalloc state. This must be done after
// the settings are loaded (so that feature_flags are set) but before
// any calls are made to obmalloc functions.
Expand Down
6 changes: 2 additions & 4 deletionsPython/pystate.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -629,10 +629,8 @@ init_interpreter(PyInterpreterState *interp,
assert(next != NULL || (interp == runtime->interpreters.main));
interp->next = next;

PyStatus status = _PyObject_InitState(interp);
if (_PyStatus_EXCEPTION(status)) {
return status;
}
// We would call _PyObject_InitState() at this point
// if interp->feature_flags were alredy set.

_PyEval_InitState(interp);
_PyGC_InitState(&interp->gc);
Expand Down

[8]ページ先頭

©2009-2025 Movatter.jp