aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2020-06-05 02:05:41 +0200
committerGitHub <noreply@github.com>2020-06-05 02:05:41 +0200
commit88ec9190105c9b03f49aaef601ce02b242a75273 (patch)
tree699bea45830306ef5cd9943138a8c03d846e33d3 /Objects/listobject.c
parentbpo-40807: Show warnings once from codeop._maybe_compile (#20486) (diff)
downloadcpython-88ec9190105c9b03f49aaef601ce02b242a75273.tar.gz
cpython-88ec9190105c9b03f49aaef601ce02b242a75273.tar.bz2
cpython-88ec9190105c9b03f49aaef601ce02b242a75273.zip
bpo-40521: Make list free list per-interpreter (GH-20642)
Each interpreter now has its own list free list: * Move list numfree and free_list into PyInterpreterState. * Add _Py_list_state structure. * Add tstate parameter to _PyList_ClearFreeList() and _PyList_Fini(). * Remove "#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS". * _PyGC_Fini() clears gcstate->garbage list which can be stored in the list free list. Call _PyGC_Fini() before _PyList_Fini() to prevent leaking this list.
Diffstat (limited to 'Objects/listobject.c')
-rw-r--r--Objects/listobject.c60
1 files changed, 29 insertions, 31 deletions
diff --git a/Objects/listobject.c b/Objects/listobject.c
index 30d26207537..043256d8adb 100644
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -96,65 +96,59 @@ list_preallocate_exact(PyListObject *self, Py_ssize_t size)
return 0;
}
-/* Empty list reuse scheme to save calls to malloc and free */
-#ifndef PyList_MAXFREELIST
-# define PyList_MAXFREELIST 80
-#endif
-
-/* bpo-40521: list free lists are shared by all interpreters. */
-#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
-# undef PyList_MAXFREELIST
-# define PyList_MAXFREELIST 0
-#endif
-
-static PyListObject *free_list[PyList_MAXFREELIST];
-static int numfree = 0;
-
void
-_PyList_ClearFreeList(void)
+_PyList_ClearFreeList(PyThreadState *tstate)
{
- while (numfree) {
- PyListObject *op = free_list[--numfree];
+ struct _Py_list_state *state = &tstate->interp->list;
+ while (state->numfree) {
+ PyListObject *op = state->free_list[--state->numfree];
assert(PyList_CheckExact(op));
PyObject_GC_Del(op);
}
}
void
-_PyList_Fini(void)
+_PyList_Fini(PyThreadState *tstate)
{
- _PyList_ClearFreeList();
+ _PyList_ClearFreeList(tstate);
}
/* Print summary info about the state of the optimized allocator */
void
_PyList_DebugMallocStats(FILE *out)
{
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ struct _Py_list_state *state = &interp->list;
_PyDebugAllocatorStats(out,
"free PyListObject",
- numfree, sizeof(PyListObject));
+ state->numfree, sizeof(PyListObject));
}
PyObject *
PyList_New(Py_ssize_t size)
{
- PyListObject *op;
-
if (size < 0) {
PyErr_BadInternalCall();
return NULL;
}
- if (numfree) {
- numfree--;
- op = free_list[numfree];
+
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ struct _Py_list_state *state = &interp->list;
+ PyListObject *op;
+ if (state->numfree) {
+ state->numfree--;
+ op = state->free_list[state->numfree];
_Py_NewReference((PyObject *)op);
- } else {
+ }
+ else {
op = PyObject_GC_New(PyListObject, &PyList_Type);
- if (op == NULL)
+ if (op == NULL) {
return NULL;
+ }
}
- if (size <= 0)
+ if (size <= 0) {
op->ob_item = NULL;
+ }
else {
op->ob_item = (PyObject **) PyMem_Calloc(size, sizeof(PyObject *));
if (op->ob_item == NULL) {
@@ -334,10 +328,14 @@ list_dealloc(PyListObject *op)
}
PyMem_FREE(op->ob_item);
}
- if (numfree < PyList_MAXFREELIST && PyList_CheckExact(op))
- free_list[numfree++] = op;
- else
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ struct _Py_list_state *state = &interp->list;
+ if (state->numfree < PyList_MAXFREELIST && PyList_CheckExact(op)) {
+ state->free_list[state->numfree++] = op;
+ }
+ else {
Py_TYPE(op)->tp_free((PyObject *)op);
+ }
Py_TRASHCAN_END
}