Skip to content

Commit 261cfed

Browse files
authored
bpo-40521: Make the empty frozenset per interpreter (GH-21068)
Each interpreter now has its own empty frozenset singleton.
1 parent b4e85ca commit 261cfed

File tree

5 files changed

+24
-19
lines changed

5 files changed

+24
-19
lines changed

Include/internal/pycore_interp.h

+2
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,8 @@ struct _is {
238238
/* Using a cache is very effective since typically only a single slice is
239239
created and then deleted again. */
240240
PySliceObject *slice_cache;
241+
// The empty frozenset is a singleton.
242+
PyObject *empty_frozenset;
241243

242244
struct _Py_tuple_state tuple;
243245
struct _Py_list_state list;

Include/internal/pycore_pylifecycle.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ extern void _PyFrame_Fini(PyThreadState *tstate);
6262
extern void _PyDict_Fini(PyThreadState *tstate);
6363
extern void _PyTuple_Fini(PyThreadState *tstate);
6464
extern void _PyList_Fini(PyThreadState *tstate);
65-
extern void _PySet_Fini(void);
65+
extern void _PySet_Fini(PyThreadState *tstate);
6666
extern void _PyBytes_Fini(void);
6767
extern void _PyFloat_Fini(PyThreadState *tstate);
6868
extern void _PySlice_Fini(PyThreadState *tstate);
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
The tuple free lists, the empty tuple singleton, the list free list, the float
2-
free list, the slice cache, the dict free lists, the frame free list, the
3-
asynchronous generator free lists, and the context free list are no longer
4-
shared by all interpreters: each interpreter now its has own free lists and
5-
caches.
1+
The tuple free lists, the empty tuple singleton, the list free list, the empty
2+
frozenset singleton, the float free list, the slice cache, the dict free lists,
3+
the frame free list, the asynchronous generator free lists, and the context
4+
free list are no longer shared by all interpreters: each interpreter now its
5+
has own free lists and caches.

Objects/setobject.c

+15-10
Original file line numberDiff line numberDiff line change
@@ -975,12 +975,11 @@ make_new_set_basetype(PyTypeObject *type, PyObject *iterable)
975975
return make_new_set(type, iterable);
976976
}
977977

978-
/* The empty frozenset is a singleton */
979-
static PyObject *emptyfrozenset = NULL;
980-
981978
static PyObject *
982979
make_new_frozenset(PyTypeObject *type, PyObject *iterable)
983980
{
981+
PyObject *res;
982+
984983
if (type != &PyFrozenSet_Type) {
985984
return make_new_set(type, iterable);
986985
}
@@ -991,7 +990,7 @@ make_new_frozenset(PyTypeObject *type, PyObject *iterable)
991990
Py_INCREF(iterable);
992991
return iterable;
993992
}
994-
PyObject *res = make_new_set((PyTypeObject *)type, iterable);
993+
res = make_new_set((PyTypeObject *)type, iterable);
995994
if (res == NULL || PySet_GET_SIZE(res) != 0) {
996995
return res;
997996
}
@@ -1000,11 +999,17 @@ make_new_frozenset(PyTypeObject *type, PyObject *iterable)
1000999
}
10011000

10021001
// The empty frozenset is a singleton
1003-
if (emptyfrozenset == NULL) {
1004-
emptyfrozenset = make_new_set((PyTypeObject *)type, NULL);
1002+
PyInterpreterState *interp = _PyInterpreterState_GET();
1003+
res = interp->empty_frozenset;
1004+
if (res == NULL) {
1005+
interp->empty_frozenset = make_new_set((PyTypeObject *)type, NULL);
1006+
res = interp->empty_frozenset;
1007+
if (res == NULL) {
1008+
return NULL;
1009+
}
10051010
}
1006-
Py_XINCREF(emptyfrozenset);
1007-
return emptyfrozenset;
1011+
Py_INCREF(res);
1012+
return res;
10081013
}
10091014

10101015
static PyObject *
@@ -2300,9 +2305,9 @@ PySet_Add(PyObject *anyset, PyObject *key)
23002305
}
23012306

23022307
void
2303-
_PySet_Fini(void)
2308+
_PySet_Fini(PyThreadState *tstate)
23042309
{
2305-
Py_CLEAR(emptyfrozenset);
2310+
Py_CLEAR(tstate->interp->empty_frozenset);
23062311
}
23072312

23082313
int

Python/pylifecycle.c

+1-3
Original file line numberDiff line numberDiff line change
@@ -1255,9 +1255,7 @@ finalize_interp_types(PyThreadState *tstate, int is_main_interp)
12551255
_PyAsyncGen_Fini(tstate);
12561256
_PyContext_Fini(tstate);
12571257

1258-
if (is_main_interp) {
1259-
_PySet_Fini();
1260-
}
1258+
_PySet_Fini(tstate);
12611259
_PyDict_Fini(tstate);
12621260
_PyList_Fini(tstate);
12631261
_PyTuple_Fini(tstate);

0 commit comments

Comments
 (0)