mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	gh-81057: Move contextvars-related Globals to _PyRuntimeState (gh-99400)
This is part of the effort to consolidate global variables, to make them easier to manage (and make it easier to later move some of them to PyInterpreterState). https://github.com/python/cpython/issues/81057
This commit is contained in:
		
							parent
							
								
									5f55067e23
								
							
						
					
					
						commit
						01fa907aa8
					
				
					 9 changed files with 82 additions and 90 deletions
				
			
		|  | @ -18,6 +18,10 @@ void _PyContext_Fini(PyInterpreterState *); | ||||||
| 
 | 
 | ||||||
| /* other API */ | /* other API */ | ||||||
| 
 | 
 | ||||||
|  | typedef struct { | ||||||
|  |     PyObject_HEAD | ||||||
|  | } _PyContextTokenMissing; | ||||||
|  | 
 | ||||||
| #ifndef WITH_FREELISTS | #ifndef WITH_FREELISTS | ||||||
| // without freelists
 | // without freelists
 | ||||||
| #  define PyContext_MAXFREELIST 0 | #  define PyContext_MAXFREELIST 0 | ||||||
|  |  | ||||||
|  | @ -10,6 +10,8 @@ extern "C" { | ||||||
| 
 | 
 | ||||||
| #include "pycore_gc.h"              // PyGC_Head | #include "pycore_gc.h"              // PyGC_Head | ||||||
| #include "pycore_global_strings.h"  // struct _Py_global_strings | #include "pycore_global_strings.h"  // struct _Py_global_strings | ||||||
|  | #include "pycore_hamt.h"            // PyHamtNode_Bitmap | ||||||
|  | #include "pycore_context.h"         // _PyContextTokenMissing | ||||||
| #include "pycore_typeobject.h"      // pytype_slotdef | #include "pycore_typeobject.h"      // pytype_slotdef | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -52,6 +54,10 @@ struct _Py_global_objects { | ||||||
| 
 | 
 | ||||||
|         _PyGC_Head_UNUSED _tuple_empty_gc_not_used; |         _PyGC_Head_UNUSED _tuple_empty_gc_not_used; | ||||||
|         PyTupleObject tuple_empty; |         PyTupleObject tuple_empty; | ||||||
|  | 
 | ||||||
|  |         _PyGC_Head_UNUSED _hamt_bitmap_node_empty_gc_not_used; | ||||||
|  |         PyHamtNode_Bitmap hamt_bitmap_node_empty; | ||||||
|  |         _PyContextTokenMissing context_token_missing; | ||||||
|     } singletons; |     } singletons; | ||||||
| 
 | 
 | ||||||
|     PyObject *interned; |     PyObject *interned; | ||||||
|  | @ -76,6 +82,9 @@ struct _Py_interp_cached_objects { | ||||||
| struct _Py_interp_static_objects { | struct _Py_interp_static_objects { | ||||||
|     struct { |     struct { | ||||||
|         int _not_used; |         int _not_used; | ||||||
|  |         // hamt_empty is here instead of global because of its weakreflist.
 | ||||||
|  |         _PyGC_Head_UNUSED _hamt_empty_gc_not_used; | ||||||
|  |         PyHamtObject hamt_empty; | ||||||
|     } singletons; |     } singletons; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1475,6 +1475,9 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { | ||||||
|     /* non-generated */ |     /* non-generated */ | ||||||
|     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(bytes_empty)); |     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(bytes_empty)); | ||||||
|     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(tuple_empty)); |     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(tuple_empty)); | ||||||
|  |     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(hamt_bitmap_node_empty)); | ||||||
|  |     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_INTERP_SINGLETON(interp, hamt_empty)); | ||||||
|  |     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(context_token_missing)); | ||||||
| } | } | ||||||
| #endif  // Py_DEBUG
 | #endif  // Py_DEBUG
 | ||||||
| /* End auto-generated code */ | /* End auto-generated code */ | ||||||
|  |  | ||||||
|  | @ -28,10 +28,6 @@ extern PyTypeObject _PyHamtKeys_Type; | ||||||
| extern PyTypeObject _PyHamtValues_Type; | extern PyTypeObject _PyHamtValues_Type; | ||||||
| extern PyTypeObject _PyHamtItems_Type; | extern PyTypeObject _PyHamtItems_Type; | ||||||
| 
 | 
 | ||||||
| /* runtime lifecycle */ |  | ||||||
| 
 |  | ||||||
| void _PyHamt_Fini(PyInterpreterState *); |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| /* other API */ | /* other API */ | ||||||
| 
 | 
 | ||||||
|  | @ -53,6 +49,13 @@ typedef struct { | ||||||
| } PyHamtObject; | } PyHamtObject; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | typedef struct { | ||||||
|  |     PyObject_VAR_HEAD | ||||||
|  |     uint32_t b_bitmap; | ||||||
|  |     PyObject *b_array[1]; | ||||||
|  | } PyHamtNode_Bitmap; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| /* A struct to hold the state of depth-first traverse of the tree.
 | /* A struct to hold the state of depth-first traverse of the tree.
 | ||||||
| 
 | 
 | ||||||
|    HAMT is an immutable collection.  Iterators will hold a strong reference |    HAMT is an immutable collection.  Iterators will hold a strong reference | ||||||
|  |  | ||||||
|  | @ -75,6 +75,12 @@ extern "C" { | ||||||
|                 .tuple_empty = { \ |                 .tuple_empty = { \ | ||||||
|                     .ob_base = _PyVarObject_IMMORTAL_INIT(&PyTuple_Type, 0) \ |                     .ob_base = _PyVarObject_IMMORTAL_INIT(&PyTuple_Type, 0) \ | ||||||
|                 }, \ |                 }, \ | ||||||
|  |                 .hamt_bitmap_node_empty = { \ | ||||||
|  |                     .ob_base = _PyVarObject_IMMORTAL_INIT(&_PyHamt_BitmapNode_Type, 0) \ | ||||||
|  |                 }, \ | ||||||
|  |                 .context_token_missing = { \ | ||||||
|  |                     .ob_base = _PyObject_IMMORTAL_INIT(&_PyContextTokenMissing_Type), \ | ||||||
|  |                 }, \ | ||||||
|             }, \ |             }, \ | ||||||
|         }, \ |         }, \ | ||||||
|         ._main_interpreter = _PyInterpreterState_INIT, \ |         ._main_interpreter = _PyInterpreterState_INIT, \ | ||||||
|  | @ -112,6 +118,10 @@ extern "C" { | ||||||
|         .static_objects = { \ |         .static_objects = { \ | ||||||
|             .singletons = { \ |             .singletons = { \ | ||||||
|                 ._not_used = 1, \ |                 ._not_used = 1, \ | ||||||
|  |                 .hamt_empty = { \ | ||||||
|  |                     .ob_base = _PyObject_IMMORTAL_INIT(&_PyHamt_Type), \ | ||||||
|  |                     .h_root = (PyHamtNode*)&_Py_SINGLETON(hamt_bitmap_node_empty), \ | ||||||
|  |                 }, \ | ||||||
|             }, \ |             }, \ | ||||||
|         }, \ |         }, \ | ||||||
|         ._initial_thread = _PyThreadState_INIT, \ |         ._initial_thread = _PyThreadState_INIT, \ | ||||||
|  |  | ||||||
|  | @ -1235,25 +1235,29 @@ token_new(PyContext *ctx, PyContextVar *var, PyObject *val) | ||||||
| /////////////////////////// Token.MISSING
 | /////////////////////////// Token.MISSING
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static PyObject *_token_missing; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| typedef struct { |  | ||||||
|     PyObject_HEAD |  | ||||||
| } PyContextTokenMissing; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| static PyObject * | static PyObject * | ||||||
| context_token_missing_tp_repr(PyObject *self) | context_token_missing_tp_repr(PyObject *self) | ||||||
| { | { | ||||||
|     return PyUnicode_FromString("<Token.MISSING>"); |     return PyUnicode_FromString("<Token.MISSING>"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void | ||||||
|  | context_token_missing_tp_dealloc(_PyContextTokenMissing *Py_UNUSED(self)) | ||||||
|  | { | ||||||
|  | #ifdef Py_DEBUG | ||||||
|  |     /* The singleton is statically allocated. */ | ||||||
|  |     _Py_FatalRefcountError("deallocating the token missing singleton"); | ||||||
|  | #else | ||||||
|  |     return; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| PyTypeObject _PyContextTokenMissing_Type = { | PyTypeObject _PyContextTokenMissing_Type = { | ||||||
|     PyVarObject_HEAD_INIT(&PyType_Type, 0) |     PyVarObject_HEAD_INIT(&PyType_Type, 0) | ||||||
|     "Token.MISSING", |     "Token.MISSING", | ||||||
|     sizeof(PyContextTokenMissing), |     sizeof(_PyContextTokenMissing), | ||||||
|  |     .tp_dealloc = (destructor)context_token_missing_tp_dealloc, | ||||||
|     .tp_getattro = PyObject_GenericGetAttr, |     .tp_getattro = PyObject_GenericGetAttr, | ||||||
|     .tp_flags = Py_TPFLAGS_DEFAULT, |     .tp_flags = Py_TPFLAGS_DEFAULT, | ||||||
|     .tp_repr = context_token_missing_tp_repr, |     .tp_repr = context_token_missing_tp_repr, | ||||||
|  | @ -1263,17 +1267,7 @@ PyTypeObject _PyContextTokenMissing_Type = { | ||||||
| static PyObject * | static PyObject * | ||||||
| get_token_missing(void) | get_token_missing(void) | ||||||
| { | { | ||||||
|     if (_token_missing != NULL) { |     return Py_NewRef(&_Py_SINGLETON(context_token_missing)); | ||||||
|         return Py_NewRef(_token_missing); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     _token_missing = (PyObject *)PyObject_New( |  | ||||||
|         PyContextTokenMissing, &_PyContextTokenMissing_Type); |  | ||||||
|     if (_token_missing == NULL) { |  | ||||||
|         return NULL; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return Py_NewRef(_token_missing); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -1298,15 +1292,11 @@ _PyContext_ClearFreeList(PyInterpreterState *interp) | ||||||
| void | void | ||||||
| _PyContext_Fini(PyInterpreterState *interp) | _PyContext_Fini(PyInterpreterState *interp) | ||||||
| { | { | ||||||
|     if (_Py_IsMainInterpreter(interp)) { |  | ||||||
|         Py_CLEAR(_token_missing); |  | ||||||
|     } |  | ||||||
|     _PyContext_ClearFreeList(interp); |     _PyContext_ClearFreeList(interp); | ||||||
| #if defined(Py_DEBUG) && PyContext_MAXFREELIST > 0 | #if defined(Py_DEBUG) && PyContext_MAXFREELIST > 0 | ||||||
|     struct _Py_context_state *state = &interp->context; |     struct _Py_context_state *state = &interp->context; | ||||||
|     state->numfree = -1; |     state->numfree = -1; | ||||||
| #endif | #endif | ||||||
|     _PyHamt_Fini(interp); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -319,13 +319,6 @@ typedef struct { | ||||||
| } PyHamtNode_Array; | } PyHamtNode_Array; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| typedef struct { |  | ||||||
|     PyObject_VAR_HEAD |  | ||||||
|     uint32_t b_bitmap; |  | ||||||
|     PyObject *b_array[1]; |  | ||||||
| } PyHamtNode_Bitmap; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| typedef struct { | typedef struct { | ||||||
|     PyObject_VAR_HEAD |     PyObject_VAR_HEAD | ||||||
|     int32_t c_hash; |     int32_t c_hash; | ||||||
|  | @ -333,10 +326,6 @@ typedef struct { | ||||||
| } PyHamtNode_Collision; | } PyHamtNode_Collision; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static PyHamtNode_Bitmap *_empty_bitmap_node; |  | ||||||
| static PyHamtObject *_empty_hamt; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| static PyHamtObject * | static PyHamtObject * | ||||||
| hamt_alloc(void); | hamt_alloc(void); | ||||||
| 
 | 
 | ||||||
|  | @ -521,13 +510,16 @@ hamt_node_bitmap_new(Py_ssize_t size) | ||||||
|     PyHamtNode_Bitmap *node; |     PyHamtNode_Bitmap *node; | ||||||
|     Py_ssize_t i; |     Py_ssize_t i; | ||||||
| 
 | 
 | ||||||
|  |     if (size == 0) { | ||||||
|  |         /* Since bitmap nodes are immutable, we can cache the instance
 | ||||||
|  |            for size=0 and reuse it whenever we need an empty bitmap node. | ||||||
|  |         */ | ||||||
|  |         return (PyHamtNode *)Py_NewRef(&_Py_SINGLETON(hamt_bitmap_node_empty)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     assert(size >= 0); |     assert(size >= 0); | ||||||
|     assert(size % 2 == 0); |     assert(size % 2 == 0); | ||||||
| 
 | 
 | ||||||
|     if (size == 0 && _empty_bitmap_node != NULL) { |  | ||||||
|         return (PyHamtNode *)Py_NewRef(_empty_bitmap_node); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /* No freelist; allocate a new bitmap node */ |     /* No freelist; allocate a new bitmap node */ | ||||||
|     node = PyObject_GC_NewVar( |     node = PyObject_GC_NewVar( | ||||||
|         PyHamtNode_Bitmap, &_PyHamt_BitmapNode_Type, size); |         PyHamtNode_Bitmap, &_PyHamt_BitmapNode_Type, size); | ||||||
|  | @ -545,13 +537,6 @@ hamt_node_bitmap_new(Py_ssize_t size) | ||||||
| 
 | 
 | ||||||
|     _PyObject_GC_TRACK(node); |     _PyObject_GC_TRACK(node); | ||||||
| 
 | 
 | ||||||
|     if (size == 0 && _empty_bitmap_node == NULL) { |  | ||||||
|         /* Since bitmap nodes are immutable, we can cache the instance
 |  | ||||||
|            for size=0 and reuse it whenever we need an empty bitmap node. |  | ||||||
|         */ |  | ||||||
|         _empty_bitmap_node = (PyHamtNode_Bitmap*)Py_NewRef(node); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return (PyHamtNode *)node; |     return (PyHamtNode *)node; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1142,6 +1127,16 @@ hamt_node_bitmap_dealloc(PyHamtNode_Bitmap *self) | ||||||
|     Py_ssize_t len = Py_SIZE(self); |     Py_ssize_t len = Py_SIZE(self); | ||||||
|     Py_ssize_t i; |     Py_ssize_t i; | ||||||
| 
 | 
 | ||||||
|  |     if (Py_SIZE(self) == 0) { | ||||||
|  |         /* The empty node is statically allocated. */ | ||||||
|  |         assert(self == &_Py_SINGLETON(hamt_bitmap_node_empty)); | ||||||
|  | #ifdef Py_DEBUG | ||||||
|  |         _Py_FatalRefcountError("deallocating the empty hamt node bitmap singleton"); | ||||||
|  | #else | ||||||
|  |         return; | ||||||
|  | #endif | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     PyObject_GC_UnTrack(self); |     PyObject_GC_UnTrack(self); | ||||||
|     Py_TRASHCAN_BEGIN(self, hamt_node_bitmap_dealloc) |     Py_TRASHCAN_BEGIN(self, hamt_node_bitmap_dealloc) | ||||||
| 
 | 
 | ||||||
|  | @ -2431,33 +2426,15 @@ hamt_alloc(void) | ||||||
|     return o; |     return o; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #define _empty_hamt \ | ||||||
|  |     (&_Py_INTERP_SINGLETON(_PyInterpreterState_Get(), hamt_empty)) | ||||||
|  | 
 | ||||||
| PyHamtObject * | PyHamtObject * | ||||||
| _PyHamt_New(void) | _PyHamt_New(void) | ||||||
| { | { | ||||||
|     if (_empty_hamt != NULL) { |     /* HAMT is an immutable object so we can easily cache an
 | ||||||
|         /* HAMT is an immutable object so we can easily cache an
 |        empty instance. */ | ||||||
|            empty instance. */ |     return (PyHamtObject*)Py_NewRef(_empty_hamt); | ||||||
|         return (PyHamtObject*)Py_NewRef(_empty_hamt); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     PyHamtObject *o = hamt_alloc(); |  | ||||||
|     if (o == NULL) { |  | ||||||
|         return NULL; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     o->h_root = hamt_node_bitmap_new(0); |  | ||||||
|     if (o->h_root == NULL) { |  | ||||||
|         Py_DECREF(o); |  | ||||||
|         return NULL; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     o->h_count = 0; |  | ||||||
| 
 |  | ||||||
|     if (_empty_hamt == NULL) { |  | ||||||
|         _empty_hamt = (PyHamtObject*)Py_NewRef(o); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return o; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #ifdef Py_DEBUG | #ifdef Py_DEBUG | ||||||
|  | @ -2673,6 +2650,15 @@ hamt_tp_traverse(PyHamtObject *self, visitproc visit, void *arg) | ||||||
| static void | static void | ||||||
| hamt_tp_dealloc(PyHamtObject *self) | hamt_tp_dealloc(PyHamtObject *self) | ||||||
| { | { | ||||||
|  |     if (self == _empty_hamt) { | ||||||
|  |         /* The empty one is statically allocated. */ | ||||||
|  | #ifdef Py_DEBUG | ||||||
|  |         _Py_FatalRefcountError("deallocating the empty hamt singleton"); | ||||||
|  | #else | ||||||
|  |         return; | ||||||
|  | #endif | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     PyObject_GC_UnTrack(self); |     PyObject_GC_UnTrack(self); | ||||||
|     if (self->h_weakreflist != NULL) { |     if (self->h_weakreflist != NULL) { | ||||||
|         PyObject_ClearWeakRefs((PyObject*)self); |         PyObject_ClearWeakRefs((PyObject*)self); | ||||||
|  | @ -2908,11 +2894,3 @@ PyTypeObject _PyHamt_CollisionNode_Type = { | ||||||
|     .tp_free = PyObject_GC_Del, |     .tp_free = PyObject_GC_Del, | ||||||
|     .tp_hash = PyObject_HashNotImplemented, |     .tp_hash = PyObject_HashNotImplemented, | ||||||
| }; | }; | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| void |  | ||||||
| _PyHamt_Fini(PyInterpreterState *interp) |  | ||||||
| { |  | ||||||
|     Py_CLEAR(_empty_hamt); |  | ||||||
|     Py_CLEAR(_empty_bitmap_node); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  | @ -127,6 +127,9 @@ | ||||||
|     # The generated ones come from generate_runtime_init(). |     # The generated ones come from generate_runtime_init(). | ||||||
|     '(PyObject *)&_Py_SINGLETON(bytes_empty)', |     '(PyObject *)&_Py_SINGLETON(bytes_empty)', | ||||||
|     '(PyObject *)&_Py_SINGLETON(tuple_empty)', |     '(PyObject *)&_Py_SINGLETON(tuple_empty)', | ||||||
|  |     '(PyObject *)&_Py_SINGLETON(hamt_bitmap_node_empty)', | ||||||
|  |     '(PyObject *)&_Py_INTERP_SINGLETON(interp, hamt_empty)', | ||||||
|  |     '(PyObject *)&_Py_SINGLETON(context_token_missing)', | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -298,14 +298,6 @@ Objects/setobject.c	-	_dummy_struct	- | ||||||
| Objects/setobject.c	-	_PySet_Dummy	- | Objects/setobject.c	-	_PySet_Dummy	- | ||||||
| Objects/sliceobject.c	-	_Py_EllipsisObject	- | Objects/sliceobject.c	-	_Py_EllipsisObject	- | ||||||
| 
 | 
 | ||||||
| #----------------------- |  | ||||||
| # other |  | ||||||
| 
 |  | ||||||
| # initialized once |  | ||||||
| Python/context.c	-	_token_missing	- |  | ||||||
| Python/hamt.c	-	_empty_bitmap_node	- |  | ||||||
| Python/hamt.c	-	_empty_hamt	- |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| ################################## | ################################## | ||||||
| # global non-objects to fix in core code | # global non-objects to fix in core code | ||||||
|  |  | ||||||
| Can't render this file because it has a wrong number of fields in line 4. | 
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Eric Snow
						Eric Snow