From c8a3d391755aa4cf3b4d5e350a4ff7ffd9101ab4 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Fri, 2 Feb 2024 19:12:46 +0900 Subject: [PATCH 01/13] gh-111968: Refactor _PyXXX_Fini to follow Eric's suggestion --- Include/internal/pycore_context.h | 2 +- Include/internal/pycore_floatobject.h | 2 +- Include/internal/pycore_gc.h | 2 +- Include/internal/pycore_genobject.h | 2 +- Include/internal/pycore_list.h | 2 +- Include/internal/pycore_sliceobject.h | 2 +- Include/internal/pycore_tuple.h | 2 +- Objects/floatobject.c | 3 ++- Objects/genobject.c | 3 ++- Objects/listobject.c | 3 ++- Objects/sliceobject.c | 10 +++++++--- Objects/tupleobject.c | 7 ++++++- Python/context.c | 3 ++- Python/pylifecycle.c | 15 +++++++-------- Python/pystate.c | 2 +- 15 files changed, 36 insertions(+), 24 deletions(-) diff --git a/Include/internal/pycore_context.h b/Include/internal/pycore_context.h index 3284efba2b6f4c..e21eb00fb33b74 100644 --- a/Include/internal/pycore_context.h +++ b/Include/internal/pycore_context.h @@ -14,7 +14,7 @@ extern PyTypeObject _PyContextTokenMissing_Type; /* runtime lifecycle */ PyStatus _PyContext_Init(PyInterpreterState *); -void _PyContext_Fini(_PyFreeListState *); +void _PyContext_Fini(PyInterpreterState *); /* other API */ diff --git a/Include/internal/pycore_floatobject.h b/Include/internal/pycore_floatobject.h index 038578e1f9680a..f1b4c4def37739 100644 --- a/Include/internal/pycore_floatobject.h +++ b/Include/internal/pycore_floatobject.h @@ -15,7 +15,7 @@ extern "C" { extern void _PyFloat_InitState(PyInterpreterState *); extern PyStatus _PyFloat_InitTypes(PyInterpreterState *); -extern void _PyFloat_Fini(_PyFreeListState *); +extern void _PyFloat_Fini(PyInterpreterState *); extern void _PyFloat_FiniType(PyInterpreterState *); diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index ca1d9fdf5253b8..713cd1e647d5ed 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -266,7 +266,7 @@ extern void _Py_ClearFreeLists(_PyFreeListState *state, int is_finalization); extern void _PyTuple_ClearFreeList(_PyFreeListState *state, int is_finalization); extern void _PyFloat_ClearFreeList(_PyFreeListState *state, int is_finalization); extern void _PyList_ClearFreeList(_PyFreeListState *state, int is_finalization); -extern void _PySlice_ClearCache(_PyFreeListState *state); +extern void _PySlice_ClearCache(_PyFreeListState *state, int is_finalization); extern void _PyDict_ClearFreeList(_PyFreeListState *state, int is_finalization); extern void _PyAsyncGen_ClearFreeLists(_PyFreeListState *state, int is_finalization); extern void _PyContext_ClearFreeList(_PyFreeListState *state, int is_finalization); diff --git a/Include/internal/pycore_genobject.h b/Include/internal/pycore_genobject.h index 5ad63658051e86..33ba65dbf1fc1f 100644 --- a/Include/internal/pycore_genobject.h +++ b/Include/internal/pycore_genobject.h @@ -28,7 +28,7 @@ extern PyTypeObject _PyAsyncGenAThrow_Type; /* runtime lifecycle */ -extern void _PyAsyncGen_Fini(_PyFreeListState *); +extern void _PyAsyncGen_Fini(PyInterpreterState *); #ifdef __cplusplus } diff --git a/Include/internal/pycore_list.h b/Include/internal/pycore_list.h index 4536f90e414493..2e636f88ff8732 100644 --- a/Include/internal/pycore_list.h +++ b/Include/internal/pycore_list.h @@ -16,7 +16,7 @@ extern void _PyList_DebugMallocStats(FILE *out); /* runtime lifecycle */ -extern void _PyList_Fini(_PyFreeListState *); +extern void _PyList_Fini(PyInterpreterState *); #define _PyList_ITEMS(op) _Py_RVALUE(_PyList_CAST(op)->ob_item) diff --git a/Include/internal/pycore_sliceobject.h b/Include/internal/pycore_sliceobject.h index 0c72d3ee6225c5..98665c3859d574 100644 --- a/Include/internal/pycore_sliceobject.h +++ b/Include/internal/pycore_sliceobject.h @@ -11,7 +11,7 @@ extern "C" { /* runtime lifecycle */ -extern void _PySlice_Fini(_PyFreeListState *); +extern void _PySlice_Fini(PyInterpreterState *); extern PyObject * _PyBuildSlice_ConsumeRefs(PyObject *start, PyObject *stop); diff --git a/Include/internal/pycore_tuple.h b/Include/internal/pycore_tuple.h index b348339a505b0f..bc3a4ea20fe0d5 100644 --- a/Include/internal/pycore_tuple.h +++ b/Include/internal/pycore_tuple.h @@ -14,7 +14,7 @@ extern void _PyTuple_DebugMallocStats(FILE *out); /* runtime lifecycle */ extern PyStatus _PyTuple_InitGlobalObjects(PyInterpreterState *); -extern void _PyTuple_Fini(_PyFreeListState *); +extern void _PyTuple_Fini(PyInterpreterState *); /* other API */ diff --git a/Objects/floatobject.c b/Objects/floatobject.c index c440e0dab0e79f..a3a4bb82154d07 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -2011,11 +2011,12 @@ _PyFloat_ClearFreeList(_PyFreeListState *freelist_state, int is_finalization) } void -_PyFloat_Fini(_PyFreeListState *state) +_PyFloat_Fini(PyInterpreterState *Py_UNUSED(interp)) { // With Py_GIL_DISABLED: // the freelists for the current thread state have already been cleared. #ifndef Py_GIL_DISABLED + _PyFreeListState *state = _PyFreeListState_GET(); _PyFloat_ClearFreeList(state, 1); #endif } diff --git a/Objects/genobject.c b/Objects/genobject.c index ab523e46cceaa3..c4675426720477 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -1683,11 +1683,12 @@ _PyAsyncGen_ClearFreeLists(_PyFreeListState *freelist_state, int is_finalization } void -_PyAsyncGen_Fini(_PyFreeListState *state) +_PyAsyncGen_Fini(PyInterpreterState *Py_UNUSED(interp)) { // With Py_GIL_DISABLED: // the freelists for the current thread state have already been cleared. #ifndef Py_GIL_DISABLED + _PyFreeListState *state = _PyFreeListState_GET(); _PyAsyncGen_ClearFreeLists(state, 1); #endif } diff --git a/Objects/listobject.c b/Objects/listobject.c index da2b9cc32697dd..c2a0a9ec48189f 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -136,11 +136,12 @@ _PyList_ClearFreeList(_PyFreeListState *freelist_state, int is_finalization) } void -_PyList_Fini(_PyFreeListState *state) +_PyList_Fini(PyInterpreterState *Py_UNUSED(interp)) { // With Py_GIL_DISABLED: // the freelists for the current thread state have already been cleared. #ifndef Py_GIL_DISABLED + _PyFreeListState *state = _PyFreeListState_GET(); _PyList_ClearFreeList(state, 1); #endif } diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c index 8b9d6bbfd858b7..d6beac53b7715c 100644 --- a/Objects/sliceobject.c +++ b/Objects/sliceobject.c @@ -103,8 +103,11 @@ PyObject _Py_EllipsisObject = _PyObject_HEAD_INIT(&PyEllipsis_Type); /* Slice object implementation */ -void _PySlice_ClearCache(_PyFreeListState *state) +void _PySlice_ClearCache(_PyFreeListState *state, int is_finalization) { + if (!is_finalization) { + return; + } #ifdef WITH_FREELISTS PySliceObject *obj = state->slices.slice_cache; if (obj != NULL) { @@ -114,10 +117,11 @@ void _PySlice_ClearCache(_PyFreeListState *state) #endif } -void _PySlice_Fini(_PyFreeListState *state) +void _PySlice_Fini(PyInterpreterState *Py_UNUSED(interp)) { #ifdef WITH_FREELISTS - _PySlice_ClearCache(state); + _PyFreeListState *state = _PyFreeListState_GET(); + _PySlice_ClearCache(state, 1); #endif } diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index b9bf6cd48f6129..a6b52da7bfa59e 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -965,9 +965,14 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize) static void maybe_freelist_clear(_PyFreeListState *, int); void -_PyTuple_Fini(_PyFreeListState *state) +_PyTuple_Fini(PyInterpreterState *Py_UNUSED(interp)) { + // With Py_GIL_DISABLED: + // the freelists for the current thread state have already been cleared. +#ifndef Py_GIL_DISABLED + _PyFreeListState *state = _PyFreeListState_GET(); maybe_freelist_clear(state, 1); +#endif } void diff --git a/Python/context.c b/Python/context.c index 793dfa2b72c7e3..1d298d9c79404b 100644 --- a/Python/context.c +++ b/Python/context.c @@ -1285,11 +1285,12 @@ _PyContext_ClearFreeList(_PyFreeListState *freelist_state, int is_finalization) void -_PyContext_Fini(_PyFreeListState *state) +_PyContext_Fini(PyInterpreterState *Py_UNUSED(interp)) { // With Py_GIL_DISABLED: // the freelists for the current thread state have already been cleared. #ifndef Py_GIL_DISABLED + _PyFreeListState *state = _PyFreeListState_GET(); _PyContext_ClearFreeList(state, 1); #endif } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 372f60602375b6..7b30f3dd2f104b 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1782,16 +1782,15 @@ finalize_interp_types(PyInterpreterState *interp) // a dict internally. _PyUnicode_ClearInterned(interp); - _PyDict_Fini(interp); _PyUnicode_Fini(interp); - _PyFreeListState *state = _PyFreeListState_GET(); - _PyTuple_Fini(state); - _PyList_Fini(state); - _PyFloat_Fini(state); - _PySlice_Fini(state); - _PyContext_Fini(state); - _PyAsyncGen_Fini(state); + _PyTuple_Fini(interp); + _PyList_Fini(interp); + _PyDict_Fini(interp); + _PyFloat_Fini(interp); + _PySlice_Fini(interp); + _PyContext_Fini(interp); + _PyAsyncGen_Fini(interp); #ifdef Py_DEBUG _PyStaticObjects_CheckRefcnt(interp); diff --git a/Python/pystate.c b/Python/pystate.c index 27b6d0573ade3b..d46b367b7d1ca5 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1470,6 +1470,7 @@ _Py_ClearFreeLists(_PyFreeListState *state, int is_finalization) _PyContext_ClearFreeList(state, is_finalization); _PyAsyncGen_ClearFreeLists(state, is_finalization); _PyObjectStackChunk_ClearFreeList(state, is_finalization); + _PySlice_ClearCache(state, is_finalization); } void @@ -1558,7 +1559,6 @@ PyThreadState_Clear(PyThreadState *tstate) // Each thread should clear own freelists in free-threading builds. _PyFreeListState *freelist_state = &((_PyThreadStateImpl*)tstate)->freelist_state; _Py_ClearFreeLists(freelist_state, 1); - _PySlice_ClearCache(freelist_state); #endif _PyThreadState_ClearMimallocHeaps(tstate); From 944929e13d98aaafe8efa4e66f80081653d4065c Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Fri, 2 Feb 2024 19:32:11 +0900 Subject: [PATCH 02/13] Remove _PyXXX_Fini --- Include/internal/pycore_context.h | 1 - Include/internal/pycore_floatobject.h | 1 - Include/internal/pycore_genobject.h | 4 ---- Include/internal/pycore_list.h | 6 ------ Include/internal/pycore_sliceobject.h | 2 -- Include/internal/pycore_tuple.h | 1 - Objects/floatobject.c | 11 ----------- Objects/genobject.c | 12 ------------ Objects/listobject.c | 11 ----------- Python/pylifecycle.c | 13 ++++++------- 10 files changed, 6 insertions(+), 56 deletions(-) diff --git a/Include/internal/pycore_context.h b/Include/internal/pycore_context.h index e21eb00fb33b74..ae5c47f195eb7f 100644 --- a/Include/internal/pycore_context.h +++ b/Include/internal/pycore_context.h @@ -14,7 +14,6 @@ extern PyTypeObject _PyContextTokenMissing_Type; /* runtime lifecycle */ PyStatus _PyContext_Init(PyInterpreterState *); -void _PyContext_Fini(PyInterpreterState *); /* other API */ diff --git a/Include/internal/pycore_floatobject.h b/Include/internal/pycore_floatobject.h index f1b4c4def37739..3767df5506d43f 100644 --- a/Include/internal/pycore_floatobject.h +++ b/Include/internal/pycore_floatobject.h @@ -15,7 +15,6 @@ extern "C" { extern void _PyFloat_InitState(PyInterpreterState *); extern PyStatus _PyFloat_InitTypes(PyInterpreterState *); -extern void _PyFloat_Fini(PyInterpreterState *); extern void _PyFloat_FiniType(PyInterpreterState *); diff --git a/Include/internal/pycore_genobject.h b/Include/internal/pycore_genobject.h index 33ba65dbf1fc1f..b2aa017598409f 100644 --- a/Include/internal/pycore_genobject.h +++ b/Include/internal/pycore_genobject.h @@ -26,10 +26,6 @@ extern PyTypeObject _PyCoroWrapper_Type; extern PyTypeObject _PyAsyncGenWrappedValue_Type; extern PyTypeObject _PyAsyncGenAThrow_Type; -/* runtime lifecycle */ - -extern void _PyAsyncGen_Fini(PyInterpreterState *); - #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_list.h b/Include/internal/pycore_list.h index 2e636f88ff8732..50dc13c4da4487 100644 --- a/Include/internal/pycore_list.h +++ b/Include/internal/pycore_list.h @@ -13,12 +13,6 @@ extern "C" { extern PyObject* _PyList_Extend(PyListObject *, PyObject *); extern void _PyList_DebugMallocStats(FILE *out); - -/* runtime lifecycle */ - -extern void _PyList_Fini(PyInterpreterState *); - - #define _PyList_ITEMS(op) _Py_RVALUE(_PyList_CAST(op)->ob_item) extern int diff --git a/Include/internal/pycore_sliceobject.h b/Include/internal/pycore_sliceobject.h index 98665c3859d574..89086f67683a2f 100644 --- a/Include/internal/pycore_sliceobject.h +++ b/Include/internal/pycore_sliceobject.h @@ -11,8 +11,6 @@ extern "C" { /* runtime lifecycle */ -extern void _PySlice_Fini(PyInterpreterState *); - extern PyObject * _PyBuildSlice_ConsumeRefs(PyObject *start, PyObject *stop); diff --git a/Include/internal/pycore_tuple.h b/Include/internal/pycore_tuple.h index bc3a4ea20fe0d5..4605f355ccbc38 100644 --- a/Include/internal/pycore_tuple.h +++ b/Include/internal/pycore_tuple.h @@ -14,7 +14,6 @@ extern void _PyTuple_DebugMallocStats(FILE *out); /* runtime lifecycle */ extern PyStatus _PyTuple_InitGlobalObjects(PyInterpreterState *); -extern void _PyTuple_Fini(PyInterpreterState *); /* other API */ diff --git a/Objects/floatobject.c b/Objects/floatobject.c index a3a4bb82154d07..9b322c52d4daea 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -2010,17 +2010,6 @@ _PyFloat_ClearFreeList(_PyFreeListState *freelist_state, int is_finalization) #endif } -void -_PyFloat_Fini(PyInterpreterState *Py_UNUSED(interp)) -{ - // With Py_GIL_DISABLED: - // the freelists for the current thread state have already been cleared. -#ifndef Py_GIL_DISABLED - _PyFreeListState *state = _PyFreeListState_GET(); - _PyFloat_ClearFreeList(state, 1); -#endif -} - void _PyFloat_FiniType(PyInterpreterState *interp) { diff --git a/Objects/genobject.c b/Objects/genobject.c index c4675426720477..59ab7abf6180bd 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -1682,18 +1682,6 @@ _PyAsyncGen_ClearFreeLists(_PyFreeListState *freelist_state, int is_finalization #endif } -void -_PyAsyncGen_Fini(PyInterpreterState *Py_UNUSED(interp)) -{ - // With Py_GIL_DISABLED: - // the freelists for the current thread state have already been cleared. -#ifndef Py_GIL_DISABLED - _PyFreeListState *state = _PyFreeListState_GET(); - _PyAsyncGen_ClearFreeLists(state, 1); -#endif -} - - static PyObject * async_gen_unwrap_value(PyAsyncGenObject *gen, PyObject *result) { diff --git a/Objects/listobject.c b/Objects/listobject.c index c2a0a9ec48189f..9d16fec51ae01e 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -135,17 +135,6 @@ _PyList_ClearFreeList(_PyFreeListState *freelist_state, int is_finalization) #endif } -void -_PyList_Fini(PyInterpreterState *Py_UNUSED(interp)) -{ - // With Py_GIL_DISABLED: - // the freelists for the current thread state have already been cleared. -#ifndef Py_GIL_DISABLED - _PyFreeListState *state = _PyFreeListState_GET(); - _PyList_ClearFreeList(state, 1); -#endif -} - /* Print summary info about the state of the optimized allocator */ void _PyList_DebugMallocStats(FILE *out) diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 7b30f3dd2f104b..d763ddbb5a42f4 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1784,13 +1784,12 @@ finalize_interp_types(PyInterpreterState *interp) _PyUnicode_Fini(interp); - _PyTuple_Fini(interp); - _PyList_Fini(interp); - _PyDict_Fini(interp); - _PyFloat_Fini(interp); - _PySlice_Fini(interp); - _PyContext_Fini(interp); - _PyAsyncGen_Fini(interp); +#ifndef Py_GIL_DISABLED + // With Py_GIL_DISABLED: + // the freelists for the current thread state have already been cleared. + _PyFreeListState *state = _PyFreeListState_GET(); + _Py_ClearFreeLists(state, 1); +#endif #ifdef Py_DEBUG _PyStaticObjects_CheckRefcnt(interp); From 6ec90f5ff4499402ce6cff6eece5abd090608594 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Fri, 2 Feb 2024 19:34:00 +0900 Subject: [PATCH 03/13] nit --- Python/context.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/Python/context.c b/Python/context.c index 1d298d9c79404b..e44fef705c36e0 100644 --- a/Python/context.c +++ b/Python/context.c @@ -1284,18 +1284,6 @@ _PyContext_ClearFreeList(_PyFreeListState *freelist_state, int is_finalization) } -void -_PyContext_Fini(PyInterpreterState *Py_UNUSED(interp)) -{ - // With Py_GIL_DISABLED: - // the freelists for the current thread state have already been cleared. -#ifndef Py_GIL_DISABLED - _PyFreeListState *state = _PyFreeListState_GET(); - _PyContext_ClearFreeList(state, 1); -#endif -} - - PyStatus _PyContext_Init(PyInterpreterState *interp) { From c4b3f4f5cdfe781244e33efb7780b4767a06cbe8 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Fri, 2 Feb 2024 19:35:41 +0900 Subject: [PATCH 04/13] nit --- Objects/sliceobject.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c index d6beac53b7715c..96e3aa97f7f0ff 100644 --- a/Objects/sliceobject.c +++ b/Objects/sliceobject.c @@ -117,14 +117,6 @@ void _PySlice_ClearCache(_PyFreeListState *state, int is_finalization) #endif } -void _PySlice_Fini(PyInterpreterState *Py_UNUSED(interp)) -{ -#ifdef WITH_FREELISTS - _PyFreeListState *state = _PyFreeListState_GET(); - _PySlice_ClearCache(state, 1); -#endif -} - /* start, stop, and step are python objects with None indicating no index is present. */ From c91a3e7b3015406a5ae6137d01ff201c4ed426b0 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Fri, 2 Feb 2024 19:38:34 +0900 Subject: [PATCH 05/13] Refactor to use _PyObject_ClearFreeLists --- Include/internal/pycore_gc.h | 2 +- Python/gc_gil.c | 2 +- Python/pylifecycle.c | 2 +- Python/pystate.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index 713cd1e647d5ed..43903d623decff 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -262,7 +262,7 @@ extern PyObject *_PyGC_GetReferrers(PyInterpreterState *interp, PyObject *objs); // Functions to clear types free lists extern void _PyGC_ClearAllFreeLists(PyInterpreterState *interp); -extern void _Py_ClearFreeLists(_PyFreeListState *state, int is_finalization); +extern void _PyObject_ClearFreeLists(_PyFreeListState *state, int is_finalization); extern void _PyTuple_ClearFreeList(_PyFreeListState *state, int is_finalization); extern void _PyFloat_ClearFreeList(_PyFreeListState *state, int is_finalization); extern void _PyList_ClearFreeList(_PyFreeListState *state, int is_finalization); diff --git a/Python/gc_gil.c b/Python/gc_gil.c index 4e2aa8f7af746c..5f1365f509deb0 100644 --- a/Python/gc_gil.c +++ b/Python/gc_gil.c @@ -11,7 +11,7 @@ void _PyGC_ClearAllFreeLists(PyInterpreterState *interp) { - _Py_ClearFreeLists(&interp->freelist_state, 0); + _PyObject_ClearFreeLists(&interp->freelist_state, 0); } #endif diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index d763ddbb5a42f4..fc4fa3c2292276 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1788,7 +1788,7 @@ finalize_interp_types(PyInterpreterState *interp) // With Py_GIL_DISABLED: // the freelists for the current thread state have already been cleared. _PyFreeListState *state = _PyFreeListState_GET(); - _Py_ClearFreeLists(state, 1); + _PyObject_ClearFreeLists(state, 1); #endif #ifdef Py_DEBUG diff --git a/Python/pystate.c b/Python/pystate.c index d46b367b7d1ca5..5981c2be39b1f9 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1459,7 +1459,7 @@ clear_datastack(PyThreadState *tstate) } void -_Py_ClearFreeLists(_PyFreeListState *state, int is_finalization) +_PyObject_ClearFreeLists(_PyFreeListState *state, int is_finalization) { // In the free-threaded build, freelists are per-PyThreadState and cleared in PyThreadState_Clear() // In the default build, freelists are per-interpreter and cleared in finalize_interp_types() From 16c72bfa2b2f843694652983be0aebd843479976 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Fri, 2 Feb 2024 19:40:51 +0900 Subject: [PATCH 06/13] nit --- Objects/tupleobject.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index a6b52da7bfa59e..7d73c3fb0f7f2c 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -964,16 +964,6 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize) static void maybe_freelist_clear(_PyFreeListState *, int); -void -_PyTuple_Fini(PyInterpreterState *Py_UNUSED(interp)) -{ - // With Py_GIL_DISABLED: - // the freelists for the current thread state have already been cleared. -#ifndef Py_GIL_DISABLED - _PyFreeListState *state = _PyFreeListState_GET(); - maybe_freelist_clear(state, 1); -#endif -} void _PyTuple_ClearFreeList(_PyFreeListState *state, int is_finalization) From f4bdc2e18e4a4b9c89cc11ed89082ea04aa441d7 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Fri, 2 Feb 2024 19:41:54 +0900 Subject: [PATCH 07/13] Add comment --- Python/pystate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Python/pystate.c b/Python/pystate.c index 5981c2be39b1f9..80f0fd744bfa74 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1469,6 +1469,7 @@ _PyObject_ClearFreeLists(_PyFreeListState *state, int is_finalization) _PyDict_ClearFreeList(state, is_finalization); _PyContext_ClearFreeList(state, is_finalization); _PyAsyncGen_ClearFreeLists(state, is_finalization); + // Only be cleared if is_finalization is true. _PyObjectStackChunk_ClearFreeList(state, is_finalization); _PySlice_ClearCache(state, is_finalization); } From 47976a27d0a071b32f5ffba89e455f10f292e3df Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Fri, 2 Feb 2024 19:51:25 +0900 Subject: [PATCH 08/13] Fix --- Python/gc_free_threading.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c index 8fbcdb15109b76..3a2e5c5250d5fe 100644 --- a/Python/gc_free_threading.c +++ b/Python/gc_free_threading.c @@ -1679,7 +1679,7 @@ _PyGC_ClearAllFreeLists(PyInterpreterState *interp) HEAD_LOCK(&_PyRuntime); _PyThreadStateImpl *tstate = (_PyThreadStateImpl *)interp->threads.head; while (tstate != NULL) { - _Py_ClearFreeLists(&tstate->freelist_state, 0); + _PyObject_ClearFreeLists(&tstate->freelist_state, 0); tstate = (_PyThreadStateImpl *)tstate->base.next; } HEAD_UNLOCK(&_PyRuntime); From 42ba4b96b48e2e99778dc48ff40f06615451b7a0 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Fri, 2 Feb 2024 19:57:48 +0900 Subject: [PATCH 09/13] fix --- Python/pystate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/pystate.c b/Python/pystate.c index 80f0fd744bfa74..ea37b4017105d9 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1559,7 +1559,7 @@ PyThreadState_Clear(PyThreadState *tstate) #ifdef Py_GIL_DISABLED // Each thread should clear own freelists in free-threading builds. _PyFreeListState *freelist_state = &((_PyThreadStateImpl*)tstate)->freelist_state; - _Py_ClearFreeLists(freelist_state, 1); + _PyObject_ClearFreeLists(freelist_state, 1); #endif _PyThreadState_ClearMimallocHeaps(tstate); From 4585c90bd3556be4ed0d3a5b4960adfa29889c68 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sat, 3 Feb 2024 17:56:40 +0900 Subject: [PATCH 10/13] Rename _PySlice_ClearCache to _PySlice_ClearFreeList --- Include/internal/pycore_gc.h | 2 +- Objects/sliceobject.c | 2 +- Python/pystate.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index 43903d623decff..6904ca3f5571e9 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -266,7 +266,7 @@ extern void _PyObject_ClearFreeLists(_PyFreeListState *state, int is_finalizatio extern void _PyTuple_ClearFreeList(_PyFreeListState *state, int is_finalization); extern void _PyFloat_ClearFreeList(_PyFreeListState *state, int is_finalization); extern void _PyList_ClearFreeList(_PyFreeListState *state, int is_finalization); -extern void _PySlice_ClearCache(_PyFreeListState *state, int is_finalization); +extern void _PySlice_ClearFreeList(_PyFreeListState *state, int is_finalization); extern void _PyDict_ClearFreeList(_PyFreeListState *state, int is_finalization); extern void _PyAsyncGen_ClearFreeLists(_PyFreeListState *state, int is_finalization); extern void _PyContext_ClearFreeList(_PyFreeListState *state, int is_finalization); diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c index 96e3aa97f7f0ff..9880c123c80f95 100644 --- a/Objects/sliceobject.c +++ b/Objects/sliceobject.c @@ -103,7 +103,7 @@ PyObject _Py_EllipsisObject = _PyObject_HEAD_INIT(&PyEllipsis_Type); /* Slice object implementation */ -void _PySlice_ClearCache(_PyFreeListState *state, int is_finalization) +void _PySlice_ClearFreeList(_PyFreeListState *state, int is_finalization) { if (!is_finalization) { return; diff --git a/Python/pystate.c b/Python/pystate.c index ea37b4017105d9..13f47046e645c6 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1471,7 +1471,7 @@ _PyObject_ClearFreeLists(_PyFreeListState *state, int is_finalization) _PyAsyncGen_ClearFreeLists(state, is_finalization); // Only be cleared if is_finalization is true. _PyObjectStackChunk_ClearFreeList(state, is_finalization); - _PySlice_ClearCache(state, is_finalization); + _PySlice_ClearFreeList(state, is_finalization); } void From a121247442b6ea43cf4e96d38d36327970d25e31 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sat, 3 Feb 2024 17:57:58 +0900 Subject: [PATCH 11/13] Address code review --- Python/pystate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/pystate.c b/Python/pystate.c index 13f47046e645c6..d84f3eed2058a7 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1558,7 +1558,7 @@ PyThreadState_Clear(PyThreadState *tstate) } #ifdef Py_GIL_DISABLED // Each thread should clear own freelists in free-threading builds. - _PyFreeListState *freelist_state = &((_PyThreadStateImpl*)tstate)->freelist_state; + _PyFreeListState *freelist_state = _PyFreeListState_GET(); _PyObject_ClearFreeLists(freelist_state, 1); #endif From 845acac503b627a6f7c2765da41d03fbd0cc54f5 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sat, 3 Feb 2024 18:05:33 +0900 Subject: [PATCH 12/13] Relocate _PyXXX_ClearFreeList declaration --- Include/internal/pycore_freelist.h | 10 ++++++++++ Include/internal/pycore_gc.h | 8 -------- Include/internal/pycore_object_stack.h | 3 --- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Include/internal/pycore_freelist.h b/Include/internal/pycore_freelist.h index 82a42300991ecc..1bc551914794f0 100644 --- a/Include/internal/pycore_freelist.h +++ b/Include/internal/pycore_freelist.h @@ -125,6 +125,16 @@ typedef struct _Py_freelist_state { struct _Py_object_stack_state object_stacks; } _PyFreeListState; +extern void _PyObject_ClearFreeLists(_PyFreeListState *state, int is_finalization); +extern void _PyTuple_ClearFreeList(_PyFreeListState *state, int is_finalization); +extern void _PyFloat_ClearFreeList(_PyFreeListState *state, int is_finalization); +extern void _PyList_ClearFreeList(_PyFreeListState *state, int is_finalization); +extern void _PySlice_ClearFreeList(_PyFreeListState *state, int is_finalization); +extern void _PyDict_ClearFreeList(_PyFreeListState *state, int is_finalization); +extern void _PyAsyncGen_ClearFreeLists(_PyFreeListState *state, int is_finalization); +extern void _PyContext_ClearFreeList(_PyFreeListState *state, int is_finalization); +extern void _PyObjectStackChunk_ClearFreeList(_PyFreeListState *state, int is_finalization); + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index 6904ca3f5571e9..7d3c581bdc6b23 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -262,14 +262,6 @@ extern PyObject *_PyGC_GetReferrers(PyInterpreterState *interp, PyObject *objs); // Functions to clear types free lists extern void _PyGC_ClearAllFreeLists(PyInterpreterState *interp); -extern void _PyObject_ClearFreeLists(_PyFreeListState *state, int is_finalization); -extern void _PyTuple_ClearFreeList(_PyFreeListState *state, int is_finalization); -extern void _PyFloat_ClearFreeList(_PyFreeListState *state, int is_finalization); -extern void _PyList_ClearFreeList(_PyFreeListState *state, int is_finalization); -extern void _PySlice_ClearFreeList(_PyFreeListState *state, int is_finalization); -extern void _PyDict_ClearFreeList(_PyFreeListState *state, int is_finalization); -extern void _PyAsyncGen_ClearFreeLists(_PyFreeListState *state, int is_finalization); -extern void _PyContext_ClearFreeList(_PyFreeListState *state, int is_finalization); extern void _Py_ScheduleGC(PyInterpreterState *interp); extern void _Py_RunGC(PyThreadState *tstate); diff --git a/Include/internal/pycore_object_stack.h b/Include/internal/pycore_object_stack.h index 1dc1c1591525de..0dfeb63c687a53 100644 --- a/Include/internal/pycore_object_stack.h +++ b/Include/internal/pycore_object_stack.h @@ -32,9 +32,6 @@ _PyObjectStackChunk_New(void); extern void _PyObjectStackChunk_Free(_PyObjectStackChunk *); -extern void -_PyObjectStackChunk_ClearFreeList(_PyFreeListState *state, int is_finalization); - // Push an item onto the stack. Return -1 on allocation failure, 0 on success. static inline int _PyObjectStack_Push(_PyObjectStack *stack, PyObject *obj) From bac40eabd978df6f6cb2a2b48c932c522a8ac315 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sat, 3 Feb 2024 18:42:44 +0900 Subject: [PATCH 13/13] Address code review --- Objects/object.c | 15 +++++++++++++++ Python/pystate.c | 16 ---------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/Objects/object.c b/Objects/object.c index bbf7f98ae3daf9..2b1fa82f012a02 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -794,6 +794,21 @@ PyObject_Bytes(PyObject *v) return PyBytes_FromObject(v); } +void +_PyObject_ClearFreeLists(_PyFreeListState *state, int is_finalization) +{ + // In the free-threaded build, freelists are per-PyThreadState and cleared in PyThreadState_Clear() + // In the default build, freelists are per-interpreter and cleared in finalize_interp_types() + _PyFloat_ClearFreeList(state, is_finalization); + _PyTuple_ClearFreeList(state, is_finalization); + _PyList_ClearFreeList(state, is_finalization); + _PyDict_ClearFreeList(state, is_finalization); + _PyContext_ClearFreeList(state, is_finalization); + _PyAsyncGen_ClearFreeLists(state, is_finalization); + // Only be cleared if is_finalization is true. + _PyObjectStackChunk_ClearFreeList(state, is_finalization); + _PySlice_ClearFreeList(state, is_finalization); +} /* def _PyObject_FunctionStr(x): diff --git a/Python/pystate.c b/Python/pystate.c index d84f3eed2058a7..2267827579b5f4 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1458,22 +1458,6 @@ clear_datastack(PyThreadState *tstate) } } -void -_PyObject_ClearFreeLists(_PyFreeListState *state, int is_finalization) -{ - // In the free-threaded build, freelists are per-PyThreadState and cleared in PyThreadState_Clear() - // In the default build, freelists are per-interpreter and cleared in finalize_interp_types() - _PyFloat_ClearFreeList(state, is_finalization); - _PyTuple_ClearFreeList(state, is_finalization); - _PyList_ClearFreeList(state, is_finalization); - _PyDict_ClearFreeList(state, is_finalization); - _PyContext_ClearFreeList(state, is_finalization); - _PyAsyncGen_ClearFreeLists(state, is_finalization); - // Only be cleared if is_finalization is true. - _PyObjectStackChunk_ClearFreeList(state, is_finalization); - _PySlice_ClearFreeList(state, is_finalization); -} - void PyThreadState_Clear(PyThreadState *tstate) {