]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-40521: Make context free list per-interpreter (GH-20644)
authorVictor Stinner <vstinner@python.org>
Fri, 5 Jun 2020 00:56:37 +0000 (02:56 +0200)
committerGitHub <noreply@github.com>
Fri, 5 Jun 2020 00:56:37 +0000 (02:56 +0200)
Each interpreter now has its own context free list:

* Move context free list into PyInterpreterState.
* Add _Py_context_state structure.
* Add tstate parameter to _PyContext_ClearFreeList()
  and _PyContext_Fini().
* Pass tstate to clear_freelists().

Include/internal/pycore_context.h
Include/internal/pycore_gc.h
Include/internal/pycore_interp.h
Misc/NEWS.d/next/Core and Builtins/2020-05-20-01-17-34.bpo-40521.wvAehI.rst
Modules/gcmodule.c
Python/context.c
Python/pylifecycle.c

index f665ad5c115b07ac839917db3271ade9b4663475..ea4b3c8ea738f079c1153bec18a8342a8c5cdf68 100644 (file)
@@ -37,6 +37,6 @@ struct _pycontexttokenobject {
 
 
 int _PyContext_Init(void);
-void _PyContext_Fini(void);
+void _PyContext_Fini(PyThreadState *tstate);
 
 #endif /* !Py_INTERNAL_CONTEXT_H */
index ad2e552df55f98bd93625f00a7f1834297d5f8ae..fd3fb7f94cab084631e093902f6f8b4ea96664fe 100644 (file)
@@ -171,7 +171,7 @@ extern void _PyFloat_ClearFreeList(PyThreadState *tstate);
 extern void _PyList_ClearFreeList(PyThreadState *tstate);
 extern void _PyDict_ClearFreeList(void);
 extern void _PyAsyncGen_ClearFreeLists(PyThreadState *tstate);
-extern void _PyContext_ClearFreeList(void);
+extern void _PyContext_ClearFreeList(PyThreadState *tstate);
 
 #ifdef __cplusplus
 }
index d624218201b91b37ff76d5c06759763f8b475a44..4f811023f7a04324604b6d6d400c6adfd73f7368 100644 (file)
@@ -124,6 +124,12 @@ struct _Py_async_gen_state {
     int asend_numfree;
 };
 
+struct _Py_context_state {
+    // List of free PyContext objects
+    PyContext *freelist;
+    int numfree;
+};
+
 
 
 /* interpreter state */
@@ -223,6 +229,7 @@ struct _is {
     struct _Py_float_state float_state;
     struct _Py_frame_state frame;
     struct _Py_async_gen_state async_gen;
+    struct _Py_context_state context;
 
     /* Using a cache is very effective since typically only a single slice is
        created and then deleted again. */
index f0fd5a1e13b79b4acd3f3b569d9aa8645970dafb..39cb80447f6a98c32504218d71efafb1d6f76410 100644 (file)
@@ -1,4 +1,4 @@
 The tuple free lists, the empty tuple singleton, the list free list, the float
 free list, the slice cache, the frame free list, the asynchronous generator
-free lists are no longer shared by all interpreters: each interpreter now its
-has own free lists and caches.
+free lists, and the context free list are no longer shared by all interpreters:
+each interpreter now its has own free lists and caches.
index 89e2db7b194953822bf770d64ee97af2205bca4b..f68258d7a327c04a187b18fe9f0c71ef36147177 100644 (file)
@@ -1023,16 +1023,15 @@ delete_garbage(PyThreadState *tstate, GCState *gcstate,
  * Clearing the free lists may give back memory to the OS earlier.
  */
 static void
-clear_freelists(void)
+clear_freelists(PyThreadState *tstate)
 {
-    PyThreadState *tstate = _PyThreadState_GET();
     _PyFrame_ClearFreeList(tstate);
     _PyTuple_ClearFreeList(tstate);
     _PyFloat_ClearFreeList(tstate);
     _PyList_ClearFreeList(tstate);
     _PyDict_ClearFreeList();
     _PyAsyncGen_ClearFreeLists(tstate);
-    _PyContext_ClearFreeList();
+    _PyContext_ClearFreeList(tstate);
 }
 
 // Show stats for objects in each generations
@@ -1306,7 +1305,7 @@ collect(PyThreadState *tstate, int generation,
     /* Clear free list only during the collection of the highest
      * generation */
     if (generation == NUM_GENERATIONS-1) {
-        clear_freelists();
+        clear_freelists(tstate);
     }
 
     if (_PyErr_Occurred(tstate)) {
index bacc7010c458e1f927c24bbb467feaeb53eea390..3cf8db4c90cdfef78e1e5fb4e40524758ba93243 100644 (file)
@@ -10,8 +10,6 @@
 
 
 #define CONTEXT_FREELIST_MAXLEN 255
-static PyContext *ctx_freelist = NULL;
-static int ctx_freelist_len = 0;
 
 
 #include "clinic/context.c.h"
@@ -334,11 +332,13 @@ class _contextvars.Context "PyContext *" "&PyContext_Type"
 static inline PyContext *
 _context_alloc(void)
 {
+    PyInterpreterState *interp = _PyInterpreterState_GET();
+    struct _Py_context_state *state = &interp->context;
     PyContext *ctx;
-    if (ctx_freelist_len) {
-        ctx_freelist_len--;
-        ctx = ctx_freelist;
-        ctx_freelist = (PyContext *)ctx->ctx_weakreflist;
+    if (state->numfree) {
+        state->numfree--;
+        ctx = state->freelist;
+        state->freelist = (PyContext *)ctx->ctx_weakreflist;
         ctx->ctx_weakreflist = NULL;
         _Py_NewReference((PyObject *)ctx);
     }
@@ -458,10 +458,12 @@ context_tp_dealloc(PyContext *self)
     }
     (void)context_tp_clear(self);
 
-    if (ctx_freelist_len < CONTEXT_FREELIST_MAXLEN) {
-        ctx_freelist_len++;
-        self->ctx_weakreflist = (PyObject *)ctx_freelist;
-        ctx_freelist = self;
+    PyInterpreterState *interp = _PyInterpreterState_GET();
+    struct _Py_context_state *state = &interp->context;
+    if (state->numfree < CONTEXT_FREELIST_MAXLEN) {
+        state->numfree++;
+        self->ctx_weakreflist = (PyObject *)state->freelist;
+        state->freelist = self;
     }
     else {
         Py_TYPE(self)->tp_free(self);
@@ -1271,11 +1273,12 @@ get_token_missing(void)
 
 
 void
-_PyContext_ClearFreeList(void)
+_PyContext_ClearFreeList(PyThreadState *tstate)
 {
-    for (; ctx_freelist_len; ctx_freelist_len--) {
-        PyContext *ctx = ctx_freelist;
-        ctx_freelist = (PyContext *)ctx->ctx_weakreflist;
+    struct _Py_context_state *state = &tstate->interp->context;
+    for (; state->numfree; state->numfree--) {
+        PyContext *ctx = state->freelist;
+        state->freelist = (PyContext *)ctx->ctx_weakreflist;
         ctx->ctx_weakreflist = NULL;
         PyObject_GC_Del(ctx);
     }
@@ -1283,10 +1286,10 @@ _PyContext_ClearFreeList(void)
 
 
 void
-_PyContext_Fini(void)
+_PyContext_Fini(PyThreadState *tstate)
 {
     Py_CLEAR(_token_missing);
-    _PyContext_ClearFreeList();
+    _PyContext_ClearFreeList(tstate);
     _PyHamt_Fini();
 }
 
index 073973e1328d48d26474e7eb2aff5e384828a019..6d2eb1defc884e65936e06e1f8d087d06fefa088 100644 (file)
@@ -1273,10 +1273,7 @@ finalize_interp_types(PyThreadState *tstate, int is_main_interp)
     }
 
     _PyAsyncGen_Fini(tstate);
-
-    if (is_main_interp) {
-        _PyContext_Fini();
-    }
+    _PyContext_Fini(tstate);
 
     /* Cleanup Unicode implementation */
     _PyUnicode_Fini(tstate);