Skip to content
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

bpo-36854: Move _PyRuntimeState.gc to PyInterpreterState #17287

Merged
merged 1 commit into from
Nov 20, 2019
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
2 changes: 1 addition & 1 deletion Include/internal/pycore_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ static inline void _PyObject_GC_TRACK_impl(const char *filename, int lineno,
filename, lineno, "_PyObject_GC_TRACK");

PyThreadState *tstate = _PyThreadState_GET();
PyGC_Head *generation0 = tstate->interp->runtime->gc.generation0;
PyGC_Head *generation0 = tstate->interp->gc.generation0;
PyGC_Head *last = (PyGC_Head*)(generation0->_gc_prev);
_PyGCHead_SET_NEXT(last, gc);
_PyGCHead_SET_PREV(gc, last);
Expand Down
2 changes: 1 addition & 1 deletion Include/internal/pycore_pymem.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ struct _gc_runtime_state {
Py_ssize_t long_lived_pending;
};

PyAPI_FUNC(void) _PyGC_InitializeRuntime(struct _gc_runtime_state *);
PyAPI_FUNC(void) _PyGC_InitState(struct _gc_runtime_state *);


/* Set the memory allocator of the specified domain to the default.
Expand Down
7 changes: 3 additions & 4 deletions Include/internal/pycore_pystate.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ struct _is {

int finalizing;

struct _gc_runtime_state gc;

PyObject *modules;
PyObject *modules_by_index;
PyObject *sysdict;
Expand Down Expand Up @@ -130,9 +132,7 @@ struct _is {
struct _warnings_runtime_state warnings;

PyObject *audit_hooks;
/*
* See bpo-36876: miscellaneous ad hoc statics have been moved here.
*/

struct {
struct {
int level;
Expand Down Expand Up @@ -239,7 +239,6 @@ typedef struct pyruntimestate {
void (*exitfuncs[NEXITFUNCS])(void);
int nexitfuncs;

struct _gc_runtime_state gc;
struct _ceval_runtime_state ceval;
struct _gilstate_runtime_state gilstate;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
The garbage collector state becomes per interpreter
(``PyInterpreterState.gc``), rather than being global
(``_PyRuntimeState.gc``).
72 changes: 38 additions & 34 deletions Modules/gcmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ static PyObject *gc_str = NULL;
#define GEN_HEAD(gcstate, n) (&(gcstate)->generations[n].head)

void
_PyGC_InitializeRuntime(GCState *gcstate)
_PyGC_InitState(GCState *gcstate)
{
gcstate->enabled = 1; /* automatic collection enabled? */

Expand All @@ -159,7 +159,7 @@ _PyGC_InitializeRuntime(GCState *gcstate)
PyStatus
_PyGC_Init(PyThreadState *tstate)
{
GCState *gcstate = &tstate->interp->runtime->gc;
GCState *gcstate = &tstate->interp->gc;
if (gcstate->garbage == NULL) {
gcstate->garbage = PyList_New(0);
if (gcstate->garbage == NULL) {
Expand Down Expand Up @@ -1159,7 +1159,7 @@ collect(PyThreadState *tstate, int generation,
PyGC_Head finalizers; /* objects with, & reachable from, __del__ */
PyGC_Head *gc;
_PyTime_t t1 = 0; /* initialize to prevent a compiler warning */
GCState *gcstate = &tstate->interp->runtime->gc;
GCState *gcstate = &tstate->interp->gc;

if (gcstate->debug & DEBUG_STATS) {
PySys_WriteStderr("gc: collecting generation %d...\n", generation);
Expand Down Expand Up @@ -1324,7 +1324,7 @@ invoke_gc_callback(PyThreadState *tstate, const char *phase,
assert(!_PyErr_Occurred(tstate));

/* we may get called very early */
GCState *gcstate = &tstate->interp->runtime->gc;
GCState *gcstate = &tstate->interp->gc;
if (gcstate->callbacks == NULL) {
return;
}
Expand Down Expand Up @@ -1376,7 +1376,7 @@ collect_with_callback(PyThreadState *tstate, int generation)
static Py_ssize_t
collect_generations(PyThreadState *tstate)
{
GCState *gcstate = &tstate->interp->runtime->gc;
GCState *gcstate = &tstate->interp->gc;
/* Find the oldest generation (highest numbered) where the count
* exceeds the threshold. Objects in the that generation and
* generations younger than it will be collected. */
Expand Down Expand Up @@ -1410,7 +1410,7 @@ gc_enable_impl(PyObject *module)
/*[clinic end generated code: output=45a427e9dce9155c input=81ac4940ca579707]*/
{
PyThreadState *tstate = _PyThreadState_GET();
GCState *gcstate = &tstate->interp->runtime->gc;
GCState *gcstate = &tstate->interp->gc;
gcstate->enabled = 1;
Py_RETURN_NONE;
}
Expand All @@ -1426,7 +1426,7 @@ gc_disable_impl(PyObject *module)
/*[clinic end generated code: output=97d1030f7aa9d279 input=8c2e5a14e800d83b]*/
{
PyThreadState *tstate = _PyThreadState_GET();
GCState *gcstate = &tstate->interp->runtime->gc;
GCState *gcstate = &tstate->interp->gc;
gcstate->enabled = 0;
Py_RETURN_NONE;
}
Expand All @@ -1442,7 +1442,7 @@ gc_isenabled_impl(PyObject *module)
/*[clinic end generated code: output=1874298331c49130 input=30005e0422373b31]*/
{
PyThreadState *tstate = _PyThreadState_GET();
GCState *gcstate = &tstate->interp->runtime->gc;
GCState *gcstate = &tstate->interp->gc;
return gcstate->enabled;
}

Expand Down Expand Up @@ -1471,7 +1471,7 @@ gc_collect_impl(PyObject *module, int generation)
return -1;
}

GCState *gcstate = &tstate->interp->runtime->gc;
GCState *gcstate = &tstate->interp->gc;
Py_ssize_t n;
if (gcstate->collecting) {
/* already collecting, don't do anything */
Expand Down Expand Up @@ -1508,7 +1508,7 @@ gc_set_debug_impl(PyObject *module, int flags)
/*[clinic end generated code: output=7c8366575486b228 input=5e5ce15e84fbed15]*/
{
PyThreadState *tstate = _PyThreadState_GET();
GCState *gcstate = &tstate->interp->runtime->gc;
GCState *gcstate = &tstate->interp->gc;
gcstate->debug = flags;
Py_RETURN_NONE;
}
Expand All @@ -1524,7 +1524,7 @@ gc_get_debug_impl(PyObject *module)
/*[clinic end generated code: output=91242f3506cd1e50 input=91a101e1c3b98366]*/
{
PyThreadState *tstate = _PyThreadState_GET();
GCState *gcstate = &tstate->interp->runtime->gc;
GCState *gcstate = &tstate->interp->gc;
return gcstate->debug;
}

Expand All @@ -1538,7 +1538,7 @@ static PyObject *
gc_set_threshold(PyObject *self, PyObject *args)
{
PyThreadState *tstate = _PyThreadState_GET();
GCState *gcstate = &tstate->interp->runtime->gc;
GCState *gcstate = &tstate->interp->gc;
if (!PyArg_ParseTuple(args, "i|ii:set_threshold",
&gcstate->generations[0].threshold,
&gcstate->generations[1].threshold,
Expand All @@ -1562,7 +1562,7 @@ gc_get_threshold_impl(PyObject *module)
/*[clinic end generated code: output=7902bc9f41ecbbd8 input=286d79918034d6e6]*/
{
PyThreadState *tstate = _PyThreadState_GET();
GCState *gcstate = &tstate->interp->runtime->gc;
GCState *gcstate = &tstate->interp->gc;
return Py_BuildValue("(iii)",
gcstate->generations[0].threshold,
gcstate->generations[1].threshold,
Expand All @@ -1580,7 +1580,7 @@ gc_get_count_impl(PyObject *module)
/*[clinic end generated code: output=354012e67b16398f input=a392794a08251751]*/
{
PyThreadState *tstate = _PyThreadState_GET();
GCState *gcstate = &tstate->interp->runtime->gc;
GCState *gcstate = &tstate->interp->gc;
return Py_BuildValue("(iii)",
gcstate->generations[0].count,
gcstate->generations[1].count,
Expand Down Expand Up @@ -1630,7 +1630,7 @@ gc_get_referrers(PyObject *self, PyObject *args)
return NULL;
}

GCState *gcstate = &tstate->interp->runtime->gc;
GCState *gcstate = &tstate->interp->gc;
for (i = 0; i < NUM_GENERATIONS; i++) {
if (!(gc_referrers_for(args, GEN_HEAD(gcstate, i), result))) {
Py_DECREF(result);
Expand Down Expand Up @@ -1695,7 +1695,7 @@ gc_get_objects_impl(PyObject *module, Py_ssize_t generation)
PyThreadState *tstate = _PyThreadState_GET();
int i;
PyObject* result;
GCState *gcstate = &tstate->interp->runtime->gc;
GCState *gcstate = &tstate->interp->gc;

result = PyList_New(0);
if (result == NULL) {
Expand Down Expand Up @@ -1754,7 +1754,7 @@ gc_get_stats_impl(PyObject *module)

/* To get consistent values despite allocations while constructing
the result list, we use a snapshot of the running stats. */
GCState *gcstate = &tstate->interp->runtime->gc;
GCState *gcstate = &tstate->interp->gc;
for (i = 0; i < NUM_GENERATIONS; i++) {
stats[i] = gcstate->generation_stats[i];
}
Expand Down Expand Up @@ -1827,7 +1827,7 @@ gc_freeze_impl(PyObject *module)
/*[clinic end generated code: output=502159d9cdc4c139 input=b602b16ac5febbe5]*/
{
PyThreadState *tstate = _PyThreadState_GET();
GCState *gcstate = &tstate->interp->runtime->gc;
GCState *gcstate = &tstate->interp->gc;
for (int i = 0; i < NUM_GENERATIONS; ++i) {
gc_list_merge(GEN_HEAD(gcstate, i), &gcstate->permanent_generation.head);
gcstate->generations[i].count = 0;
Expand All @@ -1848,7 +1848,7 @@ gc_unfreeze_impl(PyObject *module)
/*[clinic end generated code: output=1c15f2043b25e169 input=2dd52b170f4cef6c]*/
{
PyThreadState *tstate = _PyThreadState_GET();
GCState *gcstate = &tstate->interp->runtime->gc;
GCState *gcstate = &tstate->interp->gc;
gc_list_merge(&gcstate->permanent_generation.head,
GEN_HEAD(gcstate, NUM_GENERATIONS-1));
Py_RETURN_NONE;
Expand All @@ -1865,7 +1865,7 @@ gc_get_freeze_count_impl(PyObject *module)
/*[clinic end generated code: output=61cbd9f43aa032e1 input=45ffbc65cfe2a6ed]*/
{
PyThreadState *tstate = _PyThreadState_GET();
GCState *gcstate = &tstate->interp->runtime->gc;
GCState *gcstate = &tstate->interp->gc;
return gc_list_size(&gcstate->permanent_generation.head);
}

Expand Down Expand Up @@ -1929,34 +1929,38 @@ static struct PyModuleDef gcmodule = {
PyMODINIT_FUNC
PyInit_gc(void)
{
PyObject *m;
PyThreadState *tstate = _PyThreadState_GET();
GCState *gcstate = &tstate->interp->gc;

m = PyModule_Create(&gcmodule);
PyObject *m = PyModule_Create(&gcmodule);

if (m == NULL) {
return NULL;
}

GCState *gcstate = &_PyRuntime.gc;
if (gcstate->garbage == NULL) {
gcstate->garbage = PyList_New(0);
if (gcstate->garbage == NULL)
if (gcstate->garbage == NULL) {
return NULL;
}
}
Py_INCREF(gcstate->garbage);
if (PyModule_AddObject(m, "garbage", gcstate->garbage) < 0)
if (PyModule_AddObject(m, "garbage", gcstate->garbage) < 0) {
return NULL;
}

if (gcstate->callbacks == NULL) {
gcstate->callbacks = PyList_New(0);
if (gcstate->callbacks == NULL)
if (gcstate->callbacks == NULL) {
return NULL;
}
}
Py_INCREF(gcstate->callbacks);
if (PyModule_AddObject(m, "callbacks", gcstate->callbacks) < 0)
if (PyModule_AddObject(m, "callbacks", gcstate->callbacks) < 0) {
return NULL;
}

#define ADD_INT(NAME) if (PyModule_AddIntConstant(m, #NAME, NAME) < 0) return NULL
#define ADD_INT(NAME) if (PyModule_AddIntConstant(m, #NAME, NAME) < 0) { return NULL; }
ADD_INT(DEBUG_STATS);
ADD_INT(DEBUG_COLLECTABLE);
ADD_INT(DEBUG_UNCOLLECTABLE);
Expand All @@ -1971,7 +1975,7 @@ Py_ssize_t
PyGC_Collect(void)
{
PyThreadState *tstate = _PyThreadState_GET();
GCState *gcstate = &tstate->interp->runtime->gc;
GCState *gcstate = &tstate->interp->gc;

if (!gcstate->enabled) {
return 0;
Expand Down Expand Up @@ -2006,7 +2010,7 @@ _PyGC_CollectNoFail(void)
PyThreadState *tstate = _PyThreadState_GET();
assert(!_PyErr_Occurred(tstate));

GCState *gcstate = &tstate->interp->runtime->gc;
GCState *gcstate = &tstate->interp->gc;
Py_ssize_t n;

/* Ideally, this function is only called on interpreter shutdown,
Expand All @@ -2029,7 +2033,7 @@ _PyGC_CollectNoFail(void)
void
_PyGC_DumpShutdownStats(PyThreadState *tstate)
{
GCState *gcstate = &tstate->interp->runtime->gc;
GCState *gcstate = &tstate->interp->gc;
if (!(gcstate->debug & DEBUG_SAVEALL)
&& gcstate->garbage != NULL && PyList_GET_SIZE(gcstate->garbage) > 0) {
const char *message;
Expand Down Expand Up @@ -2066,7 +2070,7 @@ _PyGC_DumpShutdownStats(PyThreadState *tstate)
void
_PyGC_Fini(PyThreadState *tstate)
{
GCState *gcstate = &tstate->interp->runtime->gc;
GCState *gcstate = &tstate->interp->gc;
Py_CLEAR(gcstate->garbage);
Py_CLEAR(gcstate->callbacks);
}
Expand Down Expand Up @@ -2131,7 +2135,7 @@ static PyObject *
_PyObject_GC_Alloc(int use_calloc, size_t basicsize)
{
PyThreadState *tstate = _PyThreadState_GET();
GCState *gcstate = &tstate->interp->runtime->gc;
GCState *gcstate = &tstate->interp->gc;
if (basicsize > PY_SSIZE_T_MAX - sizeof(PyGC_Head)) {
return _PyErr_NoMemory(tstate);
}
Expand Down Expand Up @@ -2230,7 +2234,7 @@ PyObject_GC_Del(void *op)
gc_list_remove(g);
}
PyThreadState *tstate = _PyThreadState_GET();
GCState *gcstate = &tstate->interp->runtime->gc;
GCState *gcstate = &tstate->interp->gc;
if (gcstate->generations[0].count > 0) {
gcstate->generations[0].count--;
}
Expand Down
20 changes: 13 additions & 7 deletions Objects/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -2131,11 +2131,14 @@ Py_ReprLeave(PyObject *obj)
void
_PyTrash_deposit_object(PyObject *op)
{
PyThreadState *tstate = _PyThreadState_GET();
struct _gc_runtime_state *gcstate = &tstate->interp->gc;

_PyObject_ASSERT(op, PyObject_IS_GC(op));
_PyObject_ASSERT(op, !_PyObject_GC_IS_TRACKED(op));
_PyObject_ASSERT(op, op->ob_refcnt == 0);
_PyGCHead_SET_PREV(_Py_AS_GC(op), _PyRuntime.gc.trash_delete_later);
_PyRuntime.gc.trash_delete_later = op;
_PyGCHead_SET_PREV(_Py_AS_GC(op), gcstate->trash_delete_later);
gcstate->trash_delete_later = op;
}

/* The equivalent API, using per-thread state recursion info */
Expand All @@ -2156,11 +2159,14 @@ _PyTrash_thread_deposit_object(PyObject *op)
void
_PyTrash_destroy_chain(void)
{
while (_PyRuntime.gc.trash_delete_later) {
PyObject *op = _PyRuntime.gc.trash_delete_later;
PyThreadState *tstate = _PyThreadState_GET();
struct _gc_runtime_state *gcstate = &tstate->interp->gc;

while (gcstate->trash_delete_later) {
PyObject *op = gcstate->trash_delete_later;
destructor dealloc = Py_TYPE(op)->tp_dealloc;

_PyRuntime.gc.trash_delete_later =
gcstate->trash_delete_later =
(PyObject*) _PyGCHead_PREV(_Py_AS_GC(op));

/* Call the deallocator directly. This used to try to
Expand All @@ -2170,9 +2176,9 @@ _PyTrash_destroy_chain(void)
* up distorting allocation statistics.
*/
_PyObject_ASSERT(op, op->ob_refcnt == 0);
++_PyRuntime.gc.trash_delete_nesting;
++gcstate->trash_delete_nesting;
(*dealloc)(op);
--_PyRuntime.gc.trash_delete_nesting;
--gcstate->trash_delete_nesting;
}
}

Expand Down
3 changes: 2 additions & 1 deletion Python/pylifecycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -1213,8 +1213,9 @@ finalize_interp_clear(PyThreadState *tstate, int is_main_interp)
PyGrammar_RemoveAccelerators(&_PyParser_Grammar);

_PyExc_Fini();
_PyGC_Fini(tstate);
}

_PyGC_Fini(tstate);
}


Expand Down
Loading