Skip to content

Commit 7e32c02

Browse files
corona10aisk
authored andcommitted
pythongh-111968: Introduce _PyFreeListState and _PyFreeListState_GET API (pythongh-113584)
1 parent ae71326 commit 7e32c02

17 files changed

+171
-50
lines changed

Include/internal/pycore_freelist.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#ifndef Py_INTERNAL_FREELIST_H
2+
#define Py_INTERNAL_FREELIST_H
3+
#ifdef __cplusplus
4+
extern "C" {
5+
#endif
6+
7+
#ifndef Py_BUILD_CORE
8+
# error "this header requires Py_BUILD_CORE define"
9+
#endif
10+
11+
#ifndef WITH_FREELISTS
12+
// without freelists
13+
# define PyList_MAXFREELIST 0
14+
#endif
15+
16+
/* Empty list reuse scheme to save calls to malloc and free */
17+
#ifndef PyList_MAXFREELIST
18+
# define PyList_MAXFREELIST 80
19+
#endif
20+
21+
struct _Py_list_state {
22+
#if PyList_MAXFREELIST > 0
23+
PyListObject *free_list[PyList_MAXFREELIST];
24+
int numfree;
25+
#endif
26+
};
27+
28+
typedef struct _Py_freelist_state {
29+
struct _Py_list_state list;
30+
} _PyFreeListState;
31+
32+
#ifdef __cplusplus
33+
}
34+
#endif
35+
#endif /* !Py_INTERNAL_FREELIST_H */

Include/internal/pycore_gc.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ extern "C" {
88
# error "this header requires Py_BUILD_CORE define"
99
#endif
1010

11+
#include "pycore_freelist.h" // _PyFreeListState
12+
1113
/* GC information is stored BEFORE the object structure. */
1214
typedef struct {
1315
// Pointer to next object in the list.
@@ -238,9 +240,11 @@ extern PyObject *_PyGC_GetObjects(PyInterpreterState *interp, Py_ssize_t generat
238240
extern PyObject *_PyGC_GetReferrers(PyInterpreterState *interp, PyObject *objs);
239241

240242
// Functions to clear types free lists
243+
extern void _PyGC_ClearAllFreeLists(PyInterpreterState *interp);
244+
extern void _Py_ClearFreeLists(_PyFreeListState *state, int is_finalization);
241245
extern void _PyTuple_ClearFreeList(PyInterpreterState *interp);
242246
extern void _PyFloat_ClearFreeList(PyInterpreterState *interp);
243-
extern void _PyList_ClearFreeList(PyInterpreterState *interp);
247+
extern void _PyList_ClearFreeList(_PyFreeListState *state, int is_finalization);
244248
extern void _PyDict_ClearFreeList(PyInterpreterState *interp);
245249
extern void _PyAsyncGen_ClearFreeLists(PyInterpreterState *interp);
246250
extern void _PyContext_ClearFreeList(PyInterpreterState *interp);

Include/internal/pycore_interp.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,9 @@ struct _is {
179179
// One bit is set for each non-NULL entry in code_watchers
180180
uint8_t active_code_watchers;
181181

182+
#if !defined(Py_GIL_DISABLED)
183+
struct _Py_freelist_state freelist_state;
184+
#endif
182185
struct _py_object_state object_state;
183186
struct _Py_unicode_state unicode;
184187
struct _Py_float_state float_state;
@@ -190,7 +193,6 @@ struct _is {
190193
PySliceObject *slice_cache;
191194

192195
struct _Py_tuple_state tuple;
193-
struct _Py_list_state list;
194196
struct _Py_dict_state dict_state;
195197
struct _Py_async_gen_state async_gen;
196198
struct _Py_context_state context;

Include/internal/pycore_list.h

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,35 +8,17 @@ extern "C" {
88
# error "this header requires Py_BUILD_CORE define"
99
#endif
1010

11+
#include "pycore_freelist.h" // _PyFreeListState
1112

1213
extern PyObject* _PyList_Extend(PyListObject *, PyObject *);
1314
extern void _PyList_DebugMallocStats(FILE *out);
1415

1516

1617
/* runtime lifecycle */
1718

18-
extern void _PyList_Fini(PyInterpreterState *);
19+
extern void _PyList_Fini(_PyFreeListState *);
1920

2021

21-
/* other API */
22-
23-
#ifndef WITH_FREELISTS
24-
// without freelists
25-
# define PyList_MAXFREELIST 0
26-
#endif
27-
28-
/* Empty list reuse scheme to save calls to malloc and free */
29-
#ifndef PyList_MAXFREELIST
30-
# define PyList_MAXFREELIST 80
31-
#endif
32-
33-
struct _Py_list_state {
34-
#if PyList_MAXFREELIST > 0
35-
PyListObject *free_list[PyList_MAXFREELIST];
36-
int numfree;
37-
#endif
38-
};
39-
4022
#define _PyList_ITEMS(op) _Py_RVALUE(_PyList_CAST(op)->ob_item)
4123

4224
extern int

Include/internal/pycore_pystate.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ extern "C" {
88
# error "this header requires Py_BUILD_CORE define"
99
#endif
1010

11+
#include "pycore_freelist.h" // _PyFreeListState
1112
#include "pycore_runtime.h" // _PyRuntime
13+
#include "pycore_tstate.h" // _PyThreadStateImpl
1214

1315

1416
// Values for PyThreadState.state. A thread must be in the "attached" state
@@ -239,6 +241,20 @@ PyAPI_FUNC(const PyConfig*) _Py_GetConfig(void);
239241
// See also PyInterpreterState_Get() and _PyInterpreterState_GET().
240242
extern PyInterpreterState* _PyGILState_GetInterpreterStateUnsafe(void);
241243

244+
static inline _PyFreeListState* _PyFreeListState_GET(void)
245+
{
246+
PyThreadState *tstate = _PyThreadState_GET();
247+
#ifdef Py_DEBUG
248+
_Py_EnsureTstateNotNULL(tstate);
249+
#endif
250+
251+
#ifdef Py_GIL_DISABLED
252+
return &((_PyThreadStateImpl*)tstate)->freelist_state;
253+
#else
254+
return &tstate->interp->freelist_state;
255+
#endif
256+
}
257+
242258
#ifdef __cplusplus
243259
}
244260
#endif

Include/internal/pycore_tstate.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ extern "C" {
88
# error "this header requires Py_BUILD_CORE define"
99
#endif
1010

11+
#include "pycore_freelist.h" // struct _Py_freelist_state
1112
#include "pycore_mimalloc.h" // struct _mimalloc_thread_state
1213

1314

@@ -20,6 +21,7 @@ typedef struct _PyThreadStateImpl {
2021

2122
#ifdef Py_GIL_DISABLED
2223
struct _mimalloc_thread_state mimalloc;
24+
struct _Py_freelist_state freelist_state;
2325
#endif
2426

2527
} _PyThreadStateImpl;

Makefile.pre.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,8 @@ PYTHON_OBJS= \
418418
Python/frozenmain.o \
419419
Python/future.o \
420420
Python/gc.o \
421+
Python/gc_free_threading.o \
422+
Python/gc_gil.o \
421423
Python/getargs.o \
422424
Python/getcompiler.o \
423425
Python/getcopyright.o \
@@ -1828,6 +1830,7 @@ PYTHON_HEADERS= \
18281830
$(srcdir)/Include/internal/pycore_floatobject.h \
18291831
$(srcdir)/Include/internal/pycore_format.h \
18301832
$(srcdir)/Include/internal/pycore_frame.h \
1833+
$(srcdir)/Include/internal/pycore_freelist.h \
18311834
$(srcdir)/Include/internal/pycore_function.h \
18321835
$(srcdir)/Include/internal/pycore_genobject.h \
18331836
$(srcdir)/Include/internal/pycore_getopt.h \

Objects/listobject.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,9 @@ _Py_DECLARE_STR(list_err, "list index out of range");
2424
static struct _Py_list_state *
2525
get_list_state(void)
2626
{
27-
PyInterpreterState *interp = _PyInterpreterState_GET();
28-
return &interp->list;
27+
_PyFreeListState *state = _PyFreeListState_GET();
28+
assert(state != NULL);
29+
return &state->list;
2930
}
3031
#endif
3132

@@ -120,26 +121,25 @@ list_preallocate_exact(PyListObject *self, Py_ssize_t size)
120121
}
121122

122123
void
123-
_PyList_ClearFreeList(PyInterpreterState *interp)
124+
_PyList_ClearFreeList(_PyFreeListState *freelist_state, int is_finalization)
124125
{
125126
#if PyList_MAXFREELIST > 0
126-
struct _Py_list_state *state = &interp->list;
127-
while (state->numfree) {
127+
struct _Py_list_state *state = &freelist_state->list;
128+
while (state->numfree > 0) {
128129
PyListObject *op = state->free_list[--state->numfree];
129130
assert(PyList_CheckExact(op));
130131
PyObject_GC_Del(op);
131132
}
133+
if (is_finalization) {
134+
state->numfree = -1;
135+
}
132136
#endif
133137
}
134138

135139
void
136-
_PyList_Fini(PyInterpreterState *interp)
140+
_PyList_Fini(_PyFreeListState *state)
137141
{
138-
_PyList_ClearFreeList(interp);
139-
#if defined(Py_DEBUG) && PyList_MAXFREELIST > 0
140-
struct _Py_list_state *state = &interp->list;
141-
state->numfree = -1;
142-
#endif
142+
_PyList_ClearFreeList(state, 1);
143143
}
144144

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

PCbuild/_freeze_module.vcxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,8 @@
208208
<ClCompile Include="..\Python\frame.c" />
209209
<ClCompile Include="..\Python\future.c" />
210210
<ClCompile Include="..\Python\gc.c" />
211+
<ClCompile Include="..\Python\gc_gil.c" />
212+
<ClCompile Include="..\Python\gc_free_threading.c" />
211213
<ClCompile Include="..\Python\getargs.c" />
212214
<ClCompile Include="..\Python\getcompiler.c" />
213215
<ClCompile Include="..\Python\getcopyright.c" />

PCbuild/_freeze_module.vcxproj.filters

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,12 @@
169169
<ClCompile Include="..\Python\gc.c">
170170
<Filter>Source Files</Filter>
171171
</ClCompile>
172+
<ClCompile Include="..\Python\gc_free_threading.c">
173+
<Filter>Source Files</Filter>
174+
</ClCompile>
175+
<ClCompile Include="..\Python\gc_gil.c">
176+
<Filter>Source Files</Filter>
177+
</ClCompile>
172178
<ClCompile Include="..\Modules\gcmodule.c">
173179
<Filter>Source Files</Filter>
174180
</ClCompile>

0 commit comments

Comments
 (0)