Skip to content

Commit e3debdb

Browse files
Move GC state from _PyRuntimeState to PyInterpreterState.
1 parent 86ea581 commit e3debdb

File tree

8 files changed

+70
-41
lines changed

8 files changed

+70
-41
lines changed

Include/internal/pycore_object.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ PyAPI_FUNC(int) _PyDict_CheckConsistency(PyObject *mp, int check_content);
1919
* NB: While the object is tracked by the collector, it must be safe to call the
2020
* ob_traverse method.
2121
*
22-
* Internal note: _PyRuntime.gc.generation0->_gc_prev doesn't have any bit flags
22+
* Internal note: PyInterpreterState.gc.generation0->_gc_prev doesn't have any bit flags
2323
* because it's not object header. So we don't use _PyGCHead_PREV() and
2424
* _PyGCHead_SET_PREV() for it to avoid unnecessary bitwise operations.
2525
*
@@ -38,11 +38,12 @@ static inline void _PyObject_GC_TRACK_impl(const char *filename, int lineno,
3838
"object is in generation which is garbage collected",
3939
filename, lineno, "_PyObject_GC_TRACK");
4040

41-
PyGC_Head *last = (PyGC_Head*)(_PyRuntime.gc.generation0->_gc_prev);
41+
PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE();
42+
PyGC_Head *last = (PyGC_Head*)(interp->gc.generation0->_gc_prev);
4243
_PyGCHead_SET_NEXT(last, gc);
4344
_PyGCHead_SET_PREV(gc, last);
44-
_PyGCHead_SET_NEXT(gc, _PyRuntime.gc.generation0);
45-
_PyRuntime.gc.generation0->_gc_prev = (uintptr_t)gc;
45+
_PyGCHead_SET_NEXT(gc, interp->gc.generation0);
46+
interp->gc.generation0->_gc_prev = (uintptr_t)gc;
4647
}
4748

4849
#define _PyObject_GC_TRACK(op) \

Include/internal/pycore_pylifecycle.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ extern void PyAsyncGen_Fini(void);
7373
extern void _PyExc_Fini(void);
7474
extern void _PyImport_Fini(void);
7575
extern void _PyImport_Fini2(void);
76-
extern void _PyGC_Fini(_PyRuntimeState *runtime);
76+
extern void _PyGC_Fini(PyInterpreterState *interp);
7777
extern void _PyType_Fini(void);
7878
extern void _Py_HashRandomization_Fini(void);
7979
extern void _PyUnicode_Fini(void);
@@ -89,7 +89,7 @@ extern void _PyGILState_Init(
8989
PyThreadState *tstate);
9090
extern void _PyGILState_Fini(_PyRuntimeState *runtime);
9191

92-
PyAPI_FUNC(void) _PyGC_DumpShutdownStats(_PyRuntimeState *runtime);
92+
PyAPI_FUNC(void) _PyGC_DumpShutdownStats(PyInterpreterState *interp);
9393

9494
PyAPI_FUNC(_PyInitError) _Py_PreInitializeFromPyArgv(
9595
const _PyPreConfig *src_config,

Include/internal/pycore_pystate.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ struct _is {
9292
uint64_t tstate_next_unique_id;
9393

9494
struct _warnings_runtime_state warnings;
95+
struct _gc_runtime_state gc;
9596
};
9697

9798
PyAPI_FUNC(struct _is*) _PyInterpreterState_LookUpID(PY_INT64_T);
@@ -180,7 +181,6 @@ typedef struct pyruntimestate {
180181
void (*exitfuncs[NEXITFUNCS])(void);
181182
int nexitfuncs;
182183

183-
struct _gc_runtime_state gc;
184184
struct _ceval_runtime_state ceval;
185185
struct _gilstate_runtime_state gilstate;
186186

Modules/gcmodule.c

Lines changed: 44 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,7 +1257,8 @@ static PyObject *
12571257
gc_enable_impl(PyObject *module)
12581258
/*[clinic end generated code: output=45a427e9dce9155c input=81ac4940ca579707]*/
12591259
{
1260-
_PyRuntime.gc.enabled = 1;
1260+
PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE();
1261+
interp->gc.enabled = 1;
12611262
Py_RETURN_NONE;
12621263
}
12631264

@@ -1271,7 +1272,8 @@ static PyObject *
12711272
gc_disable_impl(PyObject *module)
12721273
/*[clinic end generated code: output=97d1030f7aa9d279 input=8c2e5a14e800d83b]*/
12731274
{
1274-
_PyRuntime.gc.enabled = 0;
1275+
PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE();
1276+
interp->gc.enabled = 0;
12751277
Py_RETURN_NONE;
12761278
}
12771279

@@ -1285,7 +1287,8 @@ static int
12851287
gc_isenabled_impl(PyObject *module)
12861288
/*[clinic end generated code: output=1874298331c49130 input=30005e0422373b31]*/
12871289
{
1288-
return _PyRuntime.gc.enabled;
1290+
PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE();
1291+
return interp->gc.enabled;
12891292
}
12901293

12911294
/*[clinic input]
@@ -1312,7 +1315,8 @@ gc_collect_impl(PyObject *module, int generation)
13121315
return -1;
13131316
}
13141317

1315-
struct _gc_runtime_state *state = &_PyRuntime.gc;
1318+
PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE();
1319+
struct _gc_runtime_state *state = &interp->gc;
13161320
Py_ssize_t n;
13171321
if (state->collecting) {
13181322
/* already collecting, don't do anything */
@@ -1348,7 +1352,8 @@ static PyObject *
13481352
gc_set_debug_impl(PyObject *module, int flags)
13491353
/*[clinic end generated code: output=7c8366575486b228 input=5e5ce15e84fbed15]*/
13501354
{
1351-
_PyRuntime.gc.debug = flags;
1355+
PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE();
1356+
interp->gc.debug = flags;
13521357

13531358
Py_RETURN_NONE;
13541359
}
@@ -1363,7 +1368,8 @@ static int
13631368
gc_get_debug_impl(PyObject *module)
13641369
/*[clinic end generated code: output=91242f3506cd1e50 input=91a101e1c3b98366]*/
13651370
{
1366-
return _PyRuntime.gc.debug;
1371+
PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE();
1372+
return interp->gc.debug;
13671373
}
13681374

13691375
PyDoc_STRVAR(gc_set_thresh__doc__,
@@ -1375,7 +1381,8 @@ PyDoc_STRVAR(gc_set_thresh__doc__,
13751381
static PyObject *
13761382
gc_set_threshold(PyObject *self, PyObject *args)
13771383
{
1378-
struct _gc_runtime_state *state = &_PyRuntime.gc;
1384+
PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE();
1385+
struct _gc_runtime_state *state = &interp->gc;
13791386
if (!PyArg_ParseTuple(args, "i|ii:set_threshold",
13801387
&state->generations[0].threshold,
13811388
&state->generations[1].threshold,
@@ -1398,7 +1405,8 @@ static PyObject *
13981405
gc_get_threshold_impl(PyObject *module)
13991406
/*[clinic end generated code: output=7902bc9f41ecbbd8 input=286d79918034d6e6]*/
14001407
{
1401-
struct _gc_runtime_state *state = &_PyRuntime.gc;
1408+
PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE();
1409+
struct _gc_runtime_state *state = &interp->gc;
14021410
return Py_BuildValue("(iii)",
14031411
state->generations[0].threshold,
14041412
state->generations[1].threshold,
@@ -1415,7 +1423,8 @@ static PyObject *
14151423
gc_get_count_impl(PyObject *module)
14161424
/*[clinic end generated code: output=354012e67b16398f input=a392794a08251751]*/
14171425
{
1418-
struct _gc_runtime_state *state = &_PyRuntime.gc;
1426+
PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE();
1427+
struct _gc_runtime_state *state = &interp->gc;
14191428
return Py_BuildValue("(iii)",
14201429
state->generations[0].count,
14211430
state->generations[1].count,
@@ -1462,7 +1471,8 @@ gc_get_referrers(PyObject *self, PyObject *args)
14621471
PyObject *result = PyList_New(0);
14631472
if (!result) return NULL;
14641473

1465-
struct _gc_runtime_state *state = &_PyRuntime.gc;
1474+
PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE();
1475+
struct _gc_runtime_state *state = &interp->gc;
14661476
for (i = 0; i < NUM_GENERATIONS; i++) {
14671477
if (!(gc_referrers_for(args, GEN_HEAD(state, i), result))) {
14681478
Py_DECREF(result);
@@ -1526,7 +1536,8 @@ gc_get_objects_impl(PyObject *module, Py_ssize_t generation)
15261536
{
15271537
int i;
15281538
PyObject* result;
1529-
struct _gc_runtime_state *state = &_PyRuntime.gc;
1539+
PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE();
1540+
struct _gc_runtime_state *state = &interp->gc;
15301541

15311542
result = PyList_New(0);
15321543
if (result == NULL) {
@@ -1584,7 +1595,8 @@ gc_get_stats_impl(PyObject *module)
15841595

15851596
/* To get consistent values despite allocations while constructing
15861597
the result list, we use a snapshot of the running stats. */
1587-
struct _gc_runtime_state *state = &_PyRuntime.gc;
1598+
PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE();
1599+
struct _gc_runtime_state *state = &interp->gc;
15881600
for (i = 0; i < NUM_GENERATIONS; i++) {
15891601
stats[i] = state->generation_stats[i];
15901602
}
@@ -1656,7 +1668,8 @@ static PyObject *
16561668
gc_freeze_impl(PyObject *module)
16571669
/*[clinic end generated code: output=502159d9cdc4c139 input=b602b16ac5febbe5]*/
16581670
{
1659-
struct _gc_runtime_state *state = &_PyRuntime.gc;
1671+
PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE();
1672+
struct _gc_runtime_state *state = &interp->gc;
16601673
for (int i = 0; i < NUM_GENERATIONS; ++i) {
16611674
gc_list_merge(GEN_HEAD(state, i), &state->permanent_generation.head);
16621675
state->generations[i].count = 0;
@@ -1676,7 +1689,8 @@ static PyObject *
16761689
gc_unfreeze_impl(PyObject *module)
16771690
/*[clinic end generated code: output=1c15f2043b25e169 input=2dd52b170f4cef6c]*/
16781691
{
1679-
struct _gc_runtime_state *state = &_PyRuntime.gc;
1692+
PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE();
1693+
struct _gc_runtime_state *state = &interp->gc;
16801694
gc_list_merge(&state->permanent_generation.head, GEN_HEAD(state, NUM_GENERATIONS-1));
16811695
Py_RETURN_NONE;
16821696
}
@@ -1691,7 +1705,8 @@ static Py_ssize_t
16911705
gc_get_freeze_count_impl(PyObject *module)
16921706
/*[clinic end generated code: output=61cbd9f43aa032e1 input=45ffbc65cfe2a6ed]*/
16931707
{
1694-
return gc_list_size(&_PyRuntime.gc.permanent_generation.head);
1708+
PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE();
1709+
return gc_list_size(&interp->gc.permanent_generation.head);
16951710
}
16961711

16971712

@@ -1762,7 +1777,8 @@ PyInit_gc(void)
17621777
return NULL;
17631778
}
17641779

1765-
struct _gc_runtime_state *state = &_PyRuntime.gc;
1780+
PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE();
1781+
struct _gc_runtime_state *state = &interp->gc;
17661782
if (state->garbage == NULL) {
17671783
state->garbage = PyList_New(0);
17681784
if (state->garbage == NULL)
@@ -1795,7 +1811,8 @@ PyInit_gc(void)
17951811
Py_ssize_t
17961812
PyGC_Collect(void)
17971813
{
1798-
struct _gc_runtime_state *state = &_PyRuntime.gc;
1814+
PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE();
1815+
struct _gc_runtime_state *state = &interp->gc;
17991816
if (!state->enabled) {
18001817
return 0;
18011818
}
@@ -1828,7 +1845,8 @@ _PyGC_CollectNoFail(void)
18281845
{
18291846
assert(!PyErr_Occurred());
18301847

1831-
struct _gc_runtime_state *state = &_PyRuntime.gc;
1848+
PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE();
1849+
struct _gc_runtime_state *state = &interp->gc;
18321850
Py_ssize_t n;
18331851

18341852
/* Ideally, this function is only called on interpreter shutdown,
@@ -1849,9 +1867,9 @@ _PyGC_CollectNoFail(void)
18491867
}
18501868

18511869
void
1852-
_PyGC_DumpShutdownStats(_PyRuntimeState *runtime)
1870+
_PyGC_DumpShutdownStats(PyInterpreterState *interp)
18531871
{
1854-
struct _gc_runtime_state *state = &runtime->gc;
1872+
struct _gc_runtime_state *state = &interp->gc;
18551873
if (!(state->debug & DEBUG_SAVEALL)
18561874
&& state->garbage != NULL && PyList_GET_SIZE(state->garbage) > 0) {
18571875
const char *message;
@@ -1886,9 +1904,9 @@ _PyGC_DumpShutdownStats(_PyRuntimeState *runtime)
18861904
}
18871905

18881906
void
1889-
_PyGC_Fini(_PyRuntimeState *runtime)
1907+
_PyGC_Fini(PyInterpreterState *interp)
18901908
{
1891-
struct _gc_runtime_state *state = &runtime->gc;
1909+
struct _gc_runtime_state *state = &interp->gc;
18921910
Py_CLEAR(state->garbage);
18931911
Py_CLEAR(state->callbacks);
18941912
}
@@ -1930,7 +1948,8 @@ PyObject_GC_UnTrack(void *op_raw)
19301948
static PyObject *
19311949
_PyObject_GC_Alloc(int use_calloc, size_t basicsize)
19321950
{
1933-
struct _gc_runtime_state *state = &_PyRuntime.gc;
1951+
PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE();
1952+
struct _gc_runtime_state *state = &interp->gc;
19341953
PyObject *op;
19351954
PyGC_Head *g;
19361955
size_t size;
@@ -2023,7 +2042,8 @@ PyObject_GC_Del(void *op)
20232042
if (_PyObject_GC_IS_TRACKED(op)) {
20242043
gc_list_remove(g);
20252044
}
2026-
struct _gc_runtime_state *state = &_PyRuntime.gc;
2045+
PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE();
2046+
struct _gc_runtime_state *state = &interp->gc;
20272047
if (state->generations[0].count > 0) {
20282048
state->generations[0].count--;
20292049
}

Objects/object.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2052,8 +2052,9 @@ _PyTrash_deposit_object(PyObject *op)
20522052
_PyObject_ASSERT(op, PyObject_IS_GC(op));
20532053
_PyObject_ASSERT(op, !_PyObject_GC_IS_TRACKED(op));
20542054
_PyObject_ASSERT(op, op->ob_refcnt == 0);
2055-
_PyGCHead_SET_PREV(_Py_AS_GC(op), _PyRuntime.gc.trash_delete_later);
2056-
_PyRuntime.gc.trash_delete_later = op;
2055+
PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE();
2056+
_PyGCHead_SET_PREV(_Py_AS_GC(op), interp->gc.trash_delete_later);
2057+
interp->gc.trash_delete_later = op;
20572058
}
20582059

20592060
/* The equivalent API, using per-thread state recursion info */
@@ -2074,11 +2075,12 @@ _PyTrash_thread_deposit_object(PyObject *op)
20742075
void
20752076
_PyTrash_destroy_chain(void)
20762077
{
2077-
while (_PyRuntime.gc.trash_delete_later) {
2078-
PyObject *op = _PyRuntime.gc.trash_delete_later;
2078+
PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE();
2079+
while (interp->gc.trash_delete_later) {
2080+
PyObject *op = interp->gc.trash_delete_later;
20792081
destructor dealloc = Py_TYPE(op)->tp_dealloc;
20802082

2081-
_PyRuntime.gc.trash_delete_later =
2083+
interp->gc.trash_delete_later =
20822084
(PyObject*) _PyGCHead_PREV(_Py_AS_GC(op));
20832085

20842086
/* Call the deallocator directly. This used to try to
@@ -2088,9 +2090,9 @@ _PyTrash_destroy_chain(void)
20882090
* up distorting allocation statistics.
20892091
*/
20902092
_PyObject_ASSERT(op, op->ob_refcnt == 0);
2091-
++_PyRuntime.gc.trash_delete_nesting;
2093+
++interp->gc.trash_delete_nesting;
20922094
(*dealloc)(op);
2093-
--_PyRuntime.gc.trash_delete_nesting;
2095+
--interp->gc.trash_delete_nesting;
20942096
}
20952097
}
20962098

Python/import.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,7 @@ PyImport_Cleanup(void)
535535
_PyGC_CollectNoFail();
536536
/* Dump GC stats before it's too late, since it uses the warnings
537537
machinery. */
538-
_PyGC_DumpShutdownStats(&_PyRuntime);
538+
_PyGC_DumpShutdownStats(interp);
539539

540540
/* Now, if there are any modules left alive, clear their globals to
541541
minimize potential leaks. All C extension modules actually end

Python/pylifecycle.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,8 @@ pycore_create_interpreter(_PyRuntimeState *runtime,
511511
}
512512
*interp_p = interp;
513513

514+
_PyGC_Initialize(&interp->gc);
515+
514516
_PyInitError err = _PyCoreConfig_Copy(&interp->core_config, core_config);
515517
if (_Py_INIT_FAILED(err)) {
516518
return err;
@@ -1287,7 +1289,7 @@ Py_FinalizeEx(void)
12871289
PyFloat_Fini();
12881290
PyDict_Fini();
12891291
PySlice_Fini();
1290-
_PyGC_Fini(runtime);
1292+
_PyGC_Fini(interp);
12911293
_PyWarnings_Fini(interp);
12921294
_Py_HashRandomization_Fini();
12931295
_PyArg_Fini();
@@ -1380,6 +1382,8 @@ new_interpreter(PyThreadState **tstate_p)
13801382
return _Py_INIT_OK();
13811383
}
13821384

1385+
_PyGC_Initialize(&interp->gc);
1386+
13831387
PyThreadState *tstate = PyThreadState_New(interp);
13841388
if (tstate == NULL) {
13851389
PyInterpreterState_Delete(interp);
@@ -1558,6 +1562,9 @@ Py_EndInterpreter(PyThreadState *tstate)
15581562

15591563
PyImport_Cleanup();
15601564
PyInterpreterState_Clear(interp);
1565+
1566+
_PyGC_Fini(interp);
1567+
15611568
PyThreadState_Swap(NULL);
15621569
PyInterpreterState_Delete(interp);
15631570
}

Python/pystate.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ _PyRuntimeState_Init_impl(_PyRuntimeState *runtime)
4747
{
4848
memset(runtime, 0, sizeof(*runtime));
4949

50-
_PyGC_Initialize(&runtime->gc);
5150
_PyEval_Initialize(&runtime->ceval);
5251
runtime->preconfig = _PyPreConfig_INIT;
5352

0 commit comments

Comments
 (0)