From 261cfedf7657a515e04428bba58eba2a9bb88208 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 23 Jun 2020 14:07:52 +0200 Subject: [PATCH] bpo-40521: Make the empty frozenset per interpreter (GH-21068) Each interpreter now has its own empty frozenset singleton. --- Include/internal/pycore_interp.h | 2 ++ Include/internal/pycore_pylifecycle.h | 2 +- .../2020-05-20-01-17-34.bpo-40521.wvAehI.rst | 10 ++++---- Objects/setobject.c | 25 +++++++++++-------- Python/pylifecycle.c | 4 +-- 5 files changed, 24 insertions(+), 19 deletions(-) diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 3f64edcee98..697d97a39e0 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -238,6 +238,8 @@ struct _is { /* Using a cache is very effective since typically only a single slice is created and then deleted again. */ PySliceObject *slice_cache; + // The empty frozenset is a singleton. + PyObject *empty_frozenset; struct _Py_tuple_state tuple; struct _Py_list_state list; diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h index dc997378297..83ce1d2e746 100644 --- a/Include/internal/pycore_pylifecycle.h +++ b/Include/internal/pycore_pylifecycle.h @@ -62,7 +62,7 @@ extern void _PyFrame_Fini(PyThreadState *tstate); extern void _PyDict_Fini(PyThreadState *tstate); extern void _PyTuple_Fini(PyThreadState *tstate); extern void _PyList_Fini(PyThreadState *tstate); -extern void _PySet_Fini(void); +extern void _PySet_Fini(PyThreadState *tstate); extern void _PyBytes_Fini(void); extern void _PyFloat_Fini(PyThreadState *tstate); extern void _PySlice_Fini(PyThreadState *tstate); diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-05-20-01-17-34.bpo-40521.wvAehI.rst b/Misc/NEWS.d/next/Core and Builtins/2020-05-20-01-17-34.bpo-40521.wvAehI.rst index 3406ca8c973..24fd437062a 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2020-05-20-01-17-34.bpo-40521.wvAehI.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2020-05-20-01-17-34.bpo-40521.wvAehI.rst @@ -1,5 +1,5 @@ -The tuple free lists, the empty tuple singleton, the list free list, the float -free list, the slice cache, the dict free lists, the frame free list, the -asynchronous generator free lists, and the context free list are no longer -shared by all interpreters: each interpreter now its has own free lists and -caches. +The tuple free lists, the empty tuple singleton, the list free list, the empty +frozenset singleton, the float free list, the slice cache, the dict free lists, +the frame free list, the asynchronous generator free lists, and the context +free list are no longer shared by all interpreters: each interpreter now its +has own free lists and caches. diff --git a/Objects/setobject.c b/Objects/setobject.c index 76b1944db45..69bfc7d0a58 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -975,12 +975,11 @@ make_new_set_basetype(PyTypeObject *type, PyObject *iterable) return make_new_set(type, iterable); } -/* The empty frozenset is a singleton */ -static PyObject *emptyfrozenset = NULL; - static PyObject * make_new_frozenset(PyTypeObject *type, PyObject *iterable) { + PyObject *res; + if (type != &PyFrozenSet_Type) { return make_new_set(type, iterable); } @@ -991,7 +990,7 @@ make_new_frozenset(PyTypeObject *type, PyObject *iterable) Py_INCREF(iterable); return iterable; } - PyObject *res = make_new_set((PyTypeObject *)type, iterable); + res = make_new_set((PyTypeObject *)type, iterable); if (res == NULL || PySet_GET_SIZE(res) != 0) { return res; } @@ -1000,11 +999,17 @@ make_new_frozenset(PyTypeObject *type, PyObject *iterable) } // The empty frozenset is a singleton - if (emptyfrozenset == NULL) { - emptyfrozenset = make_new_set((PyTypeObject *)type, NULL); + PyInterpreterState *interp = _PyInterpreterState_GET(); + res = interp->empty_frozenset; + if (res == NULL) { + interp->empty_frozenset = make_new_set((PyTypeObject *)type, NULL); + res = interp->empty_frozenset; + if (res == NULL) { + return NULL; + } } - Py_XINCREF(emptyfrozenset); - return emptyfrozenset; + Py_INCREF(res); + return res; } static PyObject * @@ -2300,9 +2305,9 @@ PySet_Add(PyObject *anyset, PyObject *key) } void -_PySet_Fini(void) +_PySet_Fini(PyThreadState *tstate) { - Py_CLEAR(emptyfrozenset); + Py_CLEAR(tstate->interp->empty_frozenset); } int diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 1b4a3db517c..aaea0454d00 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1255,9 +1255,7 @@ finalize_interp_types(PyThreadState *tstate, int is_main_interp) _PyAsyncGen_Fini(tstate); _PyContext_Fini(tstate); - if (is_main_interp) { - _PySet_Fini(); - } + _PySet_Fini(tstate); _PyDict_Fini(tstate); _PyList_Fini(tstate); _PyTuple_Fini(tstate);