[Python-checkins] gh-106078: Isolate `decimal` module (#107287)

kumaraditya303 webhook-mailer at python.org
Fri Jul 28 01:58:18 EDT 2023


https://github.com/python/cpython/commit/a43cc3fa1ffebfd15eff2c6d8e5433a17969e348
commit: a43cc3fa1ffebfd15eff2c6d8e5433a17969e348
branch: main
author: Charlie Zhao <zhaoyu_hit at qq.com>
committer: kumaraditya303 <kumaraditya at python.org>
date: 2023-07-28T11:28:14+05:30
summary:

gh-106078: Isolate `decimal` module (#107287)

files:
A Misc/NEWS.d/next/Core and Builtins/2023-07-27-11-18-04.gh-issue-106078.WEy2Yn.rst
M Modules/_decimal/_decimal.c
M Tools/c-analyzer/cpython/globals-to-fix.tsv

diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-27-11-18-04.gh-issue-106078.WEy2Yn.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-27-11-18-04.gh-issue-106078.WEy2Yn.rst
new file mode 100644
index 0000000000000..f5a0e539e5d05
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-27-11-18-04.gh-issue-106078.WEy2Yn.rst	
@@ -0,0 +1 @@
+Isolate :mod:`!_decimal` (apply :pep:`687`). Patch by Charlie Zhao.
\ No newline at end of file
diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c
index 671976a220a64..7a206973975cc 100644
--- a/Modules/_decimal/_decimal.c
+++ b/Modules/_decimal/_decimal.c
@@ -95,9 +95,36 @@ typedef struct {
     PyCFunction _py_float_as_integer_ratio;
 } decimal_state;
 
-static decimal_state global_state;
+static inline decimal_state *
+get_module_state(PyObject *mod)
+{
+    decimal_state *state = _PyModule_GetState(mod);
+    assert(state != NULL);
+    return state;
+}
+
+static struct PyModuleDef _decimal_module;
+
+static inline decimal_state *
+get_module_state_by_def(PyTypeObject *tp)
+{
+    PyObject *mod = PyType_GetModuleByDef(tp, &_decimal_module);
+    assert(mod != NULL);
+    return get_module_state(mod);
+}
+
+static inline decimal_state *
+find_state_left_or_right(PyObject *left, PyObject *right)
+{
+    PyObject *mod = PyType_GetModuleByDef(Py_TYPE(left), &_decimal_module);
+    if (mod == NULL) {
+        PyErr_Clear();
+        mod = PyType_GetModuleByDef(Py_TYPE(right), &_decimal_module);
+    }
+    assert(mod != NULL);
+    return get_module_state(mod);
+}
 
-#define GLOBAL_STATE() (&global_state)
 
 #if !defined(MPD_VERSION_HEX) || MPD_VERSION_HEX < 0x02050000
   #error "libmpdec version >= 2.5.0 required"
@@ -328,10 +355,9 @@ dec_traphandler(mpd_context_t *ctx UNUSED) /* GCOV_NOT_REACHED */
 }
 
 static PyObject *
-flags_as_exception(uint32_t flags)
+flags_as_exception(decimal_state *state, uint32_t flags)
 {
     DecCondMap *cm;
-    decimal_state *state = GLOBAL_STATE();
 
     for (cm = state->signal_map; cm->name != NULL; cm++) {
         if (flags&cm->flag) {
@@ -343,10 +369,9 @@ flags_as_exception(uint32_t flags)
 }
 
 Py_LOCAL_INLINE(uint32_t)
-exception_as_flag(PyObject *ex)
+exception_as_flag(decimal_state *state, PyObject *ex)
 {
     DecCondMap *cm;
-    decimal_state *state = GLOBAL_STATE();
 
     for (cm = state->signal_map; cm->name != NULL; cm++) {
         if (cm->ex == ex) {
@@ -359,11 +384,10 @@ exception_as_flag(PyObject *ex)
 }
 
 static PyObject *
-flags_as_list(uint32_t flags)
+flags_as_list(decimal_state *state, uint32_t flags)
 {
     PyObject *list;
     DecCondMap *cm;
-    decimal_state *state = GLOBAL_STATE();
 
     list = PyList_New(0);
     if (list == NULL) {
@@ -393,11 +417,10 @@ flags_as_list(uint32_t flags)
 }
 
 static PyObject *
-signals_as_list(uint32_t flags)
+signals_as_list(decimal_state *state, uint32_t flags)
 {
     PyObject *list;
     DecCondMap *cm;
-    decimal_state *state = GLOBAL_STATE();
 
     list = PyList_New(0);
     if (list == NULL) {
@@ -417,7 +440,7 @@ signals_as_list(uint32_t flags)
 }
 
 static uint32_t
-list_as_flags(PyObject *list)
+list_as_flags(decimal_state *state, PyObject *list)
 {
     PyObject *item;
     uint32_t flags, x;
@@ -429,7 +452,7 @@ list_as_flags(PyObject *list)
     flags = 0;
     for (j = 0; j < n; j++) {
         item = PyList_GetItem(list, j);
-        x = exception_as_flag(item);
+        x = exception_as_flag(state, item);
         if (x & DEC_ERRORS) {
             return x;
         }
@@ -440,11 +463,10 @@ list_as_flags(PyObject *list)
 }
 
 static PyObject *
-flags_as_dict(uint32_t flags)
+flags_as_dict(decimal_state *state, uint32_t flags)
 {
     DecCondMap *cm;
     PyObject *dict;
-    decimal_state *state = GLOBAL_STATE();
 
     dict = PyDict_New();
     if (dict == NULL) {
@@ -463,13 +485,12 @@ flags_as_dict(uint32_t flags)
 }
 
 static uint32_t
-dict_as_flags(PyObject *val)
+dict_as_flags(decimal_state *state, PyObject *val)
 {
     PyObject *b;
     DecCondMap *cm;
     uint32_t flags = 0;
     int x;
-    decimal_state *state = GLOBAL_STATE();
 
     if (!PyDict_Check(val)) {
         PyErr_SetString(PyExc_TypeError,
@@ -529,6 +550,7 @@ static int
 dec_addstatus(PyObject *context, uint32_t status)
 {
     mpd_context_t *ctx = CTX(context);
+    decimal_state *state = get_module_state_by_def(Py_TYPE(context));
 
     ctx->status |= status;
     if (status & (ctx->traps|MPD_Malloc_error)) {
@@ -539,11 +561,11 @@ dec_addstatus(PyObject *context, uint32_t status)
             return 1;
         }
 
-        ex = flags_as_exception(ctx->traps&status);
+        ex = flags_as_exception(state, ctx->traps&status);
         if (ex == NULL) {
             return 1; /* GCOV_NOT_REACHED */
         }
-        siglist = flags_as_list(ctx->traps&status);
+        siglist = flags_as_list(state, ctx->traps&status);
         if (siglist == NULL) {
             return 1;
         }
@@ -556,11 +578,9 @@ dec_addstatus(PyObject *context, uint32_t status)
 }
 
 static int
-getround(PyObject *v)
+getround(decimal_state *state, PyObject *v)
 {
     int i;
-    decimal_state *state = GLOBAL_STATE();
-
     if (PyUnicode_Check(v)) {
         for (i = 0; i < _PY_DEC_ROUND_GUARD; i++) {
             if (v == state->round_map[i]) {
@@ -602,9 +622,9 @@ signaldict_len(PyObject *self UNUSED)
 }
 
 static PyObject *
-signaldict_iter(PyObject *self UNUSED)
+signaldict_iter(PyObject *self)
 {
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
     return PyTuple_Type.tp_iter(state->SignalTuple);
 }
 
@@ -612,8 +632,9 @@ static PyObject *
 signaldict_getitem(PyObject *self, PyObject *key)
 {
     uint32_t flag;
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
 
-    flag = exception_as_flag(key);
+    flag = exception_as_flag(state, key);
     if (flag & DEC_ERRORS) {
         return NULL;
     }
@@ -627,11 +648,12 @@ signaldict_setitem(PyObject *self, PyObject *key, PyObject *value)
     uint32_t flag;
     int x;
 
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
     if (value == NULL) {
         return value_error_int("signal keys cannot be deleted");
     }
 
-    flag = exception_as_flag(key);
+    flag = exception_as_flag(state, key);
     if (flag & DEC_ERRORS) {
         return -1;
     }
@@ -677,7 +699,7 @@ signaldict_repr(PyObject *self)
 
     assert(SIGNAL_MAP_LEN == 9);
 
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
     for (cm=state->signal_map, i=0; cm->name != NULL; cm++, i++) {
         n[i] = cm->fqname;
         b[i] = SdFlags(self)&cm->flag ? "True" : "False";
@@ -696,7 +718,7 @@ signaldict_richcompare(PyObject *v, PyObject *w, int op)
 {
     PyObject *res = Py_NotImplemented;
 
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = find_state_left_or_right(v, w);
     assert(PyDecSignalDict_Check(state, v));
 
     if (op == Py_EQ || op == Py_NE) {
@@ -704,7 +726,7 @@ signaldict_richcompare(PyObject *v, PyObject *w, int op)
             res = (SdFlags(v)==SdFlags(w)) ^ (op==Py_NE) ? Py_True : Py_False;
         }
         else if (PyDict_Check(w)) {
-            uint32_t flags = dict_as_flags(w);
+            uint32_t flags = dict_as_flags(state, w);
             if (flags & DEC_ERRORS) {
                 if (flags & DEC_INVALID_SIGNALS) {
                     /* non-comparable: Py_NotImplemented */
@@ -726,7 +748,8 @@ signaldict_richcompare(PyObject *v, PyObject *w, int op)
 static PyObject *
 signaldict_copy(PyObject *self, PyObject *args UNUSED)
 {
-    return flags_as_dict(SdFlags(self));
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
+    return flags_as_dict(state, SdFlags(self));
 }
 
 
@@ -795,7 +818,7 @@ static PyObject *
 context_getround(PyObject *self, void *closure UNUSED)
 {
     int i = mpd_getround(CTX(self));
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
 
     return Py_NewRef(state->round_map[i]);
 }
@@ -954,7 +977,8 @@ context_setround(PyObject *self, PyObject *value, void *closure UNUSED)
     mpd_context_t *ctx;
     int x;
 
-    x = getround(value);
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
+    x = getround(state, value);
     if (x == -1) {
         return -1;
     }
@@ -1012,8 +1036,8 @@ context_settraps_list(PyObject *self, PyObject *value)
 {
     mpd_context_t *ctx;
     uint32_t flags;
-
-    flags = list_as_flags(value);
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
+    flags = list_as_flags(state, value);
     if (flags & DEC_ERRORS) {
         return -1;
     }
@@ -1032,12 +1056,12 @@ context_settraps_dict(PyObject *self, PyObject *value)
     mpd_context_t *ctx;
     uint32_t flags;
 
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
     if (PyDecSignalDict_Check(state, value)) {
         flags = SdFlags(value);
     }
     else {
-        flags = dict_as_flags(value);
+        flags = dict_as_flags(state, value);
         if (flags & DEC_ERRORS) {
             return -1;
         }
@@ -1077,8 +1101,9 @@ context_setstatus_list(PyObject *self, PyObject *value)
 {
     mpd_context_t *ctx;
     uint32_t flags;
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
 
-    flags = list_as_flags(value);
+    flags = list_as_flags(state, value);
     if (flags & DEC_ERRORS) {
         return -1;
     }
@@ -1097,12 +1122,12 @@ context_setstatus_dict(PyObject *self, PyObject *value)
     mpd_context_t *ctx;
     uint32_t flags;
 
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
     if (PyDecSignalDict_Check(state, value)) {
         flags = SdFlags(value);
     }
     else {
-        flags = dict_as_flags(value);
+        flags = dict_as_flags(state, value);
         if (flags & DEC_ERRORS) {
             return -1;
         }
@@ -1288,7 +1313,7 @@ context_new(PyTypeObject *type, PyObject *args UNUSED, PyObject *kwds UNUSED)
     PyDecContextObject *self = NULL;
     mpd_context_t *ctx;
 
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(type);
     if (type == state->PyDecContext_Type) {
         self = PyObject_GC_New(PyDecContextObject, state->PyDecContext_Type);
     }
@@ -1353,7 +1378,7 @@ context_dealloc(PyDecContextObject *self)
     PyTypeObject *tp = Py_TYPE(self);
     PyObject_GC_UnTrack(self);
 #ifndef WITH_DECIMAL_CONTEXTVAR
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
     if (self == state->cached_context) {
         state->cached_context = NULL;
     }
@@ -1405,7 +1430,7 @@ context_repr(PyDecContextObject *self)
     int n, mem;
 
 #ifdef Py_DEBUG
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
     assert(PyDecContext_Check(state, self));
 #endif
     ctx = CTX(self);
@@ -1473,7 +1498,7 @@ ieee_context(PyObject *dummy UNUSED, PyObject *v)
         goto error;
     }
 
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(v));
     context = PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL);
     if (context == NULL) {
         return NULL;
@@ -1496,7 +1521,7 @@ context_copy(PyObject *self, PyObject *args UNUSED)
 {
     PyObject *copy;
 
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
     copy = PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL);
     if (copy == NULL) {
         return NULL;
@@ -1516,14 +1541,15 @@ context_reduce(PyObject *self, PyObject *args UNUSED)
     PyObject *traps;
     PyObject *ret;
     mpd_context_t *ctx;
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
 
     ctx = CTX(self);
 
-    flags = signals_as_list(ctx->status);
+    flags = signals_as_list(state, ctx->status);
     if (flags == NULL) {
         return NULL;
     }
-    traps = signals_as_list(ctx->traps);
+    traps = signals_as_list(state, ctx->traps);
     if (traps == NULL) {
         Py_DECREF(flags);
         return NULL;
@@ -1568,7 +1594,7 @@ static PyGetSetDef context_getsets [] =
 
 #define CONTEXT_CHECK_VA(state, obj) \
     if (obj == Py_None) {                           \
-        CURRENT_CONTEXT(obj);                       \
+        CURRENT_CONTEXT(state, obj);                \
     }                                               \
     else if (!PyDecContext_Check(state, obj)) {     \
         PyErr_SetString(PyExc_TypeError,            \
@@ -1591,10 +1617,9 @@ static PyGetSetDef context_getsets [] =
 #ifndef WITH_DECIMAL_CONTEXTVAR
 /* Get the context from the thread state dictionary. */
 static PyObject *
-current_context_from_dict(void)
+current_context_from_dict(decimal_state *modstate)
 {
     PyThreadState *tstate = _PyThreadState_GET();
-    decimal_state *modstate = GLOBAL_STATE();
 #ifdef Py_DEBUG
     // The caller must hold the GIL
     _Py_EnsureTstateNotNULL(tstate);
@@ -1643,45 +1668,41 @@ current_context_from_dict(void)
 
 /* Return borrowed reference to thread local context. */
 static PyObject *
-current_context(void)
+current_context(decimal_state *modstate)
 {
     PyThreadState *tstate = _PyThreadState_GET();
-    decimal_state *modstate = GLOBAL_STATE();
     if (modstate->cached_context && modstate->cached_context->tstate == tstate) {
         return (PyObject *)(modstate->cached_context);
     }
 
-    return current_context_from_dict();
+    return current_context_from_dict(modstate);
 }
 
 /* ctxobj := borrowed reference to the current context */
-#define CURRENT_CONTEXT(ctxobj) \
-    ctxobj = current_context(); \
+#define CURRENT_CONTEXT(state, ctxobj) \
+    ctxobj = current_context(state); \
     if (ctxobj == NULL) {       \
         return NULL;            \
     }
 
 /* Return a new reference to the current context */
 static PyObject *
-PyDec_GetCurrentContext(PyObject *self UNUSED, PyObject *args UNUSED)
+PyDec_GetCurrentContext(PyObject *self, PyObject *args UNUSED)
 {
     PyObject *context;
+    decimal_state *state = get_module_state(self);
 
-    context = current_context();
-    if (context == NULL) {
-        return NULL;
-    }
-
+    CURRENT_CONTEXT(state, context);
     return Py_NewRef(context);
 }
 
 /* Set the thread local context to a new context, decrement old reference */
 static PyObject *
-PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v)
+PyDec_SetCurrentContext(PyObject *self, PyObject *v)
 {
     PyObject *dict;
 
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state(self);
     CONTEXT_CHECK(state, v);
 
     dict = PyThreadState_GetDict();
@@ -1717,9 +1738,8 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v)
 }
 #else
 static PyObject *
-init_current_context(void)
+init_current_context(decimal_state *state)
 {
-    decimal_state *state = GLOBAL_STATE();
     PyObject *tl_context = context_copy(state->default_context_template, NULL);
     if (tl_context == NULL) {
         return NULL;
@@ -1737,10 +1757,9 @@ init_current_context(void)
 }
 
 static inline PyObject *
-current_context(void)
+current_context(decimal_state *state)
 {
     PyObject *tl_context;
-    decimal_state *state = GLOBAL_STATE();
     if (PyContextVar_Get(state->current_context_var, NULL, &tl_context) < 0) {
         return NULL;
     }
@@ -1749,12 +1768,12 @@ current_context(void)
         return tl_context;
     }
 
-    return init_current_context();
+    return init_current_context(state);
 }
 
 /* ctxobj := borrowed reference to the current context */
-#define CURRENT_CONTEXT(ctxobj) \
-    ctxobj = current_context(); \
+#define CURRENT_CONTEXT(state, ctxobj) \
+    ctxobj = current_context(state);   \
     if (ctxobj == NULL) {       \
         return NULL;            \
     }                           \
@@ -1762,16 +1781,17 @@ current_context(void)
 
 /* Return a new reference to the current context */
 static PyObject *
-PyDec_GetCurrentContext(PyObject *self UNUSED, PyObject *args UNUSED)
+PyDec_GetCurrentContext(PyObject *self, PyObject *args UNUSED)
 {
-    return current_context();
+    decimal_state *state = get_module_state(self);
+    return current_context(state);
 }
 
 /* Set the thread local context to a new context, decrement old reference */
 static PyObject *
-PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v)
+PyDec_SetCurrentContext(PyObject *self, PyObject *v)
 {
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state(self);
     CONTEXT_CHECK(state, v);
 
     /* If the new context is one of the templates, make a copy.
@@ -1804,7 +1824,7 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v)
  * owns one reference to the global (outer) context and one
  * to the local (inner) context. */
 static PyObject *
-ctxmanager_new(PyTypeObject *type UNUSED, PyObject *args, PyObject *kwds)
+ctxmanager_new(PyObject *m, PyObject *args, PyObject *kwds)
 {
     static char *kwlist[] = {
       "ctx", "prec", "rounding",
@@ -1824,8 +1844,8 @@ ctxmanager_new(PyTypeObject *type UNUSED, PyObject *args, PyObject *kwds)
     PyObject *flags = Py_None;
     PyObject *traps = Py_None;
 
-    decimal_state *state = GLOBAL_STATE();
-    CURRENT_CONTEXT(global);
+    decimal_state *state = get_module_state(m);
+    CURRENT_CONTEXT(state, global);
     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOOOOOOO", kwlist, &local,
           &prec, &rounding, &Emin, &Emax, &capitals, &clamp, &flags, &traps)) {
         return NULL;
@@ -1902,7 +1922,7 @@ ctxmanager_set_local(PyDecContextManagerObject *self, PyObject *args UNUSED)
 {
     PyObject *ret;
 
-    ret = PyDec_SetCurrentContext(NULL, self->local);
+    ret = PyDec_SetCurrentContext(PyType_GetModule(Py_TYPE(self)), self->local);
     if (ret == NULL) {
         return NULL;
     }
@@ -1917,7 +1937,7 @@ ctxmanager_restore_global(PyDecContextManagerObject *self,
 {
     PyObject *ret;
 
-    ret = PyDec_SetCurrentContext(NULL, self->global);
+    ret = PyDec_SetCurrentContext(PyType_GetModule(Py_TYPE(self)), self->global);
     if (ret == NULL) {
         return NULL;
     }
@@ -1960,7 +1980,7 @@ PyDecType_New(PyTypeObject *type)
 {
     PyDecObject *dec;
 
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(type);
     if (type == state->PyDec_Type) {
         dec = PyObject_GC_New(PyDecObject, state->PyDec_Type);
     }
@@ -2347,8 +2367,8 @@ PyDecType_FromFloatExact(PyTypeObject *type, PyObject *v,
     mpd_t *d1, *d2;
     uint32_t status = 0;
     mpd_context_t maxctx;
+    decimal_state *state = get_module_state_by_def(type);
 
-    decimal_state *state = GLOBAL_STATE();
 #ifdef Py_DEBUG
     assert(PyType_IsSubtype(type, state->PyDec_Type));
 #endif
@@ -2485,7 +2505,7 @@ PyDecType_FromDecimalExact(PyTypeObject *type, PyObject *v, PyObject *context)
     PyObject *dec;
     uint32_t status = 0;
 
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(type);
     if (type == state->PyDec_Type && PyDec_CheckExact(state, v)) {
         return Py_NewRef(v);
     }
@@ -2760,8 +2780,8 @@ dec_from_float(PyObject *type, PyObject *pyfloat)
     PyObject *context;
     PyObject *result;
 
-    CURRENT_CONTEXT(context);
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def((PyTypeObject *)type);
+    CURRENT_CONTEXT(state, context);
     result = PyDecType_FromFloatExact(state->PyDec_Type, pyfloat, context);
     if (type != (PyObject *)state->PyDec_Type && result != NULL) {
         Py_SETREF(result, PyObject_CallFunctionObjArgs(type, result, NULL));
@@ -2774,7 +2794,7 @@ dec_from_float(PyObject *type, PyObject *pyfloat)
 static PyObject *
 ctx_from_float(PyObject *context, PyObject *v)
 {
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(context));
     return PyDec_FromFloat(state, v, context);
 }
 
@@ -2785,7 +2805,7 @@ dec_apply(PyObject *v, PyObject *context)
     PyObject *result;
     uint32_t status = 0;
 
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(context));
     result = dec_alloc(state);
     if (result == NULL) {
         return NULL;
@@ -2812,7 +2832,7 @@ dec_apply(PyObject *v, PyObject *context)
 static PyObject *
 PyDecType_FromObjectExact(PyTypeObject *type, PyObject *v, PyObject *context)
 {
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(type);
     if (v == NULL) {
         return PyDecType_FromSsizeExact(type, 0, context);
     }
@@ -2847,7 +2867,7 @@ PyDecType_FromObjectExact(PyTypeObject *type, PyObject *v, PyObject *context)
 static PyObject *
 PyDec_FromObject(PyObject *v, PyObject *context)
 {
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(context));
     if (v == NULL) {
         return PyDec_FromSsize(state, 0, context);
     }
@@ -2903,7 +2923,7 @@ dec_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
                                      &v, &context)) {
         return NULL;
     }
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(type);
     CONTEXT_CHECK_VA(state, context);
 
     return PyDecType_FromObjectExact(type, v, context);
@@ -2934,7 +2954,7 @@ ctx_create_decimal(PyObject *context, PyObject *args)
 Py_LOCAL_INLINE(int)
 convert_op(int type_err, PyObject **conv, PyObject *v, PyObject *context)
 {
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(context));
     if (PyDec_Check(state, v)) {
         *conv = Py_NewRef(v);
         return 1;
@@ -3037,7 +3057,7 @@ multiply_by_denominator(PyObject *v, PyObject *r, PyObject *context)
     if (tmp == NULL) {
         return NULL;
     }
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(context));
     denom = PyDec_FromLongExact(state, tmp, context);
     Py_DECREF(tmp);
     if (denom == NULL) {
@@ -3092,7 +3112,7 @@ numerator_as_decimal(PyObject *r, PyObject *context)
         return NULL;
     }
 
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(context));
     num = PyDec_FromLongExact(state, tmp, context);
     Py_DECREF(tmp);
     return num;
@@ -3111,7 +3131,7 @@ convert_op_cmp(PyObject **vcmp, PyObject **wcmp, PyObject *v, PyObject *w,
 
     *vcmp = v;
 
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(context));
     if (PyDec_Check(state, w)) {
         *wcmp = Py_NewRef(w);
     }
@@ -3209,7 +3229,8 @@ dec_str(PyObject *dec)
     mpd_ssize_t size;
     char *cp;
 
-    CURRENT_CONTEXT(context);
+    decimal_state *state = get_module_state_by_def(Py_TYPE(dec));
+    CURRENT_CONTEXT(state, context);
     size = mpd_to_sci_size(&cp, MPD(dec), CtxCaps(context));
     if (size < 0) {
         PyErr_NoMemory();
@@ -3227,8 +3248,8 @@ dec_repr(PyObject *dec)
 {
     PyObject *res, *context;
     char *cp;
-
-    CURRENT_CONTEXT(context);
+    decimal_state *state = get_module_state_by_def(Py_TYPE(dec));
+    CURRENT_CONTEXT(state, context);
     cp = mpd_to_sci(MPD(dec), CtxCaps(context));
     if (cp == NULL) {
         PyErr_NoMemory();
@@ -3389,7 +3410,8 @@ dec_format(PyObject *dec, PyObject *args)
     mpd_t tmp = {MPD_STATIC|MPD_STATIC_DATA,0,0,0,MPD_MINALLOC_MAX,dt};
 
 
-    CURRENT_CONTEXT(context);
+    decimal_state *state = get_module_state_by_def(Py_TYPE(dec));
+    CURRENT_CONTEXT(state, context);
     if (!PyArg_ParseTuple(args, "O|O", &fmtarg, &override)) {
         return NULL;
     }
@@ -3652,9 +3674,9 @@ dec_as_integer_ratio(PyObject *self, PyObject *args UNUSED)
         return NULL;
     }
 
-    CURRENT_CONTEXT(context);
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
+    CURRENT_CONTEXT(state, context);
 
-    decimal_state *state = GLOBAL_STATE();
     tmp = dec_alloc(state);
     if (tmp == NULL) {
         return NULL;
@@ -3745,12 +3767,12 @@ PyDec_ToIntegralValue(PyObject *dec, PyObject *args, PyObject *kwds)
                                      &rounding, &context)) {
         return NULL;
     }
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(dec));
     CONTEXT_CHECK_VA(state, context);
 
     workctx = *CTX(context);
     if (rounding != Py_None) {
-        int round = getround(rounding);
+        int round = getround(state, rounding);
         if (round < 0) {
             return NULL;
         }
@@ -3787,12 +3809,12 @@ PyDec_ToIntegralExact(PyObject *dec, PyObject *args, PyObject *kwds)
                                      &rounding, &context)) {
         return NULL;
     }
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(dec));
     CONTEXT_CHECK_VA(state, context);
 
     workctx = *CTX(context);
     if (rounding != Py_None) {
-        int round = getround(rounding);
+        int round = getround(state, rounding);
         if (round < 0) {
             return NULL;
         }
@@ -3855,7 +3877,8 @@ PyDec_Round(PyObject *dec, PyObject *args)
     uint32_t status = 0;
     PyObject *context;
 
-    CURRENT_CONTEXT(context);
+    decimal_state *state = get_module_state_by_def(Py_TYPE(dec));
+    CURRENT_CONTEXT(state, context);
     if (!PyArg_ParseTuple(args, "|O", &x)) {
         return NULL;
     }
@@ -3875,7 +3898,6 @@ PyDec_Round(PyObject *dec, PyObject *args)
         if (y == -1 && PyErr_Occurred()) {
             return NULL;
         }
-        decimal_state *state = GLOBAL_STATE();
         result = dec_alloc(state);
         if (result == NULL) {
             return NULL;
@@ -3977,7 +3999,7 @@ PyDec_AsTuple(PyObject *dec, PyObject *dummy UNUSED)
         }
     }
 
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(dec));
     result = PyObject_CallFunctionObjArgs((PyObject *)state->DecimalTuple,
                                           sign, coeff, expt, NULL);
 
@@ -4004,8 +4026,8 @@ nm_##MPDFUNC(PyObject *self)                                \
     PyObject *context;                                      \
     uint32_t status = 0;                                    \
                                                             \
-    decimal_state *state = GLOBAL_STATE();                  \
-    CURRENT_CONTEXT(context);                               \
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));   \
+    CURRENT_CONTEXT(state, context);                        \
     if ((result = dec_alloc(state)) == NULL) {              \
         return NULL;                                        \
     }                                                       \
@@ -4029,8 +4051,8 @@ nm_##MPDFUNC(PyObject *self, PyObject *other)                    \
     PyObject *context;                                           \
     uint32_t status = 0;                                         \
                                                                  \
-    decimal_state *state = GLOBAL_STATE();                       \
-    CURRENT_CONTEXT(context) ;                                   \
+    decimal_state *state = find_state_left_or_right(self, other);  \
+    CURRENT_CONTEXT(state, context) ;                            \
     CONVERT_BINOP(&a, &b, self, other, context);                 \
                                                                  \
     if ((result = dec_alloc(state)) == NULL) {                   \
@@ -4070,7 +4092,7 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds)             \
                                      &context)) {                         \
         return NULL;                                                      \
     }                                                                     \
-    decimal_state *state = GLOBAL_STATE();                                \
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));        \
     CONTEXT_CHECK_VA(state, context);                                     \
                                                                           \
     return MPDFUNC(MPD(self), CTX(context)) ? incr_true() : incr_false(); \
@@ -4090,7 +4112,8 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds)  \
                                      &context)) {              \
         return NULL;                                           \
     }                                                          \
-    decimal_state *state = GLOBAL_STATE();                     \
+    decimal_state *state =                                     \
+        get_module_state_by_def(Py_TYPE(self));                \
     CONTEXT_CHECK_VA(state, context);                          \
                                                                \
     if ((result = dec_alloc(state)) == NULL) {                 \
@@ -4122,7 +4145,8 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds)    \
                                      &other, &context)) {        \
         return NULL;                                             \
     }                                                            \
-    decimal_state *state = GLOBAL_STATE();                       \
+    decimal_state *state =                                       \
+        get_module_state_by_def(Py_TYPE(self));                  \
     CONTEXT_CHECK_VA(state, context);                            \
     CONVERT_BINOP_RAISE(&a, &b, self, other, context);           \
                                                                  \
@@ -4160,7 +4184,8 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds)   \
                                      &other, &context)) {       \
         return NULL;                                            \
     }                                                           \
-    decimal_state *state = GLOBAL_STATE();                      \
+    decimal_state *state =                                      \
+        get_module_state_by_def(Py_TYPE(self));                 \
     CONTEXT_CHECK_VA(state, context);                           \
     CONVERT_BINOP_RAISE(&a, &b, self, other, context);          \
                                                                 \
@@ -4193,7 +4218,7 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds)            \
                                      &other, &third, &context)) {        \
         return NULL;                                                     \
     }                                                                    \
-    decimal_state *state = GLOBAL_STATE();                               \
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));       \
     CONTEXT_CHECK_VA(state, context);                                    \
     CONVERT_TERNOP_RAISE(&a, &b, &c, self, other, third, context);       \
                                                                          \
@@ -4236,8 +4261,8 @@ static PyObject *
 nm_dec_as_long(PyObject *dec)
 {
     PyObject *context;
-
-    CURRENT_CONTEXT(context);
+    decimal_state *state = get_module_state_by_def(Py_TYPE(dec));
+    CURRENT_CONTEXT(state, context);
     return dec_as_long(dec, context, MPD_ROUND_DOWN);
 }
 
@@ -4256,10 +4281,10 @@ nm_mpd_qdivmod(PyObject *v, PyObject *w)
     uint32_t status = 0;
     PyObject *ret;
 
-    CURRENT_CONTEXT(context);
+    decimal_state *state = find_state_left_or_right(v, w);
+    CURRENT_CONTEXT(state, context);
     CONVERT_BINOP(&a, &b, v, w, context);
 
-    decimal_state *state = GLOBAL_STATE();
     q = dec_alloc(state);
     if (q == NULL) {
         Py_DECREF(a);
@@ -4297,7 +4322,8 @@ nm_mpd_qpow(PyObject *base, PyObject *exp, PyObject *mod)
     PyObject *context;
     uint32_t status = 0;
 
-    CURRENT_CONTEXT(context);
+    decimal_state *state = find_state_left_or_right(base, exp);
+    CURRENT_CONTEXT(state, context);
     CONVERT_BINOP(&a, &b, base, exp, context);
 
     if (mod != Py_None) {
@@ -4308,7 +4334,6 @@ nm_mpd_qpow(PyObject *base, PyObject *exp, PyObject *mod)
         }
     }
 
-    decimal_state *state = GLOBAL_STATE();
     result = dec_alloc(state);
     if (result == NULL) {
         Py_DECREF(a);
@@ -4406,11 +4431,11 @@ dec_conjugate(PyObject *self, PyObject *dummy UNUSED)
 }
 
 static PyObject *
-dec_mpd_radix(PyObject *self UNUSED, PyObject *dummy UNUSED)
+dec_mpd_radix(PyObject *self, PyObject *dummy UNUSED)
 {
     PyObject *result;
 
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
     result = dec_alloc(state);
     if (result == NULL) {
         return NULL;
@@ -4426,7 +4451,7 @@ dec_mpd_qcopy_abs(PyObject *self, PyObject *dummy UNUSED)
     PyObject *result;
     uint32_t status = 0;
 
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
     if ((result = dec_alloc(state)) == NULL) {
         return NULL;
     }
@@ -4447,7 +4472,7 @@ dec_mpd_qcopy_negate(PyObject *self, PyObject *dummy UNUSED)
     PyObject *result;
     uint32_t status = 0;
 
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
     if ((result = dec_alloc(state)) == NULL) {
         return NULL;
     }
@@ -4477,7 +4502,7 @@ dec_mpd_class(PyObject *self, PyObject *args, PyObject *kwds)
                                      &context)) {
         return NULL;
     }
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
     CONTEXT_CHECK_VA(state, context);
 
     cp = mpd_class(MPD(self), CTX(context));
@@ -4497,7 +4522,7 @@ dec_mpd_to_eng(PyObject *self, PyObject *args, PyObject *kwds)
                                      &context)) {
         return NULL;
     }
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
     CONTEXT_CHECK_VA(state, context);
 
     size = mpd_to_eng_size(&s, MPD(self), CtxCaps(context));
@@ -4530,7 +4555,7 @@ dec_mpd_qcopy_sign(PyObject *self, PyObject *args, PyObject *kwds)
                                      &other, &context)) {
         return NULL;
     }
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
     CONTEXT_CHECK_VA(state, context);
     CONVERT_BINOP_RAISE(&a, &b, self, other, context);
 
@@ -4565,7 +4590,7 @@ dec_mpd_same_quantum(PyObject *self, PyObject *args, PyObject *kwds)
                                      &other, &context)) {
         return NULL;
     }
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
     CONTEXT_CHECK_VA(state, context);
     CONVERT_BINOP_RAISE(&a, &b, self, other, context);
 
@@ -4600,12 +4625,12 @@ dec_mpd_qquantize(PyObject *v, PyObject *args, PyObject *kwds)
                                      &w, &rounding, &context)) {
         return NULL;
     }
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(v));
     CONTEXT_CHECK_VA(state, context);
 
     workctx = *CTX(context);
     if (rounding != Py_None) {
-        int round = getround(rounding);
+        int round = getround(state, rounding);
         if (round < 0) {
             return NULL;
         }
@@ -4644,12 +4669,12 @@ dec_richcompare(PyObject *v, PyObject *w, int op)
     uint32_t status = 0;
     int a_issnan, b_issnan;
     int r;
+    decimal_state *state = find_state_left_or_right(v, w);
 
 #ifdef Py_DEBUG
-    decimal_state *state = GLOBAL_STATE();
     assert(PyDec_Check(state, v));
 #endif
-    CURRENT_CONTEXT(context);
+    CURRENT_CONTEXT(state, context);
     CONVERT_BINOP_CMP(&a, &b, v, w, op, context);
 
     a_issnan = mpd_issnan(MPD(a));
@@ -4700,7 +4725,8 @@ dec_ceil(PyObject *self, PyObject *dummy UNUSED)
 {
     PyObject *context;
 
-    CURRENT_CONTEXT(context);
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
+    CURRENT_CONTEXT(state, context);
     return dec_as_long(self, context, MPD_ROUND_CEILING);
 }
 
@@ -4738,7 +4764,8 @@ dec_floor(PyObject *self, PyObject *dummy UNUSED)
 {
     PyObject *context;
 
-    CURRENT_CONTEXT(context);
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
+    CURRENT_CONTEXT(state, context);
     return dec_as_long(self, context, MPD_ROUND_FLOOR);
 }
 
@@ -4902,7 +4929,8 @@ dec_trunc(PyObject *self, PyObject *dummy UNUSED)
 {
     PyObject *context;
 
-    CURRENT_CONTEXT(context);
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
+    CURRENT_CONTEXT(state, context);
     return dec_as_long(self, context, MPD_ROUND_DOWN);
 }
 
@@ -4918,7 +4946,7 @@ dec_imag(PyObject *self UNUSED, void *closure UNUSED)
 {
     PyObject *result;
 
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
     result = dec_alloc(state);
     if (result == NULL) {
         return NULL;
@@ -5117,7 +5145,8 @@ ctx_##MPDFUNC(PyObject *context, PyObject *v)            \
     uint32_t status = 0;                                 \
                                                          \
     CONVERT_OP_RAISE(&a, v, context);                    \
-    decimal_state *state = GLOBAL_STATE();               \
+    decimal_state *state =                               \
+        get_module_state_by_def(Py_TYPE(context));       \
     if ((result = dec_alloc(state)) == NULL) {           \
         Py_DECREF(a);                                    \
         return NULL;                                     \
@@ -5148,7 +5177,8 @@ ctx_##MPDFUNC(PyObject *context, PyObject *args)                 \
     }                                                            \
                                                                  \
     CONVERT_BINOP_RAISE(&a, &b, v, w, context);                  \
-    decimal_state *state = GLOBAL_STATE();                       \
+    decimal_state *state =                                       \
+        get_module_state_by_def(Py_TYPE(context));               \
     if ((result = dec_alloc(state)) == NULL) {                   \
         Py_DECREF(a);                                            \
         Py_DECREF(b);                                            \
@@ -5183,7 +5213,8 @@ ctx_##MPDFUNC(PyObject *context, PyObject *args) \
     }                                            \
                                                  \
     CONVERT_BINOP_RAISE(&a, &b, v, w, context);  \
-    decimal_state *state = GLOBAL_STATE();       \
+    decimal_state *state =                       \
+        get_module_state_by_def(Py_TYPE(context)); \
     if ((result = dec_alloc(state)) == NULL) {   \
         Py_DECREF(a);                            \
         Py_DECREF(b);                            \
@@ -5212,7 +5243,7 @@ ctx_##MPDFUNC(PyObject *context, PyObject *args)                         \
     }                                                                    \
                                                                          \
     CONVERT_TERNOP_RAISE(&a, &b, &c, v, w, x, context);                  \
-    decimal_state *state = GLOBAL_STATE();                               \
+    decimal_state *state = get_module_state_by_def(Py_TYPE(context));    \
     if ((result = dec_alloc(state)) == NULL) {                           \
         Py_DECREF(a);                                                    \
         Py_DECREF(b);                                                    \
@@ -5278,7 +5309,7 @@ ctx_mpd_qdivmod(PyObject *context, PyObject *args)
     }
 
     CONVERT_BINOP_RAISE(&a, &b, v, w, context);
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(context));
     q = dec_alloc(state);
     if (q == NULL) {
         Py_DECREF(a);
@@ -5333,7 +5364,7 @@ ctx_mpd_qpow(PyObject *context, PyObject *args, PyObject *kwds)
         }
     }
 
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(context));
     result = dec_alloc(state);
     if (result == NULL) {
         Py_DECREF(a);
@@ -5383,9 +5414,9 @@ DecCtx_BoolFunc_NO_CTX(mpd_issnan)
 DecCtx_BoolFunc_NO_CTX(mpd_iszero)
 
 static PyObject *
-ctx_iscanonical(PyObject *context UNUSED, PyObject *v)
+ctx_iscanonical(PyObject *context, PyObject *v)
 {
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(context));
     if (!PyDec_Check(state, v)) {
         PyErr_SetString(PyExc_TypeError,
             "argument must be a Decimal");
@@ -5409,9 +5440,9 @@ PyDecContext_Apply(PyObject *context, PyObject *v)
 }
 
 static PyObject *
-ctx_canonical(PyObject *context UNUSED, PyObject *v)
+ctx_canonical(PyObject *context, PyObject *v)
 {
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(context));
     if (!PyDec_Check(state, v)) {
         PyErr_SetString(PyExc_TypeError,
             "argument must be a Decimal");
@@ -5428,7 +5459,7 @@ ctx_mpd_qcopy_abs(PyObject *context, PyObject *v)
     uint32_t status = 0;
 
     CONVERT_OP_RAISE(&a, v, context);
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(context));
     result = dec_alloc(state);
     if (result == NULL) {
         Py_DECREF(a);
@@ -5461,7 +5492,7 @@ ctx_mpd_qcopy_negate(PyObject *context, PyObject *v)
     uint32_t status = 0;
 
     CONVERT_OP_RAISE(&a, v, context);
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(context));
     result = dec_alloc(state);
     if (result == NULL) {
         Py_DECREF(a);
@@ -5558,7 +5589,7 @@ ctx_mpd_qcopy_sign(PyObject *context, PyObject *args)
     }
 
     CONVERT_BINOP_RAISE(&a, &b, v, w, context);
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state_by_def(Py_TYPE(context));
     result = dec_alloc(state);
     if (result == NULL) {
         Py_DECREF(a);
@@ -5747,17 +5778,6 @@ static PyMethodDef _decimal_methods [] =
   { NULL, NULL, 1, NULL }
 };
 
-static struct PyModuleDef _decimal_module = {
-    PyModuleDef_HEAD_INIT,
-    "decimal",
-    doc__decimal,
-    -1,
-    _decimal_methods,
-    NULL,
-    NULL,
-    NULL,
-    NULL
-};
 
 struct ssize_constmap { const char *name; mpd_ssize_t val; };
 static struct ssize_constmap ssize_constants [] = {
@@ -5833,10 +5853,9 @@ cfunc_noargs(PyTypeObject *t, const char *name)
 }
 
 
-PyMODINIT_FUNC
-PyInit__decimal(void)
+static int
+_decimal_exec(PyObject *m)
 {
-    PyObject *m = NULL;
     PyObject *numbers = NULL;
     PyObject *Number = NULL;
     PyObject *collections = NULL;
@@ -5857,7 +5876,7 @@ PyInit__decimal(void)
     mpd_free = PyMem_Free;
     mpd_setminalloc(_Py_DEC_MINALLOC);
 
-    decimal_state *state = GLOBAL_STATE();
+    decimal_state *state = get_module_state(m);
 
     /* Init external C-API functions */
     state->_py_long_multiply = PyLong_Type.tp_as_number->nb_multiply;
@@ -5929,10 +5948,6 @@ PyInit__decimal(void)
     Py_CLEAR(collections_abc);
     Py_CLEAR(MutableMapping);
 
-
-    /* Create the module */
-    ASSIGN_PTR(m, PyModule_Create(&_decimal_module));
-
     /* Add types to the module */
     CHECK_INT(PyModule_AddType(m, state->PyDec_Type));
     CHECK_INT(PyModule_AddType(m, state->PyDecContext_Type));
@@ -6073,31 +6088,103 @@ PyInit__decimal(void)
     CHECK_INT(PyModule_AddStringConstant(m, "__version__", "1.70"));
     CHECK_INT(PyModule_AddStringConstant(m, "__libmpdec_version__", mpd_version()));
 
-
-    return m;
-
+    return 0;
 
 error:
     Py_CLEAR(obj); /* GCOV_NOT_REACHED */
     Py_CLEAR(numbers); /* GCOV_NOT_REACHED */
     Py_CLEAR(Number); /* GCOV_NOT_REACHED */
-    Py_CLEAR(state->Rational); /* GCOV_NOT_REACHED */
     Py_CLEAR(collections); /* GCOV_NOT_REACHED */
     Py_CLEAR(collections_abc); /* GCOV_NOT_REACHED */
     Py_CLEAR(MutableMapping); /* GCOV_NOT_REACHED */
-    Py_CLEAR(state->SignalTuple); /* GCOV_NOT_REACHED */
-    PyMem_Free(state->signal_map); /* GCOV_NOT_REACHED */
-    PyMem_Free(state->cond_map); /* GCOV_NOT_REACHED */
-    Py_CLEAR(state->DecimalTuple); /* GCOV_NOT_REACHED */
-    Py_CLEAR(state->default_context_template); /* GCOV_NOT_REACHED */
+
+    return -1;
+}
+
+static int
+decimal_traverse(PyObject *module, visitproc visit, void *arg)
+{
+    decimal_state *state = get_module_state(module);
+    Py_VISIT(state->PyDecContextManager_Type);
+    Py_VISIT(state->PyDecContext_Type);
+    Py_VISIT(state->PyDecSignalDictMixin_Type);
+    Py_VISIT(state->PyDec_Type);
+    Py_VISIT(state->PyDecSignalDict_Type);
+    Py_VISIT(state->DecimalTuple);
+    Py_VISIT(state->DecimalException);
+
+#ifndef WITH_DECIMAL_CONTEXTVAR
+    Py_VISIT(state->tls_context_key);
+    Py_VISIT(state->cached_context);
+#else
+    Py_VISIT(state->current_context_var);
+#endif
+
+    Py_VISIT(state->default_context_template);
+    Py_VISIT(state->basic_context_template);
+    Py_VISIT(state->extended_context_template);
+    Py_VISIT(state->Rational);
+    Py_VISIT(state->SignalTuple);
+
+    return 0;
+}
+
+static int
+decimal_clear(PyObject *module)
+{
+    decimal_state *state = get_module_state(module);
+    Py_CLEAR(state->PyDecContextManager_Type);
+    Py_CLEAR(state->PyDecContext_Type);
+    Py_CLEAR(state->PyDecSignalDictMixin_Type);
+    Py_CLEAR(state->PyDec_Type);
+    Py_CLEAR(state->PyDecSignalDict_Type);
+    Py_CLEAR(state->DecimalTuple);
+    Py_CLEAR(state->DecimalException);
+
 #ifndef WITH_DECIMAL_CONTEXTVAR
-    Py_CLEAR(state->tls_context_key); /* GCOV_NOT_REACHED */
+    Py_CLEAR(state->tls_context_key);
+    Py_CLEAR(state->cached_context);
 #else
-    Py_CLEAR(state->current_context_var); /* GCOV_NOT_REACHED */
+    Py_CLEAR(state->current_context_var);
 #endif
-    Py_CLEAR(state->basic_context_template); /* GCOV_NOT_REACHED */
-    Py_CLEAR(state->extended_context_template); /* GCOV_NOT_REACHED */
-    Py_CLEAR(m); /* GCOV_NOT_REACHED */
 
-    return NULL; /* GCOV_NOT_REACHED */
+    Py_CLEAR(state->default_context_template);
+    Py_CLEAR(state->basic_context_template);
+    Py_CLEAR(state->extended_context_template);
+    Py_CLEAR(state->Rational);
+    Py_CLEAR(state->SignalTuple);
+
+    PyMem_Free(state->signal_map);
+    PyMem_Free(state->cond_map);
+    return 0;
+}
+
+static void
+decimal_free(void *module)
+{
+    (void)decimal_clear((PyObject *)module);
+}
+
+static struct PyModuleDef_Slot _decimal_slots[] = {
+    {Py_mod_exec, _decimal_exec},
+    {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
+    {0, NULL},
+};
+
+static struct PyModuleDef _decimal_module = {
+    PyModuleDef_HEAD_INIT,
+    .m_name = "decimal",
+    .m_doc = doc__decimal,
+    .m_size = sizeof(decimal_state),
+    .m_methods = _decimal_methods,
+    .m_slots = _decimal_slots,
+    .m_traverse = decimal_traverse,
+    .m_clear = decimal_clear,
+    .m_free = decimal_free,
+};
+
+PyMODINIT_FUNC
+PyInit__decimal(void)
+{
+    return PyModuleDef_Init(&_decimal_module);
 }
diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv
index 80e9d35afd9be..dedcb3141457c 100644
--- a/Tools/c-analyzer/cpython/globals-to-fix.tsv
+++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv
@@ -421,7 +421,6 @@ Modules/_datetimemodule.c	-	us_per_hour	-
 Modules/_datetimemodule.c	-	us_per_day	-
 Modules/_datetimemodule.c	-	us_per_week	-
 Modules/_datetimemodule.c	-	seconds_per_day	-
-Modules/_decimal/_decimal.c	-	global_state	-
 
 ## state
 Modules/_ctypes/_ctypes.c	-	_ctypes_ptrtype_cache	-



More information about the Python-checkins mailing list