From 113b626baec85b64aafd412d49047ee1ed424b99 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 20 Nov 2019 11:54:39 +0100 Subject: [PATCH] bpo-36854: Move _PyRuntimeState.gc to PyInterpreterState * Rename _PyGC_InitializeRuntime() to _PyGC_InitState() * finalize_interp_clear() now also calls _PyGC_Fini() in subinterpreters. --- Include/internal/pycore_object.h | 2 +- Include/internal/pycore_pymem.h | 2 +- Include/internal/pycore_pystate.h | 7 +- .../2019-11-20-12-01-37.bpo-36854.Zga_md.rst | 3 + Modules/gcmodule.c | 72 ++++++++++--------- Objects/object.c | 20 ++++-- Python/pylifecycle.c | 3 +- Python/pystate.c | 2 +- 8 files changed, 62 insertions(+), 49 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2019-11-20-12-01-37.bpo-36854.Zga_md.rst diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 46555218bc5eaa..ba6636d7f8cfc4 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -38,7 +38,7 @@ static inline void _PyObject_GC_TRACK_impl(const char *filename, int lineno, filename, lineno, "_PyObject_GC_TRACK"); PyThreadState *tstate = _PyThreadState_GET(); - PyGC_Head *generation0 = tstate->interp->runtime->gc.generation0; + PyGC_Head *generation0 = tstate->interp->gc.generation0; PyGC_Head *last = (PyGC_Head*)(generation0->_gc_prev); _PyGCHead_SET_NEXT(last, gc); _PyGCHead_SET_PREV(gc, last); diff --git a/Include/internal/pycore_pymem.h b/Include/internal/pycore_pymem.h index 97d8fd99904a77..a4e972068348c6 100644 --- a/Include/internal/pycore_pymem.h +++ b/Include/internal/pycore_pymem.h @@ -144,7 +144,7 @@ struct _gc_runtime_state { Py_ssize_t long_lived_pending; }; -PyAPI_FUNC(void) _PyGC_InitializeRuntime(struct _gc_runtime_state *); +PyAPI_FUNC(void) _PyGC_InitState(struct _gc_runtime_state *); /* Set the memory allocator of the specified domain to the default. diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index fec64a7badba10..0c3c1e3df34de1 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -74,6 +74,8 @@ struct _is { int finalizing; + struct _gc_runtime_state gc; + PyObject *modules; PyObject *modules_by_index; PyObject *sysdict; @@ -130,9 +132,7 @@ struct _is { struct _warnings_runtime_state warnings; PyObject *audit_hooks; -/* - * See bpo-36876: miscellaneous ad hoc statics have been moved here. - */ + struct { struct { int level; @@ -239,7 +239,6 @@ typedef struct pyruntimestate { void (*exitfuncs[NEXITFUNCS])(void); int nexitfuncs; - struct _gc_runtime_state gc; struct _ceval_runtime_state ceval; struct _gilstate_runtime_state gilstate; diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-11-20-12-01-37.bpo-36854.Zga_md.rst b/Misc/NEWS.d/next/Core and Builtins/2019-11-20-12-01-37.bpo-36854.Zga_md.rst new file mode 100644 index 00000000000000..2b4d5b3bc85908 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2019-11-20-12-01-37.bpo-36854.Zga_md.rst @@ -0,0 +1,3 @@ +The garbage collector state becomes per interpreter +(``PyInterpreterState.gc``), rather than being global +(``_PyRuntimeState.gc``). diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 6fce9a8a0b6d71..967bbe9c0d45d0 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -133,7 +133,7 @@ static PyObject *gc_str = NULL; #define GEN_HEAD(gcstate, n) (&(gcstate)->generations[n].head) void -_PyGC_InitializeRuntime(GCState *gcstate) +_PyGC_InitState(GCState *gcstate) { gcstate->enabled = 1; /* automatic collection enabled? */ @@ -159,7 +159,7 @@ _PyGC_InitializeRuntime(GCState *gcstate) PyStatus _PyGC_Init(PyThreadState *tstate) { - GCState *gcstate = &tstate->interp->runtime->gc; + GCState *gcstate = &tstate->interp->gc; if (gcstate->garbage == NULL) { gcstate->garbage = PyList_New(0); if (gcstate->garbage == NULL) { @@ -1159,7 +1159,7 @@ collect(PyThreadState *tstate, int generation, PyGC_Head finalizers; /* objects with, & reachable from, __del__ */ PyGC_Head *gc; _PyTime_t t1 = 0; /* initialize to prevent a compiler warning */ - GCState *gcstate = &tstate->interp->runtime->gc; + GCState *gcstate = &tstate->interp->gc; if (gcstate->debug & DEBUG_STATS) { PySys_WriteStderr("gc: collecting generation %d...\n", generation); @@ -1324,7 +1324,7 @@ invoke_gc_callback(PyThreadState *tstate, const char *phase, assert(!_PyErr_Occurred(tstate)); /* we may get called very early */ - GCState *gcstate = &tstate->interp->runtime->gc; + GCState *gcstate = &tstate->interp->gc; if (gcstate->callbacks == NULL) { return; } @@ -1376,7 +1376,7 @@ collect_with_callback(PyThreadState *tstate, int generation) static Py_ssize_t collect_generations(PyThreadState *tstate) { - GCState *gcstate = &tstate->interp->runtime->gc; + GCState *gcstate = &tstate->interp->gc; /* Find the oldest generation (highest numbered) where the count * exceeds the threshold. Objects in the that generation and * generations younger than it will be collected. */ @@ -1410,7 +1410,7 @@ gc_enable_impl(PyObject *module) /*[clinic end generated code: output=45a427e9dce9155c input=81ac4940ca579707]*/ { PyThreadState *tstate = _PyThreadState_GET(); - GCState *gcstate = &tstate->interp->runtime->gc; + GCState *gcstate = &tstate->interp->gc; gcstate->enabled = 1; Py_RETURN_NONE; } @@ -1426,7 +1426,7 @@ gc_disable_impl(PyObject *module) /*[clinic end generated code: output=97d1030f7aa9d279 input=8c2e5a14e800d83b]*/ { PyThreadState *tstate = _PyThreadState_GET(); - GCState *gcstate = &tstate->interp->runtime->gc; + GCState *gcstate = &tstate->interp->gc; gcstate->enabled = 0; Py_RETURN_NONE; } @@ -1442,7 +1442,7 @@ gc_isenabled_impl(PyObject *module) /*[clinic end generated code: output=1874298331c49130 input=30005e0422373b31]*/ { PyThreadState *tstate = _PyThreadState_GET(); - GCState *gcstate = &tstate->interp->runtime->gc; + GCState *gcstate = &tstate->interp->gc; return gcstate->enabled; } @@ -1471,7 +1471,7 @@ gc_collect_impl(PyObject *module, int generation) return -1; } - GCState *gcstate = &tstate->interp->runtime->gc; + GCState *gcstate = &tstate->interp->gc; Py_ssize_t n; if (gcstate->collecting) { /* already collecting, don't do anything */ @@ -1508,7 +1508,7 @@ gc_set_debug_impl(PyObject *module, int flags) /*[clinic end generated code: output=7c8366575486b228 input=5e5ce15e84fbed15]*/ { PyThreadState *tstate = _PyThreadState_GET(); - GCState *gcstate = &tstate->interp->runtime->gc; + GCState *gcstate = &tstate->interp->gc; gcstate->debug = flags; Py_RETURN_NONE; } @@ -1524,7 +1524,7 @@ gc_get_debug_impl(PyObject *module) /*[clinic end generated code: output=91242f3506cd1e50 input=91a101e1c3b98366]*/ { PyThreadState *tstate = _PyThreadState_GET(); - GCState *gcstate = &tstate->interp->runtime->gc; + GCState *gcstate = &tstate->interp->gc; return gcstate->debug; } @@ -1538,7 +1538,7 @@ static PyObject * gc_set_threshold(PyObject *self, PyObject *args) { PyThreadState *tstate = _PyThreadState_GET(); - GCState *gcstate = &tstate->interp->runtime->gc; + GCState *gcstate = &tstate->interp->gc; if (!PyArg_ParseTuple(args, "i|ii:set_threshold", &gcstate->generations[0].threshold, &gcstate->generations[1].threshold, @@ -1562,7 +1562,7 @@ gc_get_threshold_impl(PyObject *module) /*[clinic end generated code: output=7902bc9f41ecbbd8 input=286d79918034d6e6]*/ { PyThreadState *tstate = _PyThreadState_GET(); - GCState *gcstate = &tstate->interp->runtime->gc; + GCState *gcstate = &tstate->interp->gc; return Py_BuildValue("(iii)", gcstate->generations[0].threshold, gcstate->generations[1].threshold, @@ -1580,7 +1580,7 @@ gc_get_count_impl(PyObject *module) /*[clinic end generated code: output=354012e67b16398f input=a392794a08251751]*/ { PyThreadState *tstate = _PyThreadState_GET(); - GCState *gcstate = &tstate->interp->runtime->gc; + GCState *gcstate = &tstate->interp->gc; return Py_BuildValue("(iii)", gcstate->generations[0].count, gcstate->generations[1].count, @@ -1630,7 +1630,7 @@ gc_get_referrers(PyObject *self, PyObject *args) return NULL; } - GCState *gcstate = &tstate->interp->runtime->gc; + GCState *gcstate = &tstate->interp->gc; for (i = 0; i < NUM_GENERATIONS; i++) { if (!(gc_referrers_for(args, GEN_HEAD(gcstate, i), result))) { Py_DECREF(result); @@ -1695,7 +1695,7 @@ gc_get_objects_impl(PyObject *module, Py_ssize_t generation) PyThreadState *tstate = _PyThreadState_GET(); int i; PyObject* result; - GCState *gcstate = &tstate->interp->runtime->gc; + GCState *gcstate = &tstate->interp->gc; result = PyList_New(0); if (result == NULL) { @@ -1754,7 +1754,7 @@ gc_get_stats_impl(PyObject *module) /* To get consistent values despite allocations while constructing the result list, we use a snapshot of the running stats. */ - GCState *gcstate = &tstate->interp->runtime->gc; + GCState *gcstate = &tstate->interp->gc; for (i = 0; i < NUM_GENERATIONS; i++) { stats[i] = gcstate->generation_stats[i]; } @@ -1827,7 +1827,7 @@ gc_freeze_impl(PyObject *module) /*[clinic end generated code: output=502159d9cdc4c139 input=b602b16ac5febbe5]*/ { PyThreadState *tstate = _PyThreadState_GET(); - GCState *gcstate = &tstate->interp->runtime->gc; + GCState *gcstate = &tstate->interp->gc; for (int i = 0; i < NUM_GENERATIONS; ++i) { gc_list_merge(GEN_HEAD(gcstate, i), &gcstate->permanent_generation.head); gcstate->generations[i].count = 0; @@ -1848,7 +1848,7 @@ gc_unfreeze_impl(PyObject *module) /*[clinic end generated code: output=1c15f2043b25e169 input=2dd52b170f4cef6c]*/ { PyThreadState *tstate = _PyThreadState_GET(); - GCState *gcstate = &tstate->interp->runtime->gc; + GCState *gcstate = &tstate->interp->gc; gc_list_merge(&gcstate->permanent_generation.head, GEN_HEAD(gcstate, NUM_GENERATIONS-1)); Py_RETURN_NONE; @@ -1865,7 +1865,7 @@ gc_get_freeze_count_impl(PyObject *module) /*[clinic end generated code: output=61cbd9f43aa032e1 input=45ffbc65cfe2a6ed]*/ { PyThreadState *tstate = _PyThreadState_GET(); - GCState *gcstate = &tstate->interp->runtime->gc; + GCState *gcstate = &tstate->interp->gc; return gc_list_size(&gcstate->permanent_generation.head); } @@ -1929,34 +1929,38 @@ static struct PyModuleDef gcmodule = { PyMODINIT_FUNC PyInit_gc(void) { - PyObject *m; + PyThreadState *tstate = _PyThreadState_GET(); + GCState *gcstate = &tstate->interp->gc; - m = PyModule_Create(&gcmodule); + PyObject *m = PyModule_Create(&gcmodule); if (m == NULL) { return NULL; } - GCState *gcstate = &_PyRuntime.gc; if (gcstate->garbage == NULL) { gcstate->garbage = PyList_New(0); - if (gcstate->garbage == NULL) + if (gcstate->garbage == NULL) { return NULL; + } } Py_INCREF(gcstate->garbage); - if (PyModule_AddObject(m, "garbage", gcstate->garbage) < 0) + if (PyModule_AddObject(m, "garbage", gcstate->garbage) < 0) { return NULL; + } if (gcstate->callbacks == NULL) { gcstate->callbacks = PyList_New(0); - if (gcstate->callbacks == NULL) + if (gcstate->callbacks == NULL) { return NULL; + } } Py_INCREF(gcstate->callbacks); - if (PyModule_AddObject(m, "callbacks", gcstate->callbacks) < 0) + if (PyModule_AddObject(m, "callbacks", gcstate->callbacks) < 0) { return NULL; + } -#define ADD_INT(NAME) if (PyModule_AddIntConstant(m, #NAME, NAME) < 0) return NULL +#define ADD_INT(NAME) if (PyModule_AddIntConstant(m, #NAME, NAME) < 0) { return NULL; } ADD_INT(DEBUG_STATS); ADD_INT(DEBUG_COLLECTABLE); ADD_INT(DEBUG_UNCOLLECTABLE); @@ -1971,7 +1975,7 @@ Py_ssize_t PyGC_Collect(void) { PyThreadState *tstate = _PyThreadState_GET(); - GCState *gcstate = &tstate->interp->runtime->gc; + GCState *gcstate = &tstate->interp->gc; if (!gcstate->enabled) { return 0; @@ -2006,7 +2010,7 @@ _PyGC_CollectNoFail(void) PyThreadState *tstate = _PyThreadState_GET(); assert(!_PyErr_Occurred(tstate)); - GCState *gcstate = &tstate->interp->runtime->gc; + GCState *gcstate = &tstate->interp->gc; Py_ssize_t n; /* Ideally, this function is only called on interpreter shutdown, @@ -2029,7 +2033,7 @@ _PyGC_CollectNoFail(void) void _PyGC_DumpShutdownStats(PyThreadState *tstate) { - GCState *gcstate = &tstate->interp->runtime->gc; + GCState *gcstate = &tstate->interp->gc; if (!(gcstate->debug & DEBUG_SAVEALL) && gcstate->garbage != NULL && PyList_GET_SIZE(gcstate->garbage) > 0) { const char *message; @@ -2066,7 +2070,7 @@ _PyGC_DumpShutdownStats(PyThreadState *tstate) void _PyGC_Fini(PyThreadState *tstate) { - GCState *gcstate = &tstate->interp->runtime->gc; + GCState *gcstate = &tstate->interp->gc; Py_CLEAR(gcstate->garbage); Py_CLEAR(gcstate->callbacks); } @@ -2131,7 +2135,7 @@ static PyObject * _PyObject_GC_Alloc(int use_calloc, size_t basicsize) { PyThreadState *tstate = _PyThreadState_GET(); - GCState *gcstate = &tstate->interp->runtime->gc; + GCState *gcstate = &tstate->interp->gc; if (basicsize > PY_SSIZE_T_MAX - sizeof(PyGC_Head)) { return _PyErr_NoMemory(tstate); } @@ -2230,7 +2234,7 @@ PyObject_GC_Del(void *op) gc_list_remove(g); } PyThreadState *tstate = _PyThreadState_GET(); - GCState *gcstate = &tstate->interp->runtime->gc; + GCState *gcstate = &tstate->interp->gc; if (gcstate->generations[0].count > 0) { gcstate->generations[0].count--; } diff --git a/Objects/object.c b/Objects/object.c index 3e612825c27775..6fc114621c1d1d 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -2131,11 +2131,14 @@ Py_ReprLeave(PyObject *obj) void _PyTrash_deposit_object(PyObject *op) { + PyThreadState *tstate = _PyThreadState_GET(); + struct _gc_runtime_state *gcstate = &tstate->interp->gc; + _PyObject_ASSERT(op, PyObject_IS_GC(op)); _PyObject_ASSERT(op, !_PyObject_GC_IS_TRACKED(op)); _PyObject_ASSERT(op, op->ob_refcnt == 0); - _PyGCHead_SET_PREV(_Py_AS_GC(op), _PyRuntime.gc.trash_delete_later); - _PyRuntime.gc.trash_delete_later = op; + _PyGCHead_SET_PREV(_Py_AS_GC(op), gcstate->trash_delete_later); + gcstate->trash_delete_later = op; } /* The equivalent API, using per-thread state recursion info */ @@ -2156,11 +2159,14 @@ _PyTrash_thread_deposit_object(PyObject *op) void _PyTrash_destroy_chain(void) { - while (_PyRuntime.gc.trash_delete_later) { - PyObject *op = _PyRuntime.gc.trash_delete_later; + PyThreadState *tstate = _PyThreadState_GET(); + struct _gc_runtime_state *gcstate = &tstate->interp->gc; + + while (gcstate->trash_delete_later) { + PyObject *op = gcstate->trash_delete_later; destructor dealloc = Py_TYPE(op)->tp_dealloc; - _PyRuntime.gc.trash_delete_later = + gcstate->trash_delete_later = (PyObject*) _PyGCHead_PREV(_Py_AS_GC(op)); /* Call the deallocator directly. This used to try to @@ -2170,9 +2176,9 @@ _PyTrash_destroy_chain(void) * up distorting allocation statistics. */ _PyObject_ASSERT(op, op->ob_refcnt == 0); - ++_PyRuntime.gc.trash_delete_nesting; + ++gcstate->trash_delete_nesting; (*dealloc)(op); - --_PyRuntime.gc.trash_delete_nesting; + --gcstate->trash_delete_nesting; } } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 73114df79cd8e3..2fe4833ad2860b 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1213,8 +1213,9 @@ finalize_interp_clear(PyThreadState *tstate, int is_main_interp) PyGrammar_RemoveAccelerators(&_PyParser_Grammar); _PyExc_Fini(); - _PyGC_Fini(tstate); } + + _PyGC_Fini(tstate); } diff --git a/Python/pystate.c b/Python/pystate.c index 93f0ce798888dc..2fc563bf5836d9 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -58,7 +58,6 @@ _PyRuntimeState_Init_impl(_PyRuntimeState *runtime) runtime->open_code_userdata = open_code_userdata; runtime->audit_hook_head = audit_hook_head; - _PyGC_InitializeRuntime(&runtime->gc); _PyEval_Initialize(&runtime->ceval); PyPreConfig_InitPythonConfig(&runtime->preconfig); @@ -208,6 +207,7 @@ PyInterpreterState_New(void) _PyRuntimeState *runtime = &_PyRuntime; interp->runtime = runtime; + _PyGC_InitState(&interp->gc); PyConfig_InitPythonConfig(&interp->config); interp->eval_frame = _PyEval_EvalFrameDefault; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy