Skip to content

Commit a0a5708

Browse files
corona10aisk
authored andcommitted
pythongh-111968: Use per-thread freelists for PyContext in free-threading (pythongh-114122)
1 parent a8e86ef commit a0a5708

File tree

9 files changed

+32
-48
lines changed

9 files changed

+32
-48
lines changed

Include/internal/pycore_context.h

+2-18
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
# error "this header requires Py_BUILD_CORE define"
66
#endif
77

8+
#include "pycore_freelist.h" // _PyFreeListState
89
#include "pycore_hamt.h" // PyHamtObject
910

1011

@@ -13,7 +14,7 @@ extern PyTypeObject _PyContextTokenMissing_Type;
1314
/* runtime lifecycle */
1415

1516
PyStatus _PyContext_Init(PyInterpreterState *);
16-
void _PyContext_Fini(PyInterpreterState *);
17+
void _PyContext_Fini(_PyFreeListState *);
1718

1819

1920
/* other API */
@@ -22,23 +23,6 @@ typedef struct {
2223
PyObject_HEAD
2324
} _PyContextTokenMissing;
2425

25-
#ifndef WITH_FREELISTS
26-
// without freelists
27-
# define PyContext_MAXFREELIST 0
28-
#endif
29-
30-
#ifndef PyContext_MAXFREELIST
31-
# define PyContext_MAXFREELIST 255
32-
#endif
33-
34-
struct _Py_context_state {
35-
#if PyContext_MAXFREELIST > 0
36-
// List of free PyContext objects
37-
PyContext *freelist;
38-
int numfree;
39-
#endif
40-
};
41-
4226
struct _pycontextobject {
4327
PyObject_HEAD
4428
PyContext *ctx_prev;

Include/internal/pycore_freelist.h

+11
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@ extern "C" {
1818
# define PyTuple_MAXFREELIST 2000
1919
# define PyList_MAXFREELIST 80
2020
# define PyFloat_MAXFREELIST 100
21+
# define PyContext_MAXFREELIST 255
2122
#else
2223
# define PyTuple_NFREELISTS 0
2324
# define PyTuple_MAXFREELIST 0
2425
# define PyList_MAXFREELIST 0
2526
# define PyFloat_MAXFREELIST 0
27+
# define PyContext_MAXFREELIST 0
2628
#endif
2729

2830
struct _Py_list_state {
@@ -67,11 +69,20 @@ struct _Py_slice_state {
6769
#endif
6870
};
6971

72+
struct _Py_context_state {
73+
#ifdef WITH_FREELISTS
74+
// List of free PyContext objects
75+
PyContext *freelist;
76+
int numfree;
77+
#endif
78+
};
79+
7080
typedef struct _Py_freelist_state {
7181
struct _Py_float_state float_state;
7282
struct _Py_tuple_state tuple_state;
7383
struct _Py_list_state list_state;
7484
struct _Py_slice_state slice_state;
85+
struct _Py_context_state context_state;
7586
} _PyFreeListState;
7687

7788
#ifdef __cplusplus

Include/internal/pycore_gc.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ extern void _PyList_ClearFreeList(_PyFreeListState *state, int is_finalization);
252252
extern void _PySlice_ClearCache(_PyFreeListState *state);
253253
extern void _PyDict_ClearFreeList(PyInterpreterState *interp);
254254
extern void _PyAsyncGen_ClearFreeLists(PyInterpreterState *interp);
255-
extern void _PyContext_ClearFreeList(PyInterpreterState *interp);
255+
extern void _PyContext_ClearFreeList(_PyFreeListState *state, int is_finalization);
256256
extern void _Py_ScheduleGC(PyInterpreterState *interp);
257257
extern void _Py_RunGC(PyThreadState *tstate);
258258

Include/internal/pycore_interp.h

-1
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,6 @@ struct _is {
191191
struct _Py_tuple_state tuple;
192192
struct _Py_dict_state dict_state;
193193
struct _Py_async_gen_state async_gen;
194-
struct _Py_context_state context;
195194
struct _Py_exc_state exc_state;
196195

197196
struct ast_state ast;

Python/context.c

+16-25
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,12 @@ static int
6464
contextvar_del(PyContextVar *var);
6565

6666

67-
#if PyContext_MAXFREELIST > 0
67+
#ifdef WITH_FREELISTS
6868
static struct _Py_context_state *
6969
get_context_state(void)
7070
{
71-
PyInterpreterState *interp = _PyInterpreterState_GET();
72-
return &interp->context;
71+
_PyFreeListState *state = _PyFreeListState_GET();
72+
return &state->context_state;
7373
}
7474
#endif
7575

@@ -340,13 +340,9 @@ static inline PyContext *
340340
_context_alloc(void)
341341
{
342342
PyContext *ctx;
343-
#if PyContext_MAXFREELIST > 0
343+
#ifdef WITH_FREELISTS
344344
struct _Py_context_state *state = get_context_state();
345-
#ifdef Py_DEBUG
346-
// _context_alloc() must not be called after _PyContext_Fini()
347-
assert(state->numfree != -1);
348-
#endif
349-
if (state->numfree) {
345+
if (state->numfree > 0) {
350346
state->numfree--;
351347
ctx = state->freelist;
352348
state->freelist = (PyContext *)ctx->ctx_weakreflist;
@@ -471,13 +467,9 @@ context_tp_dealloc(PyContext *self)
471467
}
472468
(void)context_tp_clear(self);
473469

474-
#if PyContext_MAXFREELIST > 0
470+
#ifdef WITH_FREELISTS
475471
struct _Py_context_state *state = get_context_state();
476-
#ifdef Py_DEBUG
477-
// _context_alloc() must not be called after _PyContext_Fini()
478-
assert(state->numfree != -1);
479-
#endif
480-
if (state->numfree < PyContext_MAXFREELIST) {
472+
if (state->numfree >= 0 && state->numfree < PyContext_MAXFREELIST) {
481473
state->numfree++;
482474
self->ctx_weakreflist = (PyObject *)state->freelist;
483475
state->freelist = self;
@@ -1275,28 +1267,27 @@ get_token_missing(void)
12751267

12761268

12771269
void
1278-
_PyContext_ClearFreeList(PyInterpreterState *interp)
1270+
_PyContext_ClearFreeList(_PyFreeListState *freelist_state, int is_finalization)
12791271
{
1280-
#if PyContext_MAXFREELIST > 0
1281-
struct _Py_context_state *state = &interp->context;
1282-
for (; state->numfree; state->numfree--) {
1272+
#ifdef WITH_FREELISTS
1273+
struct _Py_context_state *state = &freelist_state->context_state;
1274+
for (; state->numfree > 0; state->numfree--) {
12831275
PyContext *ctx = state->freelist;
12841276
state->freelist = (PyContext *)ctx->ctx_weakreflist;
12851277
ctx->ctx_weakreflist = NULL;
12861278
PyObject_GC_Del(ctx);
12871279
}
1280+
if (is_finalization) {
1281+
state->numfree = -1;
1282+
}
12881283
#endif
12891284
}
12901285

12911286

12921287
void
1293-
_PyContext_Fini(PyInterpreterState *interp)
1288+
_PyContext_Fini(_PyFreeListState *state)
12941289
{
1295-
_PyContext_ClearFreeList(interp);
1296-
#if defined(Py_DEBUG) && PyContext_MAXFREELIST > 0
1297-
struct _Py_context_state *state = &interp->context;
1298-
state->numfree = -1;
1299-
#endif
1290+
_PyContext_ClearFreeList(state, 1);
13001291
}
13011292

13021293

Python/gc_free_threading.c

-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ _PyGC_ClearAllFreeLists(PyInterpreterState *interp)
1616
{
1717
_PyDict_ClearFreeList(interp);
1818
_PyAsyncGen_ClearFreeLists(interp);
19-
_PyContext_ClearFreeList(interp);
2019

2120
HEAD_LOCK(&_PyRuntime);
2221
_PyThreadStateImpl *tstate = (_PyThreadStateImpl *)interp->threads.head;

Python/gc_gil.c

-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ _PyGC_ClearAllFreeLists(PyInterpreterState *interp)
1313
{
1414
_PyDict_ClearFreeList(interp);
1515
_PyAsyncGen_ClearFreeLists(interp);
16-
_PyContext_ClearFreeList(interp);
1716

1817
_Py_ClearFreeLists(&interp->freelist_state, 0);
1918
}

Python/pylifecycle.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1736,7 +1736,6 @@ finalize_interp_types(PyInterpreterState *interp)
17361736
_PyXI_FiniTypes(interp);
17371737
_PyExc_Fini(interp);
17381738
_PyAsyncGen_Fini(interp);
1739-
_PyContext_Fini(interp);
17401739
_PyFloat_FiniType(interp);
17411740
_PyLong_FiniTypes(interp);
17421741
_PyThread_FiniType(interp);
@@ -1759,6 +1758,7 @@ finalize_interp_types(PyInterpreterState *interp)
17591758
_PyList_Fini(state);
17601759
_PyFloat_Fini(state);
17611760
_PySlice_Fini(state);
1761+
_PyContext_Fini(state);
17621762

17631763
#ifdef Py_DEBUG
17641764
_PyStaticObjects_CheckRefcnt(interp);

Python/pystate.c

+1
Original file line numberDiff line numberDiff line change
@@ -1461,6 +1461,7 @@ _Py_ClearFreeLists(_PyFreeListState *state, int is_finalization)
14611461
_PyFloat_ClearFreeList(state, is_finalization);
14621462
_PyTuple_ClearFreeList(state, is_finalization);
14631463
_PyList_ClearFreeList(state, is_finalization);
1464+
_PyContext_ClearFreeList(state, is_finalization);
14641465
}
14651466

14661467
void

0 commit comments

Comments
 (0)