Skip to content

Commit

Permalink
bpo-42208: Pass tstate to _PyGC_CollectNoFail() (GH-23038)
Browse files Browse the repository at this point in the history
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()
  • Loading branch information
vstinner authored and adorilson committed Mar 11, 2021
1 parent 10fd514 commit 995ba14
Show file tree
Hide file tree
Showing 5 changed files with 25 additions and 34 deletions.
4 changes: 0 additions & 4 deletions Include/cpython/objimpl.h
Expand Up @@ -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);

Expand Down
4 changes: 3 additions & 1 deletion Include/internal/pycore_gc.h
Expand Up @@ -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
Expand Down
43 changes: 18 additions & 25 deletions Modules/gcmodule.c
Expand Up @@ -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 */
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
{
Expand All @@ -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;
}
Expand All @@ -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
Expand All @@ -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;
}

Expand Down Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions Python/import.c
Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions Python/pylifecycle.c
Expand Up @@ -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.
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 995ba14

Please sign in to comment.