Skip to content

Commit 2e96906

Browse files
authored
bpo-36710: Pass tstate parameter to GC collect() (GH-17267)
Pass tstate parameter (PyThreadState) to GC collect() function and other GC subfunctions.
1 parent 279d8df commit 2e96906

File tree

1 file changed

+50
-37
lines changed

1 file changed

+50
-37
lines changed

Modules/gcmodule.c

+50-37
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "pycore_context.h"
2828
#include "pycore_initconfig.h"
2929
#include "pycore_object.h"
30+
#include "pycore_pyerrors.h"
3031
#include "pycore_pymem.h"
3132
#include "pycore_pystate.h"
3233
#include "frameobject.h" /* for PyFrame_ClearFreeList */
@@ -917,10 +918,11 @@ debug_cycle(const char *msg, PyObject *op)
917918
* merged into the old list regardless.
918919
*/
919920
static void
920-
handle_legacy_finalizers(struct _gc_runtime_state *state,
921+
handle_legacy_finalizers(PyThreadState *tstate,
922+
struct _gc_runtime_state *state,
921923
PyGC_Head *finalizers, PyGC_Head *old)
922924
{
923-
assert(!PyErr_Occurred());
925+
assert(!_PyErr_Occurred(tstate));
924926
assert(state->garbage != NULL);
925927

926928
PyGC_Head *gc = GC_NEXT(finalizers);
@@ -929,7 +931,7 @@ handle_legacy_finalizers(struct _gc_runtime_state *state,
929931

930932
if ((state->debug & DEBUG_SAVEALL) || has_legacy_finalizer(op)) {
931933
if (PyList_Append(state->garbage, op) < 0) {
932-
PyErr_Clear();
934+
_PyErr_Clear(tstate);
933935
break;
934936
}
935937
}
@@ -979,10 +981,10 @@ finalize_garbage(PyGC_Head *collectable)
979981
* objects may be freed. It is possible I screwed something up here.
980982
*/
981983
static void
982-
delete_garbage(struct _gc_runtime_state *state,
984+
delete_garbage(PyThreadState *tstate, struct _gc_runtime_state *state,
983985
PyGC_Head *collectable, PyGC_Head *old)
984986
{
985-
assert(!PyErr_Occurred());
987+
assert(!_PyErr_Occurred(tstate));
986988

987989
while (!gc_list_is_empty(collectable)) {
988990
PyGC_Head *gc = GC_NEXT(collectable);
@@ -994,15 +996,15 @@ delete_garbage(struct _gc_runtime_state *state,
994996
if (state->debug & DEBUG_SAVEALL) {
995997
assert(state->garbage != NULL);
996998
if (PyList_Append(state->garbage, op) < 0) {
997-
PyErr_Clear();
999+
_PyErr_Clear(tstate);
9981000
}
9991001
}
10001002
else {
10011003
inquiry clear;
10021004
if ((clear = Py_TYPE(op)->tp_clear) != NULL) {
10031005
Py_INCREF(op);
10041006
(void) clear(op);
1005-
if (PyErr_Occurred()) {
1007+
if (_PyErr_Occurred(tstate)) {
10061008
_PyErr_WriteUnraisableMsg("in tp_clear of",
10071009
(PyObject*)Py_TYPE(op));
10081010
}
@@ -1143,7 +1145,7 @@ handle_resurrected_objects(PyGC_Head *unreachable, PyGC_Head* still_unreachable,
11431145
/* This is the main function. Read this to understand how the
11441146
* collection process works. */
11451147
static Py_ssize_t
1146-
collect(struct _gc_runtime_state *state, int generation,
1148+
collect(PyThreadState *tstate, struct _gc_runtime_state *state, int generation,
11471149
Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable, int nofail)
11481150
{
11491151
int i;
@@ -1245,7 +1247,7 @@ collect(struct _gc_runtime_state *state, int generation,
12451247
* in finalizers to be freed.
12461248
*/
12471249
m += gc_list_size(&final_unreachable);
1248-
delete_garbage(state, &final_unreachable, old);
1250+
delete_garbage(tstate, state, &final_unreachable, old);
12491251

12501252
/* Collect statistics on uncollectable objects found and print
12511253
* debugging information. */
@@ -1266,7 +1268,7 @@ collect(struct _gc_runtime_state *state, int generation,
12661268
* reachable list of garbage. The programmer has to deal with
12671269
* this if they insist on creating this type of structure.
12681270
*/
1269-
handle_legacy_finalizers(state, &finalizers, old);
1271+
handle_legacy_finalizers(tstate, state, &finalizers, old);
12701272
validate_list(old, collecting_clear_unreachable_clear);
12711273

12721274
/* Clear free list only during the collection of the highest
@@ -1275,9 +1277,9 @@ collect(struct _gc_runtime_state *state, int generation,
12751277
clear_freelists();
12761278
}
12771279

1278-
if (PyErr_Occurred()) {
1280+
if (_PyErr_Occurred(tstate)) {
12791281
if (nofail) {
1280-
PyErr_Clear();
1282+
_PyErr_Clear(tstate);
12811283
}
12821284
else {
12831285
if (gc_str == NULL)
@@ -1301,11 +1303,11 @@ collect(struct _gc_runtime_state *state, int generation,
13011303
stats->uncollectable += n;
13021304

13031305
if (PyDTrace_GC_DONE_ENABLED()) {
1304-
PyDTrace_GC_DONE(n+m);
1306+
PyDTrace_GC_DONE(n + m);
13051307
}
13061308

1307-
assert(!PyErr_Occurred());
1308-
return n+m;
1309+
assert(!_PyErr_Occurred(tstate));
1310+
return n + m;
13091311
}
13101312

13111313
/* Invoke progress callbacks to notify clients that garbage collection
@@ -1356,19 +1358,20 @@ invoke_gc_callback(struct _gc_runtime_state *state, const char *phase,
13561358
* progress callbacks.
13571359
*/
13581360
static Py_ssize_t
1359-
collect_with_callback(struct _gc_runtime_state *state, int generation)
1361+
collect_with_callback(PyThreadState *tstate, struct _gc_runtime_state *state,
1362+
int generation)
13601363
{
13611364
assert(!PyErr_Occurred());
13621365
Py_ssize_t result, collected, uncollectable;
13631366
invoke_gc_callback(state, "start", generation, 0, 0);
1364-
result = collect(state, generation, &collected, &uncollectable, 0);
1367+
result = collect(tstate, state, generation, &collected, &uncollectable, 0);
13651368
invoke_gc_callback(state, "stop", generation, collected, uncollectable);
13661369
assert(!PyErr_Occurred());
13671370
return result;
13681371
}
13691372

13701373
static Py_ssize_t
1371-
collect_generations(struct _gc_runtime_state *state)
1374+
collect_generations(PyThreadState *tstate, struct _gc_runtime_state *state)
13721375
{
13731376
/* Find the oldest generation (highest numbered) where the count
13741377
* exceeds the threshold. Objects in the that generation and
@@ -1383,7 +1386,7 @@ collect_generations(struct _gc_runtime_state *state)
13831386
if (i == NUM_GENERATIONS - 1
13841387
&& state->long_lived_pending < state->long_lived_total / 4)
13851388
continue;
1386-
n = collect_with_callback(state, i);
1389+
n = collect_with_callback(tstate, state, i);
13871390
break;
13881391
}
13891392
}
@@ -1451,9 +1454,10 @@ static Py_ssize_t
14511454
gc_collect_impl(PyObject *module, int generation)
14521455
/*[clinic end generated code: output=b697e633043233c7 input=40720128b682d879]*/
14531456
{
1457+
PyThreadState *tstate = _PyThreadState_GET();
14541458

14551459
if (generation < 0 || generation >= NUM_GENERATIONS) {
1456-
PyErr_SetString(PyExc_ValueError, "invalid generation");
1460+
_PyErr_SetString(tstate, PyExc_ValueError, "invalid generation");
14571461
return -1;
14581462
}
14591463

@@ -1465,7 +1469,7 @@ gc_collect_impl(PyObject *module, int generation)
14651469
}
14661470
else {
14671471
state->collecting = 1;
1468-
n = collect_with_callback(state, generation);
1472+
n = collect_with_callback(tstate, state, generation);
14691473
state->collecting = 0;
14701474
}
14711475
return n;
@@ -1940,7 +1944,9 @@ PyInit_gc(void)
19401944
Py_ssize_t
19411945
PyGC_Collect(void)
19421946
{
1947+
PyThreadState *tstate = _PyThreadState_GET();
19431948
struct _gc_runtime_state *state = &_PyRuntime.gc;
1949+
19441950
if (!state->enabled) {
19451951
return 0;
19461952
}
@@ -1953,9 +1959,9 @@ PyGC_Collect(void)
19531959
else {
19541960
PyObject *exc, *value, *tb;
19551961
state->collecting = 1;
1956-
PyErr_Fetch(&exc, &value, &tb);
1957-
n = collect_with_callback(state, NUM_GENERATIONS - 1);
1958-
PyErr_Restore(exc, value, tb);
1962+
_PyErr_Fetch(tstate, &exc, &value, &tb);
1963+
n = collect_with_callback(tstate, state, NUM_GENERATIONS - 1);
1964+
_PyErr_Restore(tstate, exc, value, tb);
19591965
state->collecting = 0;
19601966
}
19611967

@@ -1971,7 +1977,8 @@ _PyGC_CollectIfEnabled(void)
19711977
Py_ssize_t
19721978
_PyGC_CollectNoFail(void)
19731979
{
1974-
assert(!PyErr_Occurred());
1980+
PyThreadState *tstate = _PyThreadState_GET();
1981+
assert(!_PyErr_Occurred(tstate));
19751982

19761983
struct _gc_runtime_state *state = &_PyRuntime.gc;
19771984
Py_ssize_t n;
@@ -1987,7 +1994,7 @@ _PyGC_CollectNoFail(void)
19871994
}
19881995
else {
19891996
state->collecting = 1;
1990-
n = collect(state, NUM_GENERATIONS - 1, NULL, NULL, 1);
1997+
n = collect(tstate, state, NUM_GENERATIONS - 1, NULL, NULL, 1);
19911998
state->collecting = 0;
19921999
}
19932000
return n;
@@ -2098,32 +2105,38 @@ static PyObject *
20982105
_PyObject_GC_Alloc(int use_calloc, size_t basicsize)
20992106
{
21002107
struct _gc_runtime_state *state = &_PyRuntime.gc;
2101-
PyObject *op;
2102-
PyGC_Head *g;
2103-
size_t size;
2104-
if (basicsize > PY_SSIZE_T_MAX - sizeof(PyGC_Head))
2108+
if (basicsize > PY_SSIZE_T_MAX - sizeof(PyGC_Head)) {
21052109
return PyErr_NoMemory();
2106-
size = sizeof(PyGC_Head) + basicsize;
2107-
if (use_calloc)
2110+
}
2111+
size_t size = sizeof(PyGC_Head) + basicsize;
2112+
2113+
PyGC_Head *g;
2114+
if (use_calloc) {
21082115
g = (PyGC_Head *)PyObject_Calloc(1, size);
2109-
else
2116+
}
2117+
else {
21102118
g = (PyGC_Head *)PyObject_Malloc(size);
2111-
if (g == NULL)
2119+
}
2120+
if (g == NULL) {
21122121
return PyErr_NoMemory();
2122+
}
21132123
assert(((uintptr_t)g & 3) == 0); // g must be aligned 4bytes boundary
2124+
21142125
g->_gc_next = 0;
21152126
g->_gc_prev = 0;
21162127
state->generations[0].count++; /* number of allocated GC objects */
21172128
if (state->generations[0].count > state->generations[0].threshold &&
21182129
state->enabled &&
21192130
state->generations[0].threshold &&
21202131
!state->collecting &&
2121-
!PyErr_Occurred()) {
2132+
!PyErr_Occurred())
2133+
{
2134+
PyThreadState *tstate = _PyThreadState_GET();
21222135
state->collecting = 1;
2123-
collect_generations(state);
2136+
collect_generations(tstate, state);
21242137
state->collecting = 0;
21252138
}
2126-
op = FROM_GC(g);
2139+
PyObject *op = FROM_GC(g);
21272140
return op;
21282141
}
21292142

0 commit comments

Comments
 (0)