diff options
author | Victor Stinner <vstinner@python.org> | 2019-11-20 11:25:50 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-11-20 11:25:50 (GMT) |
commit | 7247407c35330f3f6292f1d40606b7ba6afd5700 (patch) | |
tree | fa9307b2cdbf41bf30c90daf12c76dd439949cfd | |
parent | 488d02a24142948bfb1fafd19fa48e61fcbbabc5 (diff) | |
download | cpython-7247407c35330f3f6292f1d40606b7ba6afd5700.zip cpython-7247407c35330f3f6292f1d40606b7ba6afd5700.tar.gz cpython-7247407c35330f3f6292f1d40606b7ba6afd5700.tar.bz2 |
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).
-rw-r--r-- | Include/internal/pycore_object.h | 2 | ||||
-rw-r--r-- | Include/internal/pycore_pymem.h | 2 | ||||
-rw-r--r-- | Include/internal/pycore_pystate.h | 7 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Core and Builtins/2019-11-20-12-01-37.bpo-36854.Zga_md.rst | 3 | ||||
-rw-r--r-- | Modules/gcmodule.c | 72 | ||||
-rw-r--r-- | Objects/object.c | 20 | ||||
-rw-r--r-- | Python/pylifecycle.c | 3 | ||||
-rw-r--r-- | Python/pystate.c | 2 |
8 files changed, 62 insertions, 49 deletions
diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 4655521..ba6636d 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 97d8fd9..a4e9720 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 fec64a7..0c3c1e3 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 0000000..2b4d5b3 --- /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 6fce9a8..967bbe9 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 3e61282..6fc1146 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -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; } } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 41b9596..2149dbf 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -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); } diff --git a/Python/pystate.c b/Python/pystate.c index 93f0ce7..2fc563b 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; |