Skip to content

Commit ae00a5a

Browse files
authored
bpo-40428: Remove PyTuple_ClearFreeList() function (GH-19769)
Remove the following function from the C API: * PyAsyncGen_ClearFreeLists() * PyContext_ClearFreeList() * PyDict_ClearFreeList() * PyFloat_ClearFreeList() * PyFrame_ClearFreeList() * PyList_ClearFreeList() * PySet_ClearFreeList() * PyTuple_ClearFreeList() Make these functions private, move them to the internal C API and change their return type to void. Call explicitly PyGC_Collect() to free all free lists. Note: PySet_ClearFreeList() did nothing.
1 parent cc0dc7e commit ae00a5a

21 files changed

+71
-86
lines changed

Doc/whatsnew/3.9.rst

+13
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,19 @@ Build and C API Changes
672672
the garbage collector respectively. (Contributed by Pablo Galindo in
673673
:issue:`40241`.)
674674

675+
* Remove the following functions from the C API. Call :c:func:`PyGC_Collect`
676+
explicitly to free all free lists.
677+
(Contributed by Victor Stinner in :issue:`40428`.)
678+
679+
* ``PyAsyncGen_ClearFreeLists()``
680+
* ``PyContext_ClearFreeList()``
681+
* ``PyDict_ClearFreeList()``
682+
* ``PyFloat_ClearFreeList()``
683+
* ``PyFrame_ClearFreeList()``
684+
* ``PyList_ClearFreeList()``
685+
* ``PySet_ClearFreeList()``
686+
* ``PyTuple_ClearFreeList()``
687+
675688

676689
Deprecated
677690
==========

Include/context.h

-3
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,6 @@ PyAPI_FUNC(int) PyContextVar_Reset(PyObject *var, PyObject *token);
7373
PyAPI_FUNC(PyObject *) _PyContext_NewHamtForTests(void);
7474

7575

76-
PyAPI_FUNC(int) PyContext_ClearFreeList(void);
77-
78-
7976
#endif /* !Py_LIMITED_API */
8077

8178
#ifdef __cplusplus

Include/cpython/dictobject.h

-2
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,6 @@ PyObject *_PyDict_Pop_KnownHash(PyObject *, PyObject *, Py_hash_t, PyObject *);
6262
PyObject *_PyDict_FromKeys(PyObject *, PyObject *, PyObject *);
6363
#define _PyDict_HasSplitTable(d) ((d)->ma_values != NULL)
6464

65-
PyAPI_FUNC(int) PyDict_ClearFreeList(void);
66-
6765
/* Like PyDict_Merge, but override can be 0, 1 or 2. If override is 0,
6866
the first occurrence of a key wins, if override is 1, the last occurrence
6967
of a key wins, if override is 2, a KeyError with conflicting key as

Include/cpython/frameobject.h

-2
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,6 @@ PyAPI_FUNC(void) PyFrame_LocalsToFast(PyFrameObject *, int);
7575
PyAPI_FUNC(int) PyFrame_FastToLocalsWithError(PyFrameObject *f);
7676
PyAPI_FUNC(void) PyFrame_FastToLocals(PyFrameObject *);
7777

78-
PyAPI_FUNC(int) PyFrame_ClearFreeList(void);
79-
8078
PyAPI_FUNC(void) _PyFrame_DebugMallocStats(FILE *out);
8179

8280
#ifdef __cplusplus

Include/cpython/listobject.h

-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ typedef struct {
2626
} PyListObject;
2727

2828
PyAPI_FUNC(PyObject *) _PyList_Extend(PyListObject *, PyObject *);
29-
PyAPI_FUNC(int) PyList_ClearFreeList(void);
3029
PyAPI_FUNC(void) _PyList_DebugMallocStats(FILE *out);
3130

3231
/* Macro, trading safety for speed */

Include/floatobject.h

-3
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,6 @@ PyAPI_FUNC(double) _PyFloat_Unpack2(const unsigned char *p, int le);
100100
PyAPI_FUNC(double) _PyFloat_Unpack4(const unsigned char *p, int le);
101101
PyAPI_FUNC(double) _PyFloat_Unpack8(const unsigned char *p, int le);
102102

103-
/* free list api */
104-
PyAPI_FUNC(int) PyFloat_ClearFreeList(void);
105-
106103
PyAPI_FUNC(void) _PyFloat_DebugMallocStats(FILE* out);
107104

108105
/* Format the object based on the format_spec, as defined in PEP 3101

Include/genobject.h

-2
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,6 @@ PyAPI_FUNC(PyObject *) PyAsyncGen_New(PyFrameObject *,
9191

9292
PyObject *_PyAsyncGenValueWrapperNew(PyObject *);
9393

94-
int PyAsyncGen_ClearFreeLists(void);
95-
9694
#endif
9795

9896
#undef _PyGenObject_HEAD

Include/internal/pycore_gc.h

+10
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,16 @@ struct _gc_runtime_state {
163163

164164
PyAPI_FUNC(void) _PyGC_InitState(struct _gc_runtime_state *);
165165

166+
167+
// Functions to clear types free lists
168+
extern void _PyFrame_ClearFreeList(void);
169+
extern void _PyTuple_ClearFreeList(void);
170+
extern void _PyFloat_ClearFreeList(void);
171+
extern void _PyList_ClearFreeList(void);
172+
extern void _PyDict_ClearFreeList(void);
173+
extern void _PyAsyncGen_ClearFreeLists(void);
174+
extern void _PyContext_ClearFreeList(void);
175+
166176
#ifdef __cplusplus
167177
}
168178
#endif

Include/setobject.h

-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ PyAPI_DATA(PyObject *) _PySet_Dummy;
7070

7171
PyAPI_FUNC(int) _PySet_NextEntry(PyObject *set, Py_ssize_t *pos, PyObject **key, Py_hash_t *hash);
7272
PyAPI_FUNC(int) _PySet_Update(PyObject *set, PyObject *iterable);
73-
PyAPI_FUNC(int) PySet_ClearFreeList(void);
7473

7574
#endif /* Section excluded by Py_LIMITED_API */
7675

Include/tupleobject.h

-2
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ PyAPI_FUNC(int) PyTuple_SetItem(PyObject *, Py_ssize_t, PyObject *);
3434
PyAPI_FUNC(PyObject *) PyTuple_GetSlice(PyObject *, Py_ssize_t, Py_ssize_t);
3535
PyAPI_FUNC(PyObject *) PyTuple_Pack(Py_ssize_t, ...);
3636

37-
PyAPI_FUNC(int) PyTuple_ClearFreeList(void);
38-
3937
#ifndef Py_LIMITED_API
4038
# define Py_CPYTHON_TUPLEOBJECT_H
4139
# include "cpython/tupleobject.h"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Remove the following functions from the C API. Call :c:func:`PyGC_Collect`
2+
explicitly to free all free lists.
3+
4+
* ``PyAsyncGen_ClearFreeLists()``
5+
* ``PyContext_ClearFreeList()``
6+
* ``PyDict_ClearFreeList()``
7+
* ``PyFloat_ClearFreeList()``
8+
* ``PyFrame_ClearFreeList()``
9+
* ``PyList_ClearFreeList()``
10+
* ``PySet_ClearFreeList()``
11+
* ``PyTuple_ClearFreeList()``

Modules/gcmodule.c

+7-9
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
#include "pycore_object.h"
3131
#include "pycore_pyerrors.h"
3232
#include "pycore_pystate.h" // _PyThreadState_GET()
33-
#include "frameobject.h" // PyFrame_ClearFreeList
3433
#include "pydtrace.h"
3534
#include "pytime.h" // _PyTime_GetMonotonicClock()
3635

@@ -1026,14 +1025,13 @@ delete_garbage(PyThreadState *tstate, GCState *gcstate,
10261025
static void
10271026
clear_freelists(void)
10281027
{
1029-
(void)PyFrame_ClearFreeList();
1030-
(void)PyTuple_ClearFreeList();
1031-
(void)PyFloat_ClearFreeList();
1032-
(void)PyList_ClearFreeList();
1033-
(void)PyDict_ClearFreeList();
1034-
(void)PySet_ClearFreeList();
1035-
(void)PyAsyncGen_ClearFreeLists();
1036-
(void)PyContext_ClearFreeList();
1028+
_PyFrame_ClearFreeList();
1029+
_PyTuple_ClearFreeList();
1030+
_PyFloat_ClearFreeList();
1031+
_PyList_ClearFreeList();
1032+
_PyDict_ClearFreeList();
1033+
_PyAsyncGen_ClearFreeLists();
1034+
_PyContext_ClearFreeList();
10371035
}
10381036

10391037
// Show stats for objects in each generations

Objects/dictobject.c

+4-7
Original file line numberDiff line numberDiff line change
@@ -257,20 +257,17 @@ static int numfreekeys = 0;
257257

258258
#include "clinic/dictobject.c.h"
259259

260-
int
261-
PyDict_ClearFreeList(void)
260+
void
261+
_PyDict_ClearFreeList(void)
262262
{
263-
PyDictObject *op;
264-
int ret = numfree + numfreekeys;
265263
while (numfree) {
266-
op = free_list[--numfree];
264+
PyDictObject *op = free_list[--numfree];
267265
assert(PyDict_CheckExact(op));
268266
PyObject_GC_Del(op);
269267
}
270268
while (numfreekeys) {
271269
PyObject_FREE(keys_free_list[--numfreekeys]);
272270
}
273-
return ret;
274271
}
275272

276273
/* Print summary info about the state of the optimized allocator */
@@ -285,7 +282,7 @@ _PyDict_DebugMallocStats(FILE *out)
285282
void
286283
_PyDict_Fini(void)
287284
{
288-
PyDict_ClearFreeList();
285+
_PyDict_ClearFreeList();
289286
}
290287

291288
#define DK_SIZE(dk) ((dk)->dk_size)

Objects/floatobject.c

+4-7
Original file line numberDiff line numberDiff line change
@@ -1998,25 +1998,22 @@ _PyFloat_Init(void)
19981998
return 1;
19991999
}
20002000

2001-
int
2002-
PyFloat_ClearFreeList(void)
2001+
void
2002+
_PyFloat_ClearFreeList(void)
20032003
{
20042004
PyFloatObject *f = free_list, *next;
2005-
int i = numfree;
2006-
while (f) {
2005+
for (; f; f = next) {
20072006
next = (PyFloatObject*) Py_TYPE(f);
20082007
PyObject_FREE(f);
2009-
f = next;
20102008
}
20112009
free_list = NULL;
20122010
numfree = 0;
2013-
return i;
20142011
}
20152012

20162013
void
20172014
_PyFloat_Fini(void)
20182015
{
2019-
(void)PyFloat_ClearFreeList();
2016+
_PyFloat_ClearFreeList();
20202017
}
20212018

20222019
/* Print summary info about the state of the optimized allocator */

Objects/frameobject.c

+3-6
Original file line numberDiff line numberDiff line change
@@ -1200,25 +1200,22 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear)
12001200
}
12011201

12021202
/* Clear out the free list */
1203-
int
1204-
PyFrame_ClearFreeList(void)
1203+
void
1204+
_PyFrame_ClearFreeList(void)
12051205
{
1206-
int freelist_size = numfree;
1207-
12081206
while (free_list != NULL) {
12091207
PyFrameObject *f = free_list;
12101208
free_list = free_list->f_back;
12111209
PyObject_GC_Del(f);
12121210
--numfree;
12131211
}
12141212
assert(numfree == 0);
1215-
return freelist_size;
12161213
}
12171214

12181215
void
12191216
_PyFrame_Fini(void)
12201217
{
1221-
(void)PyFrame_ClearFreeList();
1218+
_PyFrame_ClearFreeList();
12221219
}
12231220

12241221
/* Print summary info about the state of the optimized allocator */

Objects/genobject.c

+3-7
Original file line numberDiff line numberDiff line change
@@ -1429,11 +1429,9 @@ PyAsyncGen_New(PyFrameObject *f, PyObject *name, PyObject *qualname)
14291429
}
14301430

14311431

1432-
int
1433-
PyAsyncGen_ClearFreeLists(void)
1432+
void
1433+
_PyAsyncGen_ClearFreeLists(void)
14341434
{
1435-
int ret = ag_value_freelist_free + ag_asend_freelist_free;
1436-
14371435
while (ag_value_freelist_free) {
14381436
_PyAsyncGenWrappedValue *o;
14391437
o = ag_value_freelist[--ag_value_freelist_free];
@@ -1447,14 +1445,12 @@ PyAsyncGen_ClearFreeLists(void)
14471445
assert(Py_IS_TYPE(o, &_PyAsyncGenASend_Type));
14481446
PyObject_GC_Del(o);
14491447
}
1450-
1451-
return ret;
14521448
}
14531449

14541450
void
14551451
_PyAsyncGen_Fini(void)
14561452
{
1457-
PyAsyncGen_ClearFreeLists();
1453+
_PyAsyncGen_ClearFreeLists();
14581454
}
14591455

14601456

Objects/listobject.c

+4-7
Original file line numberDiff line numberDiff line change
@@ -103,23 +103,20 @@ list_preallocate_exact(PyListObject *self, Py_ssize_t size)
103103
static PyListObject *free_list[PyList_MAXFREELIST];
104104
static int numfree = 0;
105105

106-
int
107-
PyList_ClearFreeList(void)
106+
void
107+
_PyList_ClearFreeList(void)
108108
{
109-
PyListObject *op;
110-
int ret = numfree;
111109
while (numfree) {
112-
op = free_list[--numfree];
110+
PyListObject *op = free_list[--numfree];
113111
assert(PyList_CheckExact(op));
114112
PyObject_GC_Del(op);
115113
}
116-
return ret;
117114
}
118115

119116
void
120117
_PyList_Fini(void)
121118
{
122-
PyList_ClearFreeList();
119+
_PyList_ClearFreeList();
123120
}
124121

125122
/* Print summary info about the state of the optimized allocator */

Objects/setobject.c

-6
Original file line numberDiff line numberDiff line change
@@ -2384,12 +2384,6 @@ PySet_Add(PyObject *anyset, PyObject *key)
23842384
return set_add_key((PySetObject *)anyset, key);
23852385
}
23862386

2387-
int
2388-
PySet_ClearFreeList(void)
2389-
{
2390-
return 0;
2391-
}
2392-
23932387
void
23942388
_PySet_Fini(void)
23952389
{

Objects/tupleobject.c

+7-11
Original file line numberDiff line numberDiff line change
@@ -955,26 +955,22 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize)
955955
return 0;
956956
}
957957

958-
int
959-
PyTuple_ClearFreeList(void)
958+
void
959+
_PyTuple_ClearFreeList(void)
960960
{
961-
int freelist_size = 0;
962961
#if PyTuple_MAXSAVESIZE > 0
963-
int i;
964-
for (i = 1; i < PyTuple_MAXSAVESIZE; i++) {
965-
PyTupleObject *p, *q;
966-
p = free_list[i];
967-
freelist_size += numfree[i];
962+
for (Py_ssize_t i = 1; i < PyTuple_MAXSAVESIZE; i++) {
963+
PyTupleObject *p = free_list[i];
968964
free_list[i] = NULL;
969965
numfree[i] = 0;
970966
while (p) {
971-
q = p;
967+
PyTupleObject *q = p;
972968
p = (PyTupleObject *)(p->ob_item[0]);
973969
PyObject_GC_Del(q);
974970
}
975971
}
972+
// the empty tuple singleton is only cleared by _PyTuple_Fini()
976973
#endif
977-
return freelist_size;
978974
}
979975

980976
void
@@ -985,7 +981,7 @@ _PyTuple_Fini(void)
985981
* rely on the fact that an empty tuple is a singleton. */
986982
Py_CLEAR(free_list[0]);
987983

988-
(void)PyTuple_ClearFreeList();
984+
_PyTuple_ClearFreeList();
989985
#endif
990986
}
991987

PC/python3.def

-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ EXPORTS
3535
PyBytes_Size=python39.PyBytes_Size
3636
PyBytes_Type=python39.PyBytes_Type DATA
3737
PyCFunction_Call=python39.PyCFunction_Call
38-
PyCFunction_ClearFreeList=python39.PyCFunction_ClearFreeList
3938
PyCFunction_GetFlags=python39.PyCFunction_GetFlags
4039
PyCFunction_GetFunction=python39.PyCFunction_GetFunction
4140
PyCFunction_GetSelf=python39.PyCFunction_GetSelf
@@ -584,7 +583,6 @@ EXPORTS
584583
PyTraceBack_Print=python39.PyTraceBack_Print
585584
PyTraceBack_Type=python39.PyTraceBack_Type DATA
586585
PyTupleIter_Type=python39.PyTupleIter_Type DATA
587-
PyTuple_ClearFreeList=python39.PyTuple_ClearFreeList
588586
PyTuple_GetItem=python39.PyTuple_GetItem
589587
PyTuple_GetSlice=python39.PyTuple_GetSlice
590588
PyTuple_New=python39.PyTuple_New

0 commit comments

Comments
 (0)