From 8b3414818f5289eac530bf38bcfbd7b2b851805c Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 30 Oct 2020 17:00:00 +0100 Subject: bpo-42208: Pass tstate to _PyGC_CollectNoFail() (GH-23038) Move private _PyGC_CollectNoFail() to the internal C API. Remove the private _PyGC_CollectIfEnabled() which was just an alias to the public PyGC_Collect() function since Python 3.8. Rename functions: * collect() => gc_collect_main() * collect_with_callback() => gc_collect_with_callback() * collect_generations() => gc_collect_generations() --- Include/cpython/objimpl.h | 4 ---- Include/internal/pycore_gc.h | 4 +++- Modules/gcmodule.c | 43 ++++++++++++++++++------------------------- Python/import.c | 4 ++-- Python/pylifecycle.c | 4 ++-- 5 files changed, 25 insertions(+), 34 deletions(-) diff --git a/Include/cpython/objimpl.h b/Include/cpython/objimpl.h index 15999a2..d83700e 100644 --- a/Include/cpython/objimpl.h +++ b/Include/cpython/objimpl.h @@ -79,10 +79,6 @@ PyAPI_FUNC(void) PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator); PyAPI_FUNC(void) PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator); -PyAPI_FUNC(Py_ssize_t) _PyGC_CollectNoFail(void); -PyAPI_FUNC(Py_ssize_t) _PyGC_CollectIfEnabled(void); - - /* Test if an object implements the garbage collector protocol */ PyAPI_FUNC(int) PyObject_IS_GC(PyObject *obj); diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index da202a1..e2d47c9 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -161,7 +161,9 @@ struct _gc_runtime_state { Py_ssize_t long_lived_pending; }; -PyAPI_FUNC(void) _PyGC_InitState(struct _gc_runtime_state *); +extern void _PyGC_InitState(struct _gc_runtime_state *); + +extern Py_ssize_t _PyGC_CollectNoFail(PyThreadState *tstate); // Functions to clear types free lists diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 8833400..d90ff33 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -1176,8 +1176,9 @@ handle_resurrected_objects(PyGC_Head *unreachable, PyGC_Head* still_unreachable, /* This is the main function. Read this to understand how the * collection process works. */ static Py_ssize_t -collect(PyThreadState *tstate, int generation, - Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable, int nofail) +gc_collect_main(PyThreadState *tstate, int generation, + Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable, + int nofail) { int i; Py_ssize_t m = 0; /* # objects collected */ @@ -1395,19 +1396,19 @@ invoke_gc_callback(PyThreadState *tstate, const char *phase, * progress callbacks. */ static Py_ssize_t -collect_with_callback(PyThreadState *tstate, int generation) +gc_collect_with_callback(PyThreadState *tstate, int generation) { assert(!_PyErr_Occurred(tstate)); Py_ssize_t result, collected, uncollectable; invoke_gc_callback(tstate, "start", generation, 0, 0); - result = collect(tstate, generation, &collected, &uncollectable, 0); + result = gc_collect_main(tstate, generation, &collected, &uncollectable, 0); invoke_gc_callback(tstate, "stop", generation, collected, uncollectable); assert(!_PyErr_Occurred(tstate)); return result; } static Py_ssize_t -collect_generations(PyThreadState *tstate) +gc_collect_generations(PyThreadState *tstate) { GCState *gcstate = &tstate->interp->gc; /* Find the oldest generation (highest numbered) where the count @@ -1455,7 +1456,7 @@ collect_generations(PyThreadState *tstate) if (i == NUM_GENERATIONS - 1 && gcstate->long_lived_pending < gcstate->long_lived_total / 4) continue; - n = collect_with_callback(tstate, i); + n = gc_collect_with_callback(tstate, i); break; } } @@ -1541,7 +1542,7 @@ gc_collect_impl(PyObject *module, int generation) } else { gcstate->collecting = 1; - n = collect_with_callback(tstate, generation); + n = gc_collect_with_callback(tstate, generation); gcstate->collecting = 0; } return n; @@ -2041,7 +2042,7 @@ PyInit_gc(void) return m; } -/* API to invoke gc.collect() from C */ +/* Public API to invoke gc.collect() from C */ Py_ssize_t PyGC_Collect(void) { @@ -2061,7 +2062,7 @@ PyGC_Collect(void) PyObject *exc, *value, *tb; gcstate->collecting = 1; _PyErr_Fetch(tstate, &exc, &value, &tb); - n = collect_with_callback(tstate, NUM_GENERATIONS - 1); + n = gc_collect_with_callback(tstate, NUM_GENERATIONS - 1); _PyErr_Restore(tstate, exc, value, tb); gcstate->collecting = 0; } @@ -2070,19 +2071,11 @@ PyGC_Collect(void) } Py_ssize_t -_PyGC_CollectIfEnabled(void) +_PyGC_CollectNoFail(PyThreadState *tstate) { - return PyGC_Collect(); -} - -Py_ssize_t -_PyGC_CollectNoFail(void) -{ - PyThreadState *tstate = _PyThreadState_GET(); assert(!_PyErr_Occurred(tstate)); GCState *gcstate = &tstate->interp->gc; - Py_ssize_t n; /* Ideally, this function is only called on interpreter shutdown, and therefore not recursively. Unfortunately, when there are daemon @@ -2091,13 +2084,13 @@ _PyGC_CollectNoFail(void) See http://bugs.python.org/issue8713#msg195178 for an example. */ if (gcstate->collecting) { - n = 0; - } - else { - gcstate->collecting = 1; - n = collect(tstate, NUM_GENERATIONS - 1, NULL, NULL, 1); - gcstate->collecting = 0; + return 0; } + + Py_ssize_t n; + gcstate->collecting = 1; + n = gc_collect_main(tstate, NUM_GENERATIONS - 1, NULL, NULL, 1); + gcstate->collecting = 0; return n; } @@ -2240,7 +2233,7 @@ _PyObject_GC_Alloc(int use_calloc, size_t basicsize) !_PyErr_Occurred(tstate)) { gcstate->collecting = 1; - collect_generations(tstate); + gc_collect_generations(tstate); gcstate->collecting = 0; } PyObject *op = FROM_GC(g); diff --git a/Python/import.c b/Python/import.c index b79bda0..8b9cc30 100644 --- a/Python/import.c +++ b/Python/import.c @@ -566,7 +566,7 @@ _PyImport_Cleanup(PyThreadState *tstate) } Py_XDECREF(dict); /* Collect references */ - _PyGC_CollectNoFail(); + _PyGC_CollectNoFail(tstate); /* Dump GC stats before it's too late, since it uses the warnings machinery. */ _PyGC_DumpShutdownStats(tstate); @@ -626,7 +626,7 @@ _PyImport_Cleanup(PyThreadState *tstate) Py_DECREF(modules); /* Once more */ - _PyGC_CollectNoFail(); + _PyGC_CollectNoFail(tstate); #undef CLEAR_MODULE #undef STORE_MODULE_WEAKREF diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 774a4f9..71834f6 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1293,7 +1293,7 @@ finalize_interp_clear(PyThreadState *tstate) PyInterpreterState_Clear(tstate->interp); /* Last explicit GC collection */ - _PyGC_CollectNoFail(); + _PyGC_CollectNoFail(tstate); /* Clear all loghooks */ /* Both _PySys_Audit function and users still need PyObject, such as tuple. @@ -1414,7 +1414,7 @@ Py_FinalizeEx(void) * XXX but I'm unclear on exactly how that one happens. In any case, * XXX I haven't seen a real-life report of either of these. */ - _PyGC_CollectIfEnabled(); + PyGC_Collect(); /* Destroy all modules */ _PyImport_Cleanup(tstate); -- cgit v0.12