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()
This commit is contained in:
Victor Stinner 2020-10-30 17:00:00 +01:00 committed by GitHub
parent 99608c733c
commit 8b3414818f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 25 additions and 34 deletions

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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);