@@ -122,10 +122,7 @@ incr_false(void)
122122}
123123
124124
125- /* Key for thread state dictionary */
126- static PyObject * tls_context_key = NULL ;
127- /* Invariant: NULL or the most recently accessed thread local context */
128- static PyDecContextObject * cached_context = NULL ;
125+ static PyContextVar * current_context_var ;
129126
130127/* Template for creating new thread contexts, calling Context() without
131128 * arguments and initializing the module_context on first access. */
@@ -1220,10 +1217,6 @@ context_new(PyTypeObject *type, PyObject *args UNUSED, PyObject *kwds UNUSED)
12201217static void
12211218context_dealloc (PyDecContextObject * self )
12221219{
1223- if (self == cached_context ) {
1224- cached_context = NULL ;
1225- }
1226-
12271220 Py_XDECREF (self -> traps );
12281221 Py_XDECREF (self -> flags );
12291222 Py_TYPE (self )-> tp_free (self );
@@ -1498,117 +1491,61 @@ static PyGetSetDef context_getsets [] =
14981491 * operation.
14991492 */
15001493
1501- /* Get the context from the thread state dictionary. */
15021494static PyObject *
1503- current_context_from_dict (void )
1495+ init_current_context (void )
15041496{
1505- PyObject * dict ;
1506- PyObject * tl_context ;
1507- PyThreadState * tstate ;
1508-
1509- dict = PyThreadState_GetDict ();
1510- if (dict == NULL ) {
1511- PyErr_SetString (PyExc_RuntimeError ,
1512- "cannot get thread state" );
1497+ PyObject * tl_context = context_copy (default_context_template , NULL );
1498+ if (tl_context == NULL ) {
15131499 return NULL ;
15141500 }
1501+ CTX (tl_context )-> status = 0 ;
15151502
1516- tl_context = PyDict_GetItemWithError (dict , tls_context_key );
1517- if (tl_context != NULL ) {
1518- /* We already have a thread local context. */
1519- CONTEXT_CHECK (tl_context );
1520- }
1521- else {
1522- if (PyErr_Occurred ()) {
1523- return NULL ;
1524- }
1525-
1526- /* Set up a new thread local context. */
1527- tl_context = context_copy (default_context_template , NULL );
1528- if (tl_context == NULL ) {
1529- return NULL ;
1530- }
1531- CTX (tl_context )-> status = 0 ;
1532-
1533- if (PyDict_SetItem (dict , tls_context_key , tl_context ) < 0 ) {
1534- Py_DECREF (tl_context );
1535- return NULL ;
1536- }
1503+ PyContextToken * tok = PyContextVar_Set (current_context_var , tl_context );
1504+ if (tok == NULL ) {
15371505 Py_DECREF (tl_context );
1506+ return NULL ;
15381507 }
1508+ Py_DECREF (tok );
15391509
1540- /* Cache the context of the current thread, assuming that it
1541- * will be accessed several times before a thread switch. */
1542- tstate = PyThreadState_GET ();
1543- if (tstate ) {
1544- cached_context = (PyDecContextObject * )tl_context ;
1545- cached_context -> tstate = tstate ;
1546- }
1547-
1548- /* Borrowed reference with refcount==1 */
15491510 return tl_context ;
15501511}
15511512
1552- /* Return borrowed reference to thread local context. */
1553- static PyObject *
1513+ static inline PyObject *
15541514current_context (void )
15551515{
1556- PyThreadState * tstate ;
1516+ PyObject * tl_context ;
1517+ if (PyContextVar_Get (current_context_var , NULL , & tl_context ) < 0 ) {
1518+ return NULL ;
1519+ }
15571520
1558- tstate = PyThreadState_GET ();
1559- if (cached_context && cached_context -> tstate == tstate ) {
1560- return (PyObject * )cached_context ;
1521+ if (tl_context != NULL ) {
1522+ return tl_context ;
15611523 }
15621524
1563- return current_context_from_dict ();
1525+ return init_current_context ();
15641526}
15651527
15661528/* ctxobj := borrowed reference to the current context */
15671529#define CURRENT_CONTEXT (ctxobj ) \
15681530 ctxobj = current_context(); \
15691531 if (ctxobj == NULL) { \
15701532 return NULL; \
1571- }
1572-
1573- /* ctx := pointer to the mpd_context_t struct of the current context */
1574- #define CURRENT_CONTEXT_ADDR (ctx ) { \
1575- PyObject *_c_t_x_o_b_j = current_context(); \
1576- if (_c_t_x_o_b_j == NULL) { \
1577- return NULL; \
1578- } \
1579- ctx = CTX(_c_t_x_o_b_j); \
1580- }
1533+ } \
1534+ Py_DECREF(ctxobj);
15811535
15821536/* Return a new reference to the current context */
15831537static PyObject *
15841538PyDec_GetCurrentContext (PyObject * self UNUSED , PyObject * args UNUSED )
15851539{
1586- PyObject * context ;
1587-
1588- context = current_context ();
1589- if (context == NULL ) {
1590- return NULL ;
1591- }
1592-
1593- Py_INCREF (context );
1594- return context ;
1540+ return current_context ();
15951541}
15961542
15971543/* Set the thread local context to a new context, decrement old reference */
15981544static PyObject *
15991545PyDec_SetCurrentContext (PyObject * self UNUSED , PyObject * v )
16001546{
1601- PyObject * dict ;
1602-
16031547 CONTEXT_CHECK (v );
16041548
1605- dict = PyThreadState_GetDict ();
1606- if (dict == NULL ) {
1607- PyErr_SetString (PyExc_RuntimeError ,
1608- "cannot get thread state" );
1609- return NULL ;
1610- }
1611-
16121549 /* If the new context is one of the templates, make a copy.
16131550 * This is the current behavior of decimal.py. */
16141551 if (v == default_context_template ||
@@ -1624,13 +1561,13 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v)
16241561 Py_INCREF (v );
16251562 }
16261563
1627- cached_context = NULL ;
1628- if ( PyDict_SetItem ( dict , tls_context_key , v ) < 0 ) {
1629- Py_DECREF ( v );
1564+ PyContextToken * tok = PyContextVar_Set ( current_context_var , v ) ;
1565+ Py_DECREF ( v );
1566+ if ( tok == NULL ) {
16301567 return NULL ;
16311568 }
1569+ Py_DECREF (tok );
16321570
1633- Py_DECREF (v );
16341571 Py_RETURN_NONE ;
16351572}
16361573
@@ -4458,6 +4395,7 @@ _dec_hash(PyDecObject *v)
44584395 if (context == NULL ) {
44594396 return -1 ;
44604397 }
4398+ Py_DECREF (context );
44614399
44624400 if (mpd_isspecial (MPD (v ))) {
44634401 if (mpd_issnan (MPD (v ))) {
@@ -5599,6 +5537,11 @@ PyInit__decimal(void)
55995537 mpd_free = PyMem_Free ;
56005538 mpd_setminalloc (_Py_DEC_MINALLOC );
56015539
5540+ /* Init context variable */
5541+ current_context_var = PyContextVar_New ("decimal_context" , NULL );
5542+ if (current_context_var == NULL ) {
5543+ goto error ;
5544+ }
56025545
56035546 /* Init external C-API functions */
56045547 _py_long_multiply = PyLong_Type .tp_as_number -> nb_multiply ;
@@ -5768,7 +5711,6 @@ PyInit__decimal(void)
57685711 CHECK_INT (PyModule_AddObject (m , "DefaultContext" ,
57695712 default_context_template ));
57705713
5771- ASSIGN_PTR (tls_context_key , PyUnicode_FromString ("___DECIMAL_CTX__" ));
57725714 Py_INCREF (Py_True );
57735715 CHECK_INT (PyModule_AddObject (m , "HAVE_THREADS" , Py_True ));
57745716
@@ -5827,9 +5769,9 @@ PyInit__decimal(void)
58275769 Py_CLEAR (SignalTuple ); /* GCOV_NOT_REACHED */
58285770 Py_CLEAR (DecimalTuple ); /* GCOV_NOT_REACHED */
58295771 Py_CLEAR (default_context_template ); /* GCOV_NOT_REACHED */
5830- Py_CLEAR (tls_context_key ); /* GCOV_NOT_REACHED */
58315772 Py_CLEAR (basic_context_template ); /* GCOV_NOT_REACHED */
58325773 Py_CLEAR (extended_context_template ); /* GCOV_NOT_REACHED */
5774+ Py_CLEAR (current_context_var ); /* GCOV_NOT_REACHED */
58335775 Py_CLEAR (m ); /* GCOV_NOT_REACHED */
58345776
58355777 return NULL ; /* GCOV_NOT_REACHED */
0 commit comments