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:
parent
99608c733c
commit
8b3414818f
|
@ -79,10 +79,6 @@ PyAPI_FUNC(void) PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator);
|
||||||
PyAPI_FUNC(void) PyObject_SetArenaAllocator(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 */
|
/* Test if an object implements the garbage collector protocol */
|
||||||
PyAPI_FUNC(int) PyObject_IS_GC(PyObject *obj);
|
PyAPI_FUNC(int) PyObject_IS_GC(PyObject *obj);
|
||||||
|
|
||||||
|
|
|
@ -161,7 +161,9 @@ struct _gc_runtime_state {
|
||||||
Py_ssize_t long_lived_pending;
|
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
|
// Functions to clear types free lists
|
||||||
|
|
|
@ -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
|
/* This is the main function. Read this to understand how the
|
||||||
* collection process works. */
|
* collection process works. */
|
||||||
static Py_ssize_t
|
static Py_ssize_t
|
||||||
collect(PyThreadState *tstate, int generation,
|
gc_collect_main(PyThreadState *tstate, int generation,
|
||||||
Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable, int nofail)
|
Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable,
|
||||||
|
int nofail)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
Py_ssize_t m = 0; /* # objects collected */
|
Py_ssize_t m = 0; /* # objects collected */
|
||||||
|
@ -1395,19 +1396,19 @@ invoke_gc_callback(PyThreadState *tstate, const char *phase,
|
||||||
* progress callbacks.
|
* progress callbacks.
|
||||||
*/
|
*/
|
||||||
static Py_ssize_t
|
static Py_ssize_t
|
||||||
collect_with_callback(PyThreadState *tstate, int generation)
|
gc_collect_with_callback(PyThreadState *tstate, int generation)
|
||||||
{
|
{
|
||||||
assert(!_PyErr_Occurred(tstate));
|
assert(!_PyErr_Occurred(tstate));
|
||||||
Py_ssize_t result, collected, uncollectable;
|
Py_ssize_t result, collected, uncollectable;
|
||||||
invoke_gc_callback(tstate, "start", generation, 0, 0);
|
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);
|
invoke_gc_callback(tstate, "stop", generation, collected, uncollectable);
|
||||||
assert(!_PyErr_Occurred(tstate));
|
assert(!_PyErr_Occurred(tstate));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Py_ssize_t
|
static Py_ssize_t
|
||||||
collect_generations(PyThreadState *tstate)
|
gc_collect_generations(PyThreadState *tstate)
|
||||||
{
|
{
|
||||||
GCState *gcstate = &tstate->interp->gc;
|
GCState *gcstate = &tstate->interp->gc;
|
||||||
/* Find the oldest generation (highest numbered) where the count
|
/* Find the oldest generation (highest numbered) where the count
|
||||||
|
@ -1455,7 +1456,7 @@ collect_generations(PyThreadState *tstate)
|
||||||
if (i == NUM_GENERATIONS - 1
|
if (i == NUM_GENERATIONS - 1
|
||||||
&& gcstate->long_lived_pending < gcstate->long_lived_total / 4)
|
&& gcstate->long_lived_pending < gcstate->long_lived_total / 4)
|
||||||
continue;
|
continue;
|
||||||
n = collect_with_callback(tstate, i);
|
n = gc_collect_with_callback(tstate, i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1541,7 +1542,7 @@ gc_collect_impl(PyObject *module, int generation)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
gcstate->collecting = 1;
|
gcstate->collecting = 1;
|
||||||
n = collect_with_callback(tstate, generation);
|
n = gc_collect_with_callback(tstate, generation);
|
||||||
gcstate->collecting = 0;
|
gcstate->collecting = 0;
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
|
@ -2041,7 +2042,7 @@ PyInit_gc(void)
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* API to invoke gc.collect() from C */
|
/* Public API to invoke gc.collect() from C */
|
||||||
Py_ssize_t
|
Py_ssize_t
|
||||||
PyGC_Collect(void)
|
PyGC_Collect(void)
|
||||||
{
|
{
|
||||||
|
@ -2061,7 +2062,7 @@ PyGC_Collect(void)
|
||||||
PyObject *exc, *value, *tb;
|
PyObject *exc, *value, *tb;
|
||||||
gcstate->collecting = 1;
|
gcstate->collecting = 1;
|
||||||
_PyErr_Fetch(tstate, &exc, &value, &tb);
|
_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);
|
_PyErr_Restore(tstate, exc, value, tb);
|
||||||
gcstate->collecting = 0;
|
gcstate->collecting = 0;
|
||||||
}
|
}
|
||||||
|
@ -2070,19 +2071,11 @@ PyGC_Collect(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
Py_ssize_t
|
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));
|
assert(!_PyErr_Occurred(tstate));
|
||||||
|
|
||||||
GCState *gcstate = &tstate->interp->gc;
|
GCState *gcstate = &tstate->interp->gc;
|
||||||
Py_ssize_t n;
|
|
||||||
|
|
||||||
/* Ideally, this function is only called on interpreter shutdown,
|
/* Ideally, this function is only called on interpreter shutdown,
|
||||||
and therefore not recursively. Unfortunately, when there are daemon
|
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.
|
See http://bugs.python.org/issue8713#msg195178 for an example.
|
||||||
*/
|
*/
|
||||||
if (gcstate->collecting) {
|
if (gcstate->collecting) {
|
||||||
n = 0;
|
return 0;
|
||||||
}
|
|
||||||
else {
|
|
||||||
gcstate->collecting = 1;
|
|
||||||
n = collect(tstate, NUM_GENERATIONS - 1, NULL, NULL, 1);
|
|
||||||
gcstate->collecting = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Py_ssize_t n;
|
||||||
|
gcstate->collecting = 1;
|
||||||
|
n = gc_collect_main(tstate, NUM_GENERATIONS - 1, NULL, NULL, 1);
|
||||||
|
gcstate->collecting = 0;
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2240,7 +2233,7 @@ _PyObject_GC_Alloc(int use_calloc, size_t basicsize)
|
||||||
!_PyErr_Occurred(tstate))
|
!_PyErr_Occurred(tstate))
|
||||||
{
|
{
|
||||||
gcstate->collecting = 1;
|
gcstate->collecting = 1;
|
||||||
collect_generations(tstate);
|
gc_collect_generations(tstate);
|
||||||
gcstate->collecting = 0;
|
gcstate->collecting = 0;
|
||||||
}
|
}
|
||||||
PyObject *op = FROM_GC(g);
|
PyObject *op = FROM_GC(g);
|
||||||
|
|
|
@ -566,7 +566,7 @@ _PyImport_Cleanup(PyThreadState *tstate)
|
||||||
}
|
}
|
||||||
Py_XDECREF(dict);
|
Py_XDECREF(dict);
|
||||||
/* Collect references */
|
/* Collect references */
|
||||||
_PyGC_CollectNoFail();
|
_PyGC_CollectNoFail(tstate);
|
||||||
/* Dump GC stats before it's too late, since it uses the warnings
|
/* Dump GC stats before it's too late, since it uses the warnings
|
||||||
machinery. */
|
machinery. */
|
||||||
_PyGC_DumpShutdownStats(tstate);
|
_PyGC_DumpShutdownStats(tstate);
|
||||||
|
@ -626,7 +626,7 @@ _PyImport_Cleanup(PyThreadState *tstate)
|
||||||
Py_DECREF(modules);
|
Py_DECREF(modules);
|
||||||
|
|
||||||
/* Once more */
|
/* Once more */
|
||||||
_PyGC_CollectNoFail();
|
_PyGC_CollectNoFail(tstate);
|
||||||
|
|
||||||
#undef CLEAR_MODULE
|
#undef CLEAR_MODULE
|
||||||
#undef STORE_MODULE_WEAKREF
|
#undef STORE_MODULE_WEAKREF
|
||||||
|
|
|
@ -1293,7 +1293,7 @@ finalize_interp_clear(PyThreadState *tstate)
|
||||||
PyInterpreterState_Clear(tstate->interp);
|
PyInterpreterState_Clear(tstate->interp);
|
||||||
|
|
||||||
/* Last explicit GC collection */
|
/* Last explicit GC collection */
|
||||||
_PyGC_CollectNoFail();
|
_PyGC_CollectNoFail(tstate);
|
||||||
|
|
||||||
/* Clear all loghooks */
|
/* Clear all loghooks */
|
||||||
/* Both _PySys_Audit function and users still need PyObject, such as tuple.
|
/* 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 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.
|
* XXX I haven't seen a real-life report of either of these.
|
||||||
*/
|
*/
|
||||||
_PyGC_CollectIfEnabled();
|
PyGC_Collect();
|
||||||
|
|
||||||
/* Destroy all modules */
|
/* Destroy all modules */
|
||||||
_PyImport_Cleanup(tstate);
|
_PyImport_Cleanup(tstate);
|
||||||
|
|
Loading…
Reference in New Issue