mirror of https://github.com/python/cpython
bpo-36854: Move _PyRuntimeState.gc to PyInterpreterState (GH-17287)
* Rename _PyGC_InitializeRuntime() to _PyGC_InitState() * finalize_interp_clear() now also calls _PyGC_Fini() in subinterpreters (clear the GC state).
This commit is contained in:
parent
488d02a241
commit
7247407c35
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
The garbage collector state becomes per interpreter
|
||||
(``PyInterpreterState.gc``), rather than being global
|
||||
(``_PyRuntimeState.gc``).
|
|
@ -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--;
|
||||
}
|
||||
|
|
|
@ -2131,11 +2131,14 @@ finally:
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1219,8 +1219,9 @@ finalize_interp_clear(PyThreadState *tstate, int is_main_interp)
|
|||
PyGrammar_RemoveAccelerators(&_PyParser_Grammar);
|
||||
|
||||
_PyExc_Fini();
|
||||
_PyGC_Fini(tstate);
|
||||
}
|
||||
|
||||
_PyGC_Fini(tstate);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue