Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-106078: Move static objects related to CONTEXTVAR to the decimal module global state #106395

Merged
merged 12 commits into from
Jul 8, 2023
68 changes: 36 additions & 32 deletions Modules/_decimal/_decimal.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@

#include "docstrings.h"

typedef struct {
struct PyDecContextObject;
CharlieZhao95 marked this conversation as resolved.
Show resolved Hide resolved

typedef struct _decimal_state {
CharlieZhao95 marked this conversation as resolved.
Show resolved Hide resolved
PyTypeObject *PyDecContextManager_Type;
PyTypeObject *PyDecContext_Type;
PyTypeObject *PyDecSignalDictMixin_Type;
Expand All @@ -50,6 +52,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 */
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;
Expand Down Expand Up @@ -92,19 +103,19 @@ static decimal_state global_state;
/* _Py_DEC_MINALLOC >= MPD_MINALLOC */
#define _Py_DEC_MINALLOC 4

typedef struct {
typedef struct PyDecObject {
CharlieZhao95 marked this conversation as resolved.
Show resolved Hide resolved
PyObject_HEAD
Py_hash_t hash;
mpd_t dec;
mpd_uint_t data[_Py_DEC_MINALLOC];
} PyDecObject;

typedef struct {
typedef struct PyDecSignalDictObject {
CharlieZhao95 marked this conversation as resolved.
Show resolved Hide resolved
PyObject_HEAD
uint32_t *flags;
} PyDecSignalDictObject;

typedef struct {
typedef struct PyDecContextObject {
CharlieZhao95 marked this conversation as resolved.
Show resolved Hide resolved
PyObject_HEAD
mpd_context_t ctx;
PyObject *traps;
Expand All @@ -113,13 +124,12 @@ typedef struct {
PyThreadState *tstate;
} PyDecContextObject;

typedef struct {
typedef struct PyDecContextManagerObject {
CharlieZhao95 marked this conversation as resolved.
Show resolved Hide resolved
PyObject_HEAD
PyObject *local;
PyObject *global;
} PyDecContextManagerObject;


#undef MPD
#undef CTX
#define PyDec_CheckExact(st, v) Py_IS_TYPE(v, (st)->PyDec_Type)
Expand All @@ -145,16 +155,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

/* Error codes for functions that return signals or conditions */
#define DEC_INVALID_SIGNALS (MPD_Max_status+1U)
#define DEC_ERR_OCCURRED (DEC_INVALID_SIGNALS<<1)
Expand Down Expand Up @@ -1565,7 +1565,8 @@ current_context_from_dict(void)
return NULL;
}

PyObject *tl_context = PyDict_GetItemWithError(dict, 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);
Expand All @@ -1576,13 +1577,13 @@ 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;
}
CTX(tl_context)->status = 0;

if (PyDict_SetItem(dict, tls_context_key, tl_context) < 0) {
if (PyDict_SetItem(dict, modstate->tls_context_key, tl_context) < 0) {
Py_DECREF(tl_context);
return NULL;
}
Expand All @@ -1591,8 +1592,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;
modstate->cached_context = (PyDecContextObject *)tl_context;
modstate->cached_context->tstate = tstate;

/* Borrowed reference with refcount==1 */
return tl_context;
Expand All @@ -1603,8 +1604,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();
CharlieZhao95 marked this conversation as resolved.
Show resolved Hide resolved
if (state->cached_context && state->cached_context->tstate == tstate) {
return (PyObject *)(state->cached_context);
}

return current_context_from_dict();
Expand Down Expand Up @@ -1662,8 +1664,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;
}
Expand All @@ -1682,7 +1684,7 @@ init_current_context(void)
}
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;
Expand All @@ -1696,7 +1698,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;
}

Expand Down Expand Up @@ -1744,7 +1747,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;
Expand Down Expand Up @@ -5987,10 +5990,11 @@ PyInit__decimal(void)
Py_NewRef(state->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)));
Expand Down Expand Up @@ -6049,9 +6053,9 @@ PyInit__decimal(void)
Py_CLEAR(state->DecimalTuple); /* GCOV_NOT_REACHED */
Py_CLEAR(state->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(state->basic_context_template); /* GCOV_NOT_REACHED */
Py_CLEAR(state->extended_context_template); /* GCOV_NOT_REACHED */
Expand Down
1 change: 0 additions & 1 deletion Tools/c-analyzer/cpython/globals-to-fix.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,6 @@ Modules/_datetimemodule.c - us_per_day -
Modules/_datetimemodule.c - us_per_week -
Modules/_datetimemodule.c - seconds_per_day -
Modules/_decimal/_decimal.c - global_state -
Modules/_decimal/_decimal.c - current_context_var -
Modules/_decimal/_decimal.c - round_map -
Modules/_decimal/_decimal.c - Rational -
Modules/_decimal/_decimal.c - SignalTuple -
Expand Down