Skip to content

bpo-42208: Pass tstate to _PyGC_CollectNoFail() #23038

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions Include/cpython/objimpl.h
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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