Skip to content

Commit 7247407

Browse files
authored
bpo-36854: Move _PyRuntimeState.gc to PyInterpreterState (GH-17287)
* Rename _PyGC_InitializeRuntime() to _PyGC_InitState() * finalize_interp_clear() now also calls _PyGC_Fini() in subinterpreters (clear the GC state).
1 parent 488d02a commit 7247407

File tree

8 files changed

+62
-49
lines changed

8 files changed

+62
-49
lines changed

Include/internal/pycore_object.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ static inline void _PyObject_GC_TRACK_impl(const char *filename, int lineno,
3838
filename, lineno, "_PyObject_GC_TRACK");
3939

4040
PyThreadState *tstate = _PyThreadState_GET();
41-
PyGC_Head *generation0 = tstate->interp->runtime->gc.generation0;
41+
PyGC_Head *generation0 = tstate->interp->gc.generation0;
4242
PyGC_Head *last = (PyGC_Head*)(generation0->_gc_prev);
4343
_PyGCHead_SET_NEXT(last, gc);
4444
_PyGCHead_SET_PREV(gc, last);

Include/internal/pycore_pymem.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ struct _gc_runtime_state {
144144
Py_ssize_t long_lived_pending;
145145
};
146146

147-
PyAPI_FUNC(void) _PyGC_InitializeRuntime(struct _gc_runtime_state *);
147+
PyAPI_FUNC(void) _PyGC_InitState(struct _gc_runtime_state *);
148148

149149

150150
/* Set the memory allocator of the specified domain to the default.

Include/internal/pycore_pystate.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ struct _is {
7474

7575
int finalizing;
7676

77+
struct _gc_runtime_state gc;
78+
7779
PyObject *modules;
7880
PyObject *modules_by_index;
7981
PyObject *sysdict;
@@ -130,9 +132,7 @@ struct _is {
130132
struct _warnings_runtime_state warnings;
131133

132134
PyObject *audit_hooks;
133-
/*
134-
* See bpo-36876: miscellaneous ad hoc statics have been moved here.
135-
*/
135+
136136
struct {
137137
struct {
138138
int level;
@@ -239,7 +239,6 @@ typedef struct pyruntimestate {
239239
void (*exitfuncs[NEXITFUNCS])(void);
240240
int nexitfuncs;
241241

242-
struct _gc_runtime_state gc;
243242
struct _ceval_runtime_state ceval;
244243
struct _gilstate_runtime_state gilstate;
245244

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
The garbage collector state becomes per interpreter
2+
(``PyInterpreterState.gc``), rather than being global
3+
(``_PyRuntimeState.gc``).

Modules/gcmodule.c

Lines changed: 38 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ static PyObject *gc_str = NULL;
133133
#define GEN_HEAD(gcstate, n) (&(gcstate)->generations[n].head)
134134

135135
void
136-
_PyGC_InitializeRuntime(GCState *gcstate)
136+
_PyGC_InitState(GCState *gcstate)
137137
{
138138
gcstate->enabled = 1; /* automatic collection enabled? */
139139

@@ -159,7 +159,7 @@ _PyGC_InitializeRuntime(GCState *gcstate)
159159
PyStatus
160160
_PyGC_Init(PyThreadState *tstate)
161161
{
162-
GCState *gcstate = &tstate->interp->runtime->gc;
162+
GCState *gcstate = &tstate->interp->gc;
163163
if (gcstate->garbage == NULL) {
164164
gcstate->garbage = PyList_New(0);
165165
if (gcstate->garbage == NULL) {
@@ -1159,7 +1159,7 @@ collect(PyThreadState *tstate, int generation,
11591159
PyGC_Head finalizers; /* objects with, & reachable from, __del__ */
11601160
PyGC_Head *gc;
11611161
_PyTime_t t1 = 0; /* initialize to prevent a compiler warning */
1162-
GCState *gcstate = &tstate->interp->runtime->gc;
1162+
GCState *gcstate = &tstate->interp->gc;
11631163

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

13261326
/* we may get called very early */
1327-
GCState *gcstate = &tstate->interp->runtime->gc;
1327+
GCState *gcstate = &tstate->interp->gc;
13281328
if (gcstate->callbacks == NULL) {
13291329
return;
13301330
}
@@ -1376,7 +1376,7 @@ collect_with_callback(PyThreadState *tstate, int generation)
13761376
static Py_ssize_t
13771377
collect_generations(PyThreadState *tstate)
13781378
{
1379-
GCState *gcstate = &tstate->interp->runtime->gc;
1379+
GCState *gcstate = &tstate->interp->gc;
13801380
/* Find the oldest generation (highest numbered) where the count
13811381
* exceeds the threshold. Objects in the that generation and
13821382
* generations younger than it will be collected. */
@@ -1410,7 +1410,7 @@ gc_enable_impl(PyObject *module)
14101410
/*[clinic end generated code: output=45a427e9dce9155c input=81ac4940ca579707]*/
14111411
{
14121412
PyThreadState *tstate = _PyThreadState_GET();
1413-
GCState *gcstate = &tstate->interp->runtime->gc;
1413+
GCState *gcstate = &tstate->interp->gc;
14141414
gcstate->enabled = 1;
14151415
Py_RETURN_NONE;
14161416
}
@@ -1426,7 +1426,7 @@ gc_disable_impl(PyObject *module)
14261426
/*[clinic end generated code: output=97d1030f7aa9d279 input=8c2e5a14e800d83b]*/
14271427
{
14281428
PyThreadState *tstate = _PyThreadState_GET();
1429-
GCState *gcstate = &tstate->interp->runtime->gc;
1429+
GCState *gcstate = &tstate->interp->gc;
14301430
gcstate->enabled = 0;
14311431
Py_RETURN_NONE;
14321432
}
@@ -1442,7 +1442,7 @@ gc_isenabled_impl(PyObject *module)
14421442
/*[clinic end generated code: output=1874298331c49130 input=30005e0422373b31]*/
14431443
{
14441444
PyThreadState *tstate = _PyThreadState_GET();
1445-
GCState *gcstate = &tstate->interp->runtime->gc;
1445+
GCState *gcstate = &tstate->interp->gc;
14461446
return gcstate->enabled;
14471447
}
14481448

@@ -1471,7 +1471,7 @@ gc_collect_impl(PyObject *module, int generation)
14711471
return -1;
14721472
}
14731473

1474-
GCState *gcstate = &tstate->interp->runtime->gc;
1474+
GCState *gcstate = &tstate->interp->gc;
14751475
Py_ssize_t n;
14761476
if (gcstate->collecting) {
14771477
/* already collecting, don't do anything */
@@ -1508,7 +1508,7 @@ gc_set_debug_impl(PyObject *module, int flags)
15081508
/*[clinic end generated code: output=7c8366575486b228 input=5e5ce15e84fbed15]*/
15091509
{
15101510
PyThreadState *tstate = _PyThreadState_GET();
1511-
GCState *gcstate = &tstate->interp->runtime->gc;
1511+
GCState *gcstate = &tstate->interp->gc;
15121512
gcstate->debug = flags;
15131513
Py_RETURN_NONE;
15141514
}
@@ -1524,7 +1524,7 @@ gc_get_debug_impl(PyObject *module)
15241524
/*[clinic end generated code: output=91242f3506cd1e50 input=91a101e1c3b98366]*/
15251525
{
15261526
PyThreadState *tstate = _PyThreadState_GET();
1527-
GCState *gcstate = &tstate->interp->runtime->gc;
1527+
GCState *gcstate = &tstate->interp->gc;
15281528
return gcstate->debug;
15291529
}
15301530

@@ -1538,7 +1538,7 @@ static PyObject *
15381538
gc_set_threshold(PyObject *self, PyObject *args)
15391539
{
15401540
PyThreadState *tstate = _PyThreadState_GET();
1541-
GCState *gcstate = &tstate->interp->runtime->gc;
1541+
GCState *gcstate = &tstate->interp->gc;
15421542
if (!PyArg_ParseTuple(args, "i|ii:set_threshold",
15431543
&gcstate->generations[0].threshold,
15441544
&gcstate->generations[1].threshold,
@@ -1562,7 +1562,7 @@ gc_get_threshold_impl(PyObject *module)
15621562
/*[clinic end generated code: output=7902bc9f41ecbbd8 input=286d79918034d6e6]*/
15631563
{
15641564
PyThreadState *tstate = _PyThreadState_GET();
1565-
GCState *gcstate = &tstate->interp->runtime->gc;
1565+
GCState *gcstate = &tstate->interp->gc;
15661566
return Py_BuildValue("(iii)",
15671567
gcstate->generations[0].threshold,
15681568
gcstate->generations[1].threshold,
@@ -1580,7 +1580,7 @@ gc_get_count_impl(PyObject *module)
15801580
/*[clinic end generated code: output=354012e67b16398f input=a392794a08251751]*/
15811581
{
15821582
PyThreadState *tstate = _PyThreadState_GET();
1583-
GCState *gcstate = &tstate->interp->runtime->gc;
1583+
GCState *gcstate = &tstate->interp->gc;
15841584
return Py_BuildValue("(iii)",
15851585
gcstate->generations[0].count,
15861586
gcstate->generations[1].count,
@@ -1630,7 +1630,7 @@ gc_get_referrers(PyObject *self, PyObject *args)
16301630
return NULL;
16311631
}
16321632

1633-
GCState *gcstate = &tstate->interp->runtime->gc;
1633+
GCState *gcstate = &tstate->interp->gc;
16341634
for (i = 0; i < NUM_GENERATIONS; i++) {
16351635
if (!(gc_referrers_for(args, GEN_HEAD(gcstate, i), result))) {
16361636
Py_DECREF(result);
@@ -1695,7 +1695,7 @@ gc_get_objects_impl(PyObject *module, Py_ssize_t generation)
16951695
PyThreadState *tstate = _PyThreadState_GET();
16961696
int i;
16971697
PyObject* result;
1698-
GCState *gcstate = &tstate->interp->runtime->gc;
1698+
GCState *gcstate = &tstate->interp->gc;
16991699

17001700
result = PyList_New(0);
17011701
if (result == NULL) {
@@ -1754,7 +1754,7 @@ gc_get_stats_impl(PyObject *module)
17541754

17551755
/* To get consistent values despite allocations while constructing
17561756
the result list, we use a snapshot of the running stats. */
1757-
GCState *gcstate = &tstate->interp->runtime->gc;
1757+
GCState *gcstate = &tstate->interp->gc;
17581758
for (i = 0; i < NUM_GENERATIONS; i++) {
17591759
stats[i] = gcstate->generation_stats[i];
17601760
}
@@ -1827,7 +1827,7 @@ gc_freeze_impl(PyObject *module)
18271827
/*[clinic end generated code: output=502159d9cdc4c139 input=b602b16ac5febbe5]*/
18281828
{
18291829
PyThreadState *tstate = _PyThreadState_GET();
1830-
GCState *gcstate = &tstate->interp->runtime->gc;
1830+
GCState *gcstate = &tstate->interp->gc;
18311831
for (int i = 0; i < NUM_GENERATIONS; ++i) {
18321832
gc_list_merge(GEN_HEAD(gcstate, i), &gcstate->permanent_generation.head);
18331833
gcstate->generations[i].count = 0;
@@ -1848,7 +1848,7 @@ gc_unfreeze_impl(PyObject *module)
18481848
/*[clinic end generated code: output=1c15f2043b25e169 input=2dd52b170f4cef6c]*/
18491849
{
18501850
PyThreadState *tstate = _PyThreadState_GET();
1851-
GCState *gcstate = &tstate->interp->runtime->gc;
1851+
GCState *gcstate = &tstate->interp->gc;
18521852
gc_list_merge(&gcstate->permanent_generation.head,
18531853
GEN_HEAD(gcstate, NUM_GENERATIONS-1));
18541854
Py_RETURN_NONE;
@@ -1865,7 +1865,7 @@ gc_get_freeze_count_impl(PyObject *module)
18651865
/*[clinic end generated code: output=61cbd9f43aa032e1 input=45ffbc65cfe2a6ed]*/
18661866
{
18671867
PyThreadState *tstate = _PyThreadState_GET();
1868-
GCState *gcstate = &tstate->interp->runtime->gc;
1868+
GCState *gcstate = &tstate->interp->gc;
18691869
return gc_list_size(&gcstate->permanent_generation.head);
18701870
}
18711871

@@ -1929,34 +1929,38 @@ static struct PyModuleDef gcmodule = {
19291929
PyMODINIT_FUNC
19301930
PyInit_gc(void)
19311931
{
1932-
PyObject *m;
1932+
PyThreadState *tstate = _PyThreadState_GET();
1933+
GCState *gcstate = &tstate->interp->gc;
19331934

1934-
m = PyModule_Create(&gcmodule);
1935+
PyObject *m = PyModule_Create(&gcmodule);
19351936

19361937
if (m == NULL) {
19371938
return NULL;
19381939
}
19391940

1940-
GCState *gcstate = &_PyRuntime.gc;
19411941
if (gcstate->garbage == NULL) {
19421942
gcstate->garbage = PyList_New(0);
1943-
if (gcstate->garbage == NULL)
1943+
if (gcstate->garbage == NULL) {
19441944
return NULL;
1945+
}
19451946
}
19461947
Py_INCREF(gcstate->garbage);
1947-
if (PyModule_AddObject(m, "garbage", gcstate->garbage) < 0)
1948+
if (PyModule_AddObject(m, "garbage", gcstate->garbage) < 0) {
19481949
return NULL;
1950+
}
19491951

19501952
if (gcstate->callbacks == NULL) {
19511953
gcstate->callbacks = PyList_New(0);
1952-
if (gcstate->callbacks == NULL)
1954+
if (gcstate->callbacks == NULL) {
19531955
return NULL;
1956+
}
19541957
}
19551958
Py_INCREF(gcstate->callbacks);
1956-
if (PyModule_AddObject(m, "callbacks", gcstate->callbacks) < 0)
1959+
if (PyModule_AddObject(m, "callbacks", gcstate->callbacks) < 0) {
19571960
return NULL;
1961+
}
19581962

1959-
#define ADD_INT(NAME) if (PyModule_AddIntConstant(m, #NAME, NAME) < 0) return NULL
1963+
#define ADD_INT(NAME) if (PyModule_AddIntConstant(m, #NAME, NAME) < 0) { return NULL; }
19601964
ADD_INT(DEBUG_STATS);
19611965
ADD_INT(DEBUG_COLLECTABLE);
19621966
ADD_INT(DEBUG_UNCOLLECTABLE);
@@ -1971,7 +1975,7 @@ Py_ssize_t
19711975
PyGC_Collect(void)
19721976
{
19731977
PyThreadState *tstate = _PyThreadState_GET();
1974-
GCState *gcstate = &tstate->interp->runtime->gc;
1978+
GCState *gcstate = &tstate->interp->gc;
19751979

19761980
if (!gcstate->enabled) {
19771981
return 0;
@@ -2006,7 +2010,7 @@ _PyGC_CollectNoFail(void)
20062010
PyThreadState *tstate = _PyThreadState_GET();
20072011
assert(!_PyErr_Occurred(tstate));
20082012

2009-
GCState *gcstate = &tstate->interp->runtime->gc;
2013+
GCState *gcstate = &tstate->interp->gc;
20102014
Py_ssize_t n;
20112015

20122016
/* Ideally, this function is only called on interpreter shutdown,
@@ -2029,7 +2033,7 @@ _PyGC_CollectNoFail(void)
20292033
void
20302034
_PyGC_DumpShutdownStats(PyThreadState *tstate)
20312035
{
2032-
GCState *gcstate = &tstate->interp->runtime->gc;
2036+
GCState *gcstate = &tstate->interp->gc;
20332037
if (!(gcstate->debug & DEBUG_SAVEALL)
20342038
&& gcstate->garbage != NULL && PyList_GET_SIZE(gcstate->garbage) > 0) {
20352039
const char *message;
@@ -2066,7 +2070,7 @@ _PyGC_DumpShutdownStats(PyThreadState *tstate)
20662070
void
20672071
_PyGC_Fini(PyThreadState *tstate)
20682072
{
2069-
GCState *gcstate = &tstate->interp->runtime->gc;
2073+
GCState *gcstate = &tstate->interp->gc;
20702074
Py_CLEAR(gcstate->garbage);
20712075
Py_CLEAR(gcstate->callbacks);
20722076
}
@@ -2131,7 +2135,7 @@ static PyObject *
21312135
_PyObject_GC_Alloc(int use_calloc, size_t basicsize)
21322136
{
21332137
PyThreadState *tstate = _PyThreadState_GET();
2134-
GCState *gcstate = &tstate->interp->runtime->gc;
2138+
GCState *gcstate = &tstate->interp->gc;
21352139
if (basicsize > PY_SSIZE_T_MAX - sizeof(PyGC_Head)) {
21362140
return _PyErr_NoMemory(tstate);
21372141
}
@@ -2230,7 +2234,7 @@ PyObject_GC_Del(void *op)
22302234
gc_list_remove(g);
22312235
}
22322236
PyThreadState *tstate = _PyThreadState_GET();
2233-
GCState *gcstate = &tstate->interp->runtime->gc;
2237+
GCState *gcstate = &tstate->interp->gc;
22342238
if (gcstate->generations[0].count > 0) {
22352239
gcstate->generations[0].count--;
22362240
}

Objects/object.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2131,11 +2131,14 @@ Py_ReprLeave(PyObject *obj)
21312131
void
21322132
_PyTrash_deposit_object(PyObject *op)
21332133
{
2134+
PyThreadState *tstate = _PyThreadState_GET();
2135+
struct _gc_runtime_state *gcstate = &tstate->interp->gc;
2136+
21342137
_PyObject_ASSERT(op, PyObject_IS_GC(op));
21352138
_PyObject_ASSERT(op, !_PyObject_GC_IS_TRACKED(op));
21362139
_PyObject_ASSERT(op, op->ob_refcnt == 0);
2137-
_PyGCHead_SET_PREV(_Py_AS_GC(op), _PyRuntime.gc.trash_delete_later);
2138-
_PyRuntime.gc.trash_delete_later = op;
2140+
_PyGCHead_SET_PREV(_Py_AS_GC(op), gcstate->trash_delete_later);
2141+
gcstate->trash_delete_later = op;
21392142
}
21402143

21412144
/* The equivalent API, using per-thread state recursion info */
@@ -2156,11 +2159,14 @@ _PyTrash_thread_deposit_object(PyObject *op)
21562159
void
21572160
_PyTrash_destroy_chain(void)
21582161
{
2159-
while (_PyRuntime.gc.trash_delete_later) {
2160-
PyObject *op = _PyRuntime.gc.trash_delete_later;
2162+
PyThreadState *tstate = _PyThreadState_GET();
2163+
struct _gc_runtime_state *gcstate = &tstate->interp->gc;
2164+
2165+
while (gcstate->trash_delete_later) {
2166+
PyObject *op = gcstate->trash_delete_later;
21612167
destructor dealloc = Py_TYPE(op)->tp_dealloc;
21622168

2163-
_PyRuntime.gc.trash_delete_later =
2169+
gcstate->trash_delete_later =
21642170
(PyObject*) _PyGCHead_PREV(_Py_AS_GC(op));
21652171

21662172
/* Call the deallocator directly. This used to try to
@@ -2170,9 +2176,9 @@ _PyTrash_destroy_chain(void)
21702176
* up distorting allocation statistics.
21712177
*/
21722178
_PyObject_ASSERT(op, op->ob_refcnt == 0);
2173-
++_PyRuntime.gc.trash_delete_nesting;
2179+
++gcstate->trash_delete_nesting;
21742180
(*dealloc)(op);
2175-
--_PyRuntime.gc.trash_delete_nesting;
2181+
--gcstate->trash_delete_nesting;
21762182
}
21772183
}
21782184

Python/pylifecycle.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1219,8 +1219,9 @@ finalize_interp_clear(PyThreadState *tstate, int is_main_interp)
12191219
PyGrammar_RemoveAccelerators(&_PyParser_Grammar);
12201220

12211221
_PyExc_Fini();
1222-
_PyGC_Fini(tstate);
12231222
}
1223+
1224+
_PyGC_Fini(tstate);
12241225
}
12251226

12261227

0 commit comments

Comments
 (0)