From f996b494d68d417c5194f848a90b7082f25a6ac8 Mon Sep 17 00:00:00 2001 From: CharlieZhao Date: Mon, 3 Jul 2023 15:07:31 +0800 Subject: [PATCH 01/10] Move contextvar to global state --- Modules/_decimal/_decimal.c | 54 ++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index da623725003428..011af585fae2d1 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -49,6 +49,15 @@ typedef struct { /* Top level Exception; inherits from ArithmeticError */ PyObject *DecimalException; + +#ifndef WITH_DECIMAL_CONTEXTVAR + /* Key for thread state dictionary */ + PyObject *tls_context_key; + /* Invariant: NULL or the most recently accessed thread local context */ + PyDecContextObject *cached_context; +#else + PyObject *current_context_var; +#endif } decimal_state; static decimal_state global_state; @@ -137,16 +146,6 @@ incr_false(void) return Py_NewRef(Py_False); } - -#ifndef WITH_DECIMAL_CONTEXTVAR -/* Key for thread state dictionary */ -static PyObject *tls_context_key = NULL; -/* Invariant: NULL or the most recently accessed thread local context */ -static PyDecContextObject *cached_context = NULL; -#else -static PyObject *current_context_var = NULL; -#endif - /* Template for creating new thread contexts, calling Context() without * arguments and initializing the module_context on first access. */ static PyObject *default_context_template = NULL; @@ -1565,7 +1564,8 @@ current_context_from_dict(void) return NULL; } - PyObject *tl_context = PyDict_GetItemWithError(dict, tls_context_key); + PyObject *tl_context = PyDict_GetItemWithError(dict, + state->tls_context_key); if (tl_context != NULL) { /* We already have a thread local context. */ CONTEXT_CHECK(modstate, tl_context); @@ -1582,7 +1582,7 @@ current_context_from_dict(void) } CTX(tl_context)->status = 0; - if (PyDict_SetItem(dict, tls_context_key, tl_context) < 0) { + if (PyDict_SetItem(dict, state->tls_context_key, tl_context) < 0) { Py_DECREF(tl_context); return NULL; } @@ -1591,8 +1591,8 @@ current_context_from_dict(void) /* Cache the context of the current thread, assuming that it * will be accessed several times before a thread switch. */ - cached_context = (PyDecContextObject *)tl_context; - cached_context->tstate = tstate; + state->cached_context = (PyDecContextObject *)tl_context; + state->cached_context->tstate = tstate; /* Borrowed reference with refcount==1 */ return tl_context; @@ -1603,8 +1603,9 @@ static PyObject * current_context(void) { PyThreadState *tstate = _PyThreadState_GET(); - if (cached_context && cached_context->tstate == tstate) { - return (PyObject *)cached_context; + decimal_state *state = GLOBAL_STATE(); + if (state->cached_context && state->cached_context->tstate == tstate) { + return (PyObject *)(state->cached_context); } return current_context_from_dict(); @@ -1662,8 +1663,8 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) Py_INCREF(v); } - cached_context = NULL; - if (PyDict_SetItem(dict, tls_context_key, v) < 0) { + state->cached_context = NULL; + if (PyDict_SetItem(dict, state->tls_context_key, v) < 0) { Py_DECREF(v); return NULL; } @@ -1675,13 +1676,14 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) static PyObject * init_current_context(void) { + decimal_state *state = GLOBAL_STATE(); PyObject *tl_context = context_copy(default_context_template, NULL); if (tl_context == NULL) { return NULL; } CTX(tl_context)->status = 0; - PyObject *tok = PyContextVar_Set(current_context_var, tl_context); + PyObject *tok = PyContextVar_Set(state->current_context_var, tl_context); if (tok == NULL) { Py_DECREF(tl_context); return NULL; @@ -1695,7 +1697,8 @@ static inline PyObject * current_context(void) { PyObject *tl_context; - if (PyContextVar_Get(current_context_var, NULL, &tl_context) < 0) { + decimal_state *state = GLOBAL_STATE(); + if (PyContextVar_Get(state->current_context_var, NULL, &tl_context) < 0) { return NULL; } @@ -1743,7 +1746,7 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) Py_INCREF(v); } - PyObject *tok = PyContextVar_Set(current_context_var, v); + PyObject *tok = PyContextVar_Set(state->current_context_var, v); Py_DECREF(v); if (tok == NULL) { return NULL; @@ -5986,10 +5989,11 @@ PyInit__decimal(void) Py_NewRef(default_context_template))); #ifndef WITH_DECIMAL_CONTEXTVAR - ASSIGN_PTR(tls_context_key, PyUnicode_FromString("___DECIMAL_CTX__")); + ASSIGN_PTR(state->tls_context_key, + PyUnicode_FromString("___DECIMAL_CTX__")); CHECK_INT(PyModule_AddObject(m, "HAVE_CONTEXTVAR", Py_NewRef(Py_False))); #else - ASSIGN_PTR(current_context_var, PyContextVar_New("decimal_context", NULL)); + ASSIGN_PTR(state->current_context_var, PyContextVar_New("decimal_context", NULL)); CHECK_INT(PyModule_AddObject(m, "HAVE_CONTEXTVAR", Py_NewRef(Py_True))); #endif CHECK_INT(PyModule_AddObject(m, "HAVE_THREADS", Py_NewRef(Py_True))); @@ -6048,9 +6052,9 @@ PyInit__decimal(void) Py_CLEAR(state->DecimalTuple); /* GCOV_NOT_REACHED */ Py_CLEAR(default_context_template); /* GCOV_NOT_REACHED */ #ifndef WITH_DECIMAL_CONTEXTVAR - Py_CLEAR(tls_context_key); /* GCOV_NOT_REACHED */ + Py_CLEAR(state->tls_context_key); /* GCOV_NOT_REACHED */ #else - Py_CLEAR(current_context_var); /* GCOV_NOT_REACHED */ + Py_CLEAR(state->current_context_var); /* GCOV_NOT_REACHED */ #endif Py_CLEAR(basic_context_template); /* GCOV_NOT_REACHED */ Py_CLEAR(extended_context_template); /* GCOV_NOT_REACHED */ From 8938ce81af911b5ff324d5f233b0b82206fd3cc5 Mon Sep 17 00:00:00 2001 From: CharlieZhao Date: Mon, 3 Jul 2023 15:08:07 +0800 Subject: [PATCH 02/10] update globals-to-fix --- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 1 file changed, 1 deletion(-) diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 8fdc54df2b0722..01c5d30675ce3e 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -423,7 +423,6 @@ Modules/_datetimemodule.c - us_per_week - Modules/_datetimemodule.c - seconds_per_day - Modules/_decimal/_decimal.c - global_state - Modules/_decimal/_decimal.c - basic_context_template - -Modules/_decimal/_decimal.c - current_context_var - Modules/_decimal/_decimal.c - default_context_template - Modules/_decimal/_decimal.c - extended_context_template - Modules/_decimal/_decimal.c - round_map - From 4e98c029360c29035039948cac6266b2861f1fa4 Mon Sep 17 00:00:00 2001 From: CharlieZhao Date: Tue, 4 Jul 2023 09:52:30 +0800 Subject: [PATCH 03/10] Fix build error Fix build error with flag `--without-decimal-contextvar` --- Modules/_decimal/_decimal.c | 59 ++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 011af585fae2d1..e739afb1a6ee00 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -39,31 +39,6 @@ #include "docstrings.h" -typedef struct { - PyTypeObject *PyDecContextManager_Type; - PyTypeObject *PyDecContext_Type; - PyTypeObject *PyDecSignalDictMixin_Type; - PyTypeObject *PyDec_Type; - PyTypeObject *PyDecSignalDict_Type; - PyTypeObject *DecimalTuple; - - /* Top level Exception; inherits from ArithmeticError */ - PyObject *DecimalException; - -#ifndef WITH_DECIMAL_CONTEXTVAR - /* Key for thread state dictionary */ - PyObject *tls_context_key; - /* Invariant: NULL or the most recently accessed thread local context */ - PyDecContextObject *cached_context; -#else - PyObject *current_context_var; -#endif -} decimal_state; - -static decimal_state global_state; - -#define GLOBAL_STATE() (&global_state) - #if !defined(MPD_VERSION_HEX) || MPD_VERSION_HEX < 0x02050000 #error "libmpdec version >= 2.5.0 required" #endif @@ -120,6 +95,30 @@ typedef struct { PyObject *global; } PyDecContextManagerObject; +typedef struct { + PyTypeObject *PyDecContextManager_Type; + PyTypeObject *PyDecContext_Type; + PyTypeObject *PyDecSignalDictMixin_Type; + PyTypeObject *PyDec_Type; + PyTypeObject *PyDecSignalDict_Type; + PyTypeObject *DecimalTuple; + + /* Top level Exception; inherits from ArithmeticError */ + PyObject *DecimalException; + +#ifndef WITH_DECIMAL_CONTEXTVAR + /* Key for thread state dictionary */ + PyObject *tls_context_key; + /* Invariant: NULL or the most recently accessed thread local context */ + PyDecContextObject *cached_context; +#else + PyObject *current_context_var; +#endif +} decimal_state; + +static decimal_state global_state; + +#define GLOBAL_STATE() (&global_state) #undef MPD #undef CTX @@ -1564,8 +1563,8 @@ current_context_from_dict(void) return NULL; } - PyObject *tl_context = PyDict_GetItemWithError(dict, - state->tls_context_key); + PyObject *tl_context; + tl_context = PyDict_GetItemWithError(dict, modstate->tls_context_key); if (tl_context != NULL) { /* We already have a thread local context. */ CONTEXT_CHECK(modstate, tl_context); @@ -1582,7 +1581,7 @@ current_context_from_dict(void) } CTX(tl_context)->status = 0; - if (PyDict_SetItem(dict, state->tls_context_key, tl_context) < 0) { + if (PyDict_SetItem(dict, modstate->tls_context_key, tl_context) < 0) { Py_DECREF(tl_context); return NULL; } @@ -1591,8 +1590,8 @@ current_context_from_dict(void) /* Cache the context of the current thread, assuming that it * will be accessed several times before a thread switch. */ - state->cached_context = (PyDecContextObject *)tl_context; - state->cached_context->tstate = tstate; + modstate->cached_context = (PyDecContextObject *)tl_context; + modstate->cached_context->tstate = tstate; /* Borrowed reference with refcount==1 */ return tl_context; From 617067e947f0a23fa0a330bb0a5ff7f823273d5e Mon Sep 17 00:00:00 2001 From: CharlieZhao Date: Tue, 4 Jul 2023 15:38:10 +0800 Subject: [PATCH 04/10] Fix git merge --- Modules/_decimal/_decimal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index e94ae45894c29f..5a1d3dc00ffabc 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -1575,7 +1575,7 @@ current_context_from_dict(void) } /* Set up a new thread local context. */ - tl_context = context_copy(state->default_context_template, NULL); + tl_context = context_copy(modstate->default_context_template, NULL); if (tl_context == NULL) { return NULL; } From b9c5ac9cf4a86e92fc9731267b2a328b0a2b71d7 Mon Sep 17 00:00:00 2001 From: CharlieZhao Date: Tue, 4 Jul 2023 18:30:33 +0800 Subject: [PATCH 05/10] Add names to structures --- Modules/_decimal/_decimal.c | 76 +++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 37 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 5a1d3dc00ffabc..a1b5b98478cf41 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -39,6 +39,41 @@ #include "docstrings.h" +struct PyDecContextObject; + +typedef struct _decimal_state { + PyTypeObject *PyDecContextManager_Type; + PyTypeObject *PyDecContext_Type; + PyTypeObject *PyDecSignalDictMixin_Type; + PyTypeObject *PyDec_Type; + PyTypeObject *PyDecSignalDict_Type; + PyTypeObject *DecimalTuple; + + /* Top level Exception; inherits from ArithmeticError */ + PyObject *DecimalException; + +#ifndef WITH_DECIMAL_CONTEXTVAR + /* Key for thread state dictionary */ + PyObject *tls_context_key; + /* Invariant: NULL or the most recently accessed thread local context */ + struct PyDecContextObject *cached_context; +#else + PyObject *current_context_var; +#endif + + /* Template for creating new thread contexts, calling Context() without + * arguments and initializing the module_context on first access. */ + PyObject *default_context_template; + + /* Basic and extended context templates */ + PyObject *basic_context_template; + PyObject *extended_context_template; +} decimal_state; + +static decimal_state global_state; + +#define GLOBAL_STATE() (&global_state) + #if !defined(MPD_VERSION_HEX) || MPD_VERSION_HEX < 0x02050000 #error "libmpdec version >= 2.5.0 required" #endif @@ -68,19 +103,19 @@ /* _Py_DEC_MINALLOC >= MPD_MINALLOC */ #define _Py_DEC_MINALLOC 4 -typedef struct { +typedef struct PyDecObject { PyObject_HEAD Py_hash_t hash; mpd_t dec; mpd_uint_t data[_Py_DEC_MINALLOC]; } PyDecObject; -typedef struct { +typedef struct PyDecSignalDictObject { PyObject_HEAD uint32_t *flags; } PyDecSignalDictObject; -typedef struct { +typedef struct PyDecContextObject { PyObject_HEAD mpd_context_t ctx; PyObject *traps; @@ -89,45 +124,12 @@ typedef struct { PyThreadState *tstate; } PyDecContextObject; -typedef struct { +typedef struct PyDecContextManagerObject { PyObject_HEAD PyObject *local; PyObject *global; } PyDecContextManagerObject; -typedef struct { - PyTypeObject *PyDecContextManager_Type; - PyTypeObject *PyDecContext_Type; - PyTypeObject *PyDecSignalDictMixin_Type; - PyTypeObject *PyDec_Type; - PyTypeObject *PyDecSignalDict_Type; - PyTypeObject *DecimalTuple; - - /* Top level Exception; inherits from ArithmeticError */ - PyObject *DecimalException; - -#ifndef WITH_DECIMAL_CONTEXTVAR - /* Key for thread state dictionary */ - PyObject *tls_context_key; - /* Invariant: NULL or the most recently accessed thread local context */ - PyDecContextObject *cached_context; -#else - PyObject *current_context_var; -#endif - - /* Template for creating new thread contexts, calling Context() without - * arguments and initializing the module_context on first access. */ - PyObject *default_context_template; - - /* Basic and extended context templates */ - PyObject *basic_context_template; - PyObject *extended_context_template; -} decimal_state; - -static decimal_state global_state; - -#define GLOBAL_STATE() (&global_state) - #undef MPD #undef CTX #define PyDec_CheckExact(st, v) Py_IS_TYPE(v, (st)->PyDec_Type) From c3e84788558cf64e8bf00e3f1fb3b05ae3362e3b Mon Sep 17 00:00:00 2001 From: CharlieZhao Date: Thu, 6 Jul 2023 10:00:29 +0800 Subject: [PATCH 06/10] Rename state to modstate --- Modules/_decimal/_decimal.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index a1b5b98478cf41..4a32a69ec9d003 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -1604,9 +1604,9 @@ static PyObject * current_context(void) { PyThreadState *tstate = _PyThreadState_GET(); - decimal_state *state = GLOBAL_STATE(); - if (state->cached_context && state->cached_context->tstate == tstate) { - return (PyObject *)(state->cached_context); + decimal_state *modstate = GLOBAL_STATE(); + if (modstate->cached_context && modstate->cached_context->tstate == tstate) { + return (PyObject *)(modstate->cached_context); } return current_context_from_dict(); From 3df61b80dc3bd2348427d60547a8e52129039873 Mon Sep 17 00:00:00 2001 From: Charlie Zhao Date: Fri, 7 Jul 2023 16:28:48 +0800 Subject: [PATCH 07/10] Update Modules/_decimal/_decimal.c Co-authored-by: Erlend E. Aasland --- Modules/_decimal/_decimal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 4a32a69ec9d003..f417ba063ab701 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -41,7 +41,7 @@ struct PyDecContextObject; -typedef struct _decimal_state { +typedef struct { PyTypeObject *PyDecContextManager_Type; PyTypeObject *PyDecContext_Type; PyTypeObject *PyDecSignalDictMixin_Type; From 1c13d341f40e0672c5e442e3f73617864bc1bd67 Mon Sep 17 00:00:00 2001 From: Charlie Zhao Date: Fri, 7 Jul 2023 16:29:09 +0800 Subject: [PATCH 08/10] Update Modules/_decimal/_decimal.c Co-authored-by: Erlend E. Aasland --- Modules/_decimal/_decimal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index f417ba063ab701..a5139d5199b13f 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -103,7 +103,7 @@ static decimal_state global_state; /* _Py_DEC_MINALLOC >= MPD_MINALLOC */ #define _Py_DEC_MINALLOC 4 -typedef struct PyDecObject { +typedef struct { PyObject_HEAD Py_hash_t hash; mpd_t dec; From 17710fe8f59456ce878cc8803ad1db4b1ef4e700 Mon Sep 17 00:00:00 2001 From: Charlie Zhao Date: Fri, 7 Jul 2023 16:29:22 +0800 Subject: [PATCH 09/10] Update Modules/_decimal/_decimal.c Co-authored-by: Erlend E. Aasland --- Modules/_decimal/_decimal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index a5139d5199b13f..ed59038b4eea4f 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -110,7 +110,7 @@ typedef struct { mpd_uint_t data[_Py_DEC_MINALLOC]; } PyDecObject; -typedef struct PyDecSignalDictObject { +typedef struct { PyObject_HEAD uint32_t *flags; } PyDecSignalDictObject; From 906521ff6d9c31b733bc7355f0d0f3ab698ed14c Mon Sep 17 00:00:00 2001 From: Charlie Zhao Date: Fri, 7 Jul 2023 16:29:56 +0800 Subject: [PATCH 10/10] Update Modules/_decimal/_decimal.c Co-authored-by: Erlend E. Aasland --- Modules/_decimal/_decimal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index ed59038b4eea4f..7e1809cfb98b29 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -124,7 +124,7 @@ typedef struct PyDecContextObject { PyThreadState *tstate; } PyDecContextObject; -typedef struct PyDecContextManagerObject { +typedef struct { PyObject_HEAD PyObject *local; PyObject *global;