LCOV - code coverage report
Current view: top level - Python - context.c (source / functions) Hit Total Coverage
Test: CPython 3.12 LCOV report [commit 5e6661bce9] Lines: 154 480 32.1 %
Date: 2023-03-20 08:15:36 Functions: 21 60 35.0 %
Branches: 46 240 19.2 %

           Branch data     Line data    Source code
       1                 :            : #include "Python.h"
       2                 :            : #include "pycore_call.h"          // _PyObject_VectorcallTstate()
       3                 :            : #include "pycore_context.h"
       4                 :            : #include "pycore_gc.h"            // _PyObject_GC_MAY_BE_TRACKED()
       5                 :            : #include "pycore_hamt.h"
       6                 :            : #include "pycore_initconfig.h"    // _PyStatus_OK()
       7                 :            : #include "pycore_object.h"
       8                 :            : #include "pycore_pyerrors.h"
       9                 :            : #include "pycore_pystate.h"       // _PyThreadState_GET()
      10                 :            : #include "structmember.h"         // PyMemberDef
      11                 :            : 
      12                 :            : 
      13                 :            : #include "clinic/context.c.h"
      14                 :            : /*[clinic input]
      15                 :            : module _contextvars
      16                 :            : [clinic start generated code]*/
      17                 :            : /*[clinic end generated code: output=da39a3ee5e6b4b0d input=a0955718c8b8cea6]*/
      18                 :            : 
      19                 :            : 
      20                 :            : #define ENSURE_Context(o, err_ret)                                  \
      21                 :            :     if (!PyContext_CheckExact(o)) {                                 \
      22                 :            :         PyErr_SetString(PyExc_TypeError,                            \
      23                 :            :                         "an instance of Context was expected");     \
      24                 :            :         return err_ret;                                             \
      25                 :            :     }
      26                 :            : 
      27                 :            : #define ENSURE_ContextVar(o, err_ret)                               \
      28                 :            :     if (!PyContextVar_CheckExact(o)) {                              \
      29                 :            :         PyErr_SetString(PyExc_TypeError,                            \
      30                 :            :                        "an instance of ContextVar was expected");   \
      31                 :            :         return err_ret;                                             \
      32                 :            :     }
      33                 :            : 
      34                 :            : #define ENSURE_ContextToken(o, err_ret)                             \
      35                 :            :     if (!PyContextToken_CheckExact(o)) {                            \
      36                 :            :         PyErr_SetString(PyExc_TypeError,                            \
      37                 :            :                         "an instance of Token was expected");       \
      38                 :            :         return err_ret;                                             \
      39                 :            :     }
      40                 :            : 
      41                 :            : 
      42                 :            : /////////////////////////// Context API
      43                 :            : 
      44                 :            : 
      45                 :            : static PyContext *
      46                 :            : context_new_empty(void);
      47                 :            : 
      48                 :            : static PyContext *
      49                 :            : context_new_from_vars(PyHamtObject *vars);
      50                 :            : 
      51                 :            : static inline PyContext *
      52                 :            : context_get(void);
      53                 :            : 
      54                 :            : static PyContextToken *
      55                 :            : token_new(PyContext *ctx, PyContextVar *var, PyObject *val);
      56                 :            : 
      57                 :            : static PyContextVar *
      58                 :            : contextvar_new(PyObject *name, PyObject *def);
      59                 :            : 
      60                 :            : static int
      61                 :            : contextvar_set(PyContextVar *var, PyObject *val);
      62                 :            : 
      63                 :            : static int
      64                 :            : contextvar_del(PyContextVar *var);
      65                 :            : 
      66                 :            : 
      67                 :            : #if PyContext_MAXFREELIST > 0
      68                 :            : static struct _Py_context_state *
      69                 :          2 : get_context_state(void)
      70                 :            : {
      71                 :          2 :     PyInterpreterState *interp = _PyInterpreterState_GET();
      72                 :          2 :     return &interp->context;
      73                 :            : }
      74                 :            : #endif
      75                 :            : 
      76                 :            : 
      77                 :            : PyObject *
      78                 :          0 : _PyContext_NewHamtForTests(void)
      79                 :            : {
      80                 :          0 :     return (PyObject *)_PyHamt_New();
      81                 :            : }
      82                 :            : 
      83                 :            : 
      84                 :            : PyObject *
      85                 :          0 : PyContext_New(void)
      86                 :            : {
      87                 :          0 :     return (PyObject *)context_new_empty();
      88                 :            : }
      89                 :            : 
      90                 :            : 
      91                 :            : PyObject *
      92                 :          0 : PyContext_Copy(PyObject * octx)
      93                 :            : {
      94         [ #  # ]:          0 :     ENSURE_Context(octx, NULL)
      95                 :          0 :     PyContext *ctx = (PyContext *)octx;
      96                 :          0 :     return (PyObject *)context_new_from_vars(ctx->ctx_vars);
      97                 :            : }
      98                 :            : 
      99                 :            : 
     100                 :            : PyObject *
     101                 :          0 : PyContext_CopyCurrent(void)
     102                 :            : {
     103                 :          0 :     PyContext *ctx = context_get();
     104         [ #  # ]:          0 :     if (ctx == NULL) {
     105                 :          0 :         return NULL;
     106                 :            :     }
     107                 :            : 
     108                 :          0 :     return (PyObject *)context_new_from_vars(ctx->ctx_vars);
     109                 :            : }
     110                 :            : 
     111                 :            : 
     112                 :            : static int
     113                 :          0 : _PyContext_Enter(PyThreadState *ts, PyObject *octx)
     114                 :            : {
     115         [ #  # ]:          0 :     ENSURE_Context(octx, -1)
     116                 :          0 :     PyContext *ctx = (PyContext *)octx;
     117                 :            : 
     118         [ #  # ]:          0 :     if (ctx->ctx_entered) {
     119                 :          0 :         _PyErr_Format(ts, PyExc_RuntimeError,
     120                 :            :                       "cannot enter context: %R is already entered", ctx);
     121                 :          0 :         return -1;
     122                 :            :     }
     123                 :            : 
     124                 :          0 :     ctx->ctx_prev = (PyContext *)ts->context;  /* borrow */
     125                 :          0 :     ctx->ctx_entered = 1;
     126                 :            : 
     127                 :          0 :     ts->context = Py_NewRef(ctx);
     128                 :          0 :     ts->context_ver++;
     129                 :            : 
     130                 :          0 :     return 0;
     131                 :            : }
     132                 :            : 
     133                 :            : 
     134                 :            : int
     135                 :          0 : PyContext_Enter(PyObject *octx)
     136                 :            : {
     137                 :          0 :     PyThreadState *ts = _PyThreadState_GET();
     138                 :            :     assert(ts != NULL);
     139                 :          0 :     return _PyContext_Enter(ts, octx);
     140                 :            : }
     141                 :            : 
     142                 :            : 
     143                 :            : static int
     144                 :          0 : _PyContext_Exit(PyThreadState *ts, PyObject *octx)
     145                 :            : {
     146         [ #  # ]:          0 :     ENSURE_Context(octx, -1)
     147                 :          0 :     PyContext *ctx = (PyContext *)octx;
     148                 :            : 
     149         [ #  # ]:          0 :     if (!ctx->ctx_entered) {
     150                 :          0 :         PyErr_Format(PyExc_RuntimeError,
     151                 :            :                      "cannot exit context: %R has not been entered", ctx);
     152                 :          0 :         return -1;
     153                 :            :     }
     154                 :            : 
     155         [ #  # ]:          0 :     if (ts->context != (PyObject *)ctx) {
     156                 :            :         /* Can only happen if someone misuses the C API */
     157                 :          0 :         PyErr_SetString(PyExc_RuntimeError,
     158                 :            :                         "cannot exit context: thread state references "
     159                 :            :                         "a different context object");
     160                 :          0 :         return -1;
     161                 :            :     }
     162                 :            : 
     163                 :          0 :     Py_SETREF(ts->context, (PyObject *)ctx->ctx_prev);
     164                 :          0 :     ts->context_ver++;
     165                 :            : 
     166                 :          0 :     ctx->ctx_prev = NULL;
     167                 :          0 :     ctx->ctx_entered = 0;
     168                 :            : 
     169                 :          0 :     return 0;
     170                 :            : }
     171                 :            : 
     172                 :            : int
     173                 :          0 : PyContext_Exit(PyObject *octx)
     174                 :            : {
     175                 :          0 :     PyThreadState *ts = _PyThreadState_GET();
     176                 :            :     assert(ts != NULL);
     177                 :          0 :     return _PyContext_Exit(ts, octx);
     178                 :            : }
     179                 :            : 
     180                 :            : 
     181                 :            : PyObject *
     182                 :          2 : PyContextVar_New(const char *name, PyObject *def)
     183                 :            : {
     184                 :          2 :     PyObject *pyname = PyUnicode_FromString(name);
     185         [ -  + ]:          2 :     if (pyname == NULL) {
     186                 :          0 :         return NULL;
     187                 :            :     }
     188                 :          2 :     PyContextVar *var = contextvar_new(pyname, def);
     189                 :          2 :     Py_DECREF(pyname);
     190                 :          2 :     return (PyObject *)var;
     191                 :            : }
     192                 :            : 
     193                 :            : 
     194                 :            : int
     195                 :        342 : PyContextVar_Get(PyObject *ovar, PyObject *def, PyObject **val)
     196                 :            : {
     197         [ -  + ]:        342 :     ENSURE_ContextVar(ovar, -1)
     198                 :        342 :     PyContextVar *var = (PyContextVar *)ovar;
     199                 :            : 
     200                 :        342 :     PyThreadState *ts = _PyThreadState_GET();
     201                 :            :     assert(ts != NULL);
     202         [ +  + ]:        342 :     if (ts->context == NULL) {
     203                 :          1 :         goto not_found;
     204                 :            :     }
     205                 :            : 
     206         [ +  - ]:        341 :     if (var->var_cached != NULL &&
     207         [ +  - ]:        341 :             var->var_cached_tsid == ts->id &&
     208         [ +  - ]:        341 :             var->var_cached_tsver == ts->context_ver)
     209                 :            :     {
     210                 :        341 :         *val = var->var_cached;
     211                 :        341 :         goto found;
     212                 :            :     }
     213                 :            : 
     214                 :            :     assert(PyContext_CheckExact(ts->context));
     215                 :          0 :     PyHamtObject *vars = ((PyContext *)ts->context)->ctx_vars;
     216                 :            : 
     217                 :          0 :     PyObject *found = NULL;
     218                 :          0 :     int res = _PyHamt_Find(vars, (PyObject*)var, &found);
     219         [ #  # ]:          0 :     if (res < 0) {
     220                 :          0 :         goto error;
     221                 :            :     }
     222         [ #  # ]:          0 :     if (res == 1) {
     223                 :            :         assert(found != NULL);
     224                 :          0 :         var->var_cached = found;  /* borrow */
     225                 :          0 :         var->var_cached_tsid = ts->id;
     226                 :          0 :         var->var_cached_tsver = ts->context_ver;
     227                 :            : 
     228                 :          0 :         *val = found;
     229                 :          0 :         goto found;
     230                 :            :     }
     231                 :            : 
     232                 :          0 : not_found:
     233         [ +  - ]:          1 :     if (def == NULL) {
     234         [ -  + ]:          1 :         if (var->var_default != NULL) {
     235                 :          0 :             *val = var->var_default;
     236                 :          0 :             goto found;
     237                 :            :         }
     238                 :            : 
     239                 :          1 :         *val = NULL;
     240                 :          1 :         goto found;
     241                 :            :     }
     242                 :            :     else {
     243                 :          0 :         *val = def;
     244                 :          0 :         goto found;
     245                 :            :    }
     246                 :            : 
     247                 :        342 : found:
     248                 :        342 :     Py_XINCREF(*val);
     249                 :        342 :     return 0;
     250                 :            : 
     251                 :          0 : error:
     252                 :          0 :     *val = NULL;
     253                 :          0 :     return -1;
     254                 :            : }
     255                 :            : 
     256                 :            : 
     257                 :            : PyObject *
     258                 :         61 : PyContextVar_Set(PyObject *ovar, PyObject *val)
     259                 :            : {
     260         [ -  + ]:         61 :     ENSURE_ContextVar(ovar, NULL)
     261                 :         61 :     PyContextVar *var = (PyContextVar *)ovar;
     262                 :            : 
     263         [ -  + ]:         61 :     if (!PyContextVar_CheckExact(var)) {
     264                 :          0 :         PyErr_SetString(
     265                 :            :             PyExc_TypeError, "an instance of ContextVar was expected");
     266                 :          0 :         return NULL;
     267                 :            :     }
     268                 :            : 
     269                 :         61 :     PyContext *ctx = context_get();
     270         [ -  + ]:         61 :     if (ctx == NULL) {
     271                 :          0 :         return NULL;
     272                 :            :     }
     273                 :            : 
     274                 :         61 :     PyObject *old_val = NULL;
     275                 :         61 :     int found = _PyHamt_Find(ctx->ctx_vars, (PyObject *)var, &old_val);
     276         [ -  + ]:         61 :     if (found < 0) {
     277                 :          0 :         return NULL;
     278                 :            :     }
     279                 :            : 
     280                 :         61 :     Py_XINCREF(old_val);
     281                 :         61 :     PyContextToken *tok = token_new(ctx, var, old_val);
     282                 :         61 :     Py_XDECREF(old_val);
     283                 :            : 
     284         [ -  + ]:         61 :     if (contextvar_set(var, val)) {
     285                 :          0 :         Py_DECREF(tok);
     286                 :          0 :         return NULL;
     287                 :            :     }
     288                 :            : 
     289                 :         61 :     return (PyObject *)tok;
     290                 :            : }
     291                 :            : 
     292                 :            : 
     293                 :            : int
     294                 :          0 : PyContextVar_Reset(PyObject *ovar, PyObject *otok)
     295                 :            : {
     296         [ #  # ]:          0 :     ENSURE_ContextVar(ovar, -1)
     297         [ #  # ]:          0 :     ENSURE_ContextToken(otok, -1)
     298                 :          0 :     PyContextVar *var = (PyContextVar *)ovar;
     299                 :          0 :     PyContextToken *tok = (PyContextToken *)otok;
     300                 :            : 
     301         [ #  # ]:          0 :     if (tok->tok_used) {
     302                 :          0 :         PyErr_Format(PyExc_RuntimeError,
     303                 :            :                      "%R has already been used once", tok);
     304                 :          0 :         return -1;
     305                 :            :     }
     306                 :            : 
     307         [ #  # ]:          0 :     if (var != tok->tok_var) {
     308                 :          0 :         PyErr_Format(PyExc_ValueError,
     309                 :            :                      "%R was created by a different ContextVar", tok);
     310                 :          0 :         return -1;
     311                 :            :     }
     312                 :            : 
     313                 :          0 :     PyContext *ctx = context_get();
     314         [ #  # ]:          0 :     if (ctx != tok->tok_ctx) {
     315                 :          0 :         PyErr_Format(PyExc_ValueError,
     316                 :            :                      "%R was created in a different Context", tok);
     317                 :          0 :         return -1;
     318                 :            :     }
     319                 :            : 
     320                 :          0 :     tok->tok_used = 1;
     321                 :            : 
     322         [ #  # ]:          0 :     if (tok->tok_oldval == NULL) {
     323                 :          0 :         return contextvar_del(var);
     324                 :            :     }
     325                 :            :     else {
     326                 :          0 :         return contextvar_set(var, tok->tok_oldval);
     327                 :            :     }
     328                 :            : }
     329                 :            : 
     330                 :            : 
     331                 :            : /////////////////////////// PyContext
     332                 :            : 
     333                 :            : /*[clinic input]
     334                 :            : class _contextvars.Context "PyContext *" "&PyContext_Type"
     335                 :            : [clinic start generated code]*/
     336                 :            : /*[clinic end generated code: output=da39a3ee5e6b4b0d input=bdf87f8e0cb580e8]*/
     337                 :            : 
     338                 :            : 
     339                 :            : static inline PyContext *
     340                 :          1 : _context_alloc(void)
     341                 :            : {
     342                 :            :     PyContext *ctx;
     343                 :            : #if PyContext_MAXFREELIST > 0
     344                 :          1 :     struct _Py_context_state *state = get_context_state();
     345                 :            : #ifdef Py_DEBUG
     346                 :            :     // _context_alloc() must not be called after _PyContext_Fini()
     347                 :            :     assert(state->numfree != -1);
     348                 :            : #endif
     349         [ -  + ]:          1 :     if (state->numfree) {
     350                 :          0 :         state->numfree--;
     351                 :          0 :         ctx = state->freelist;
     352                 :          0 :         state->freelist = (PyContext *)ctx->ctx_weakreflist;
     353                 :            :         OBJECT_STAT_INC(from_freelist);
     354                 :          0 :         ctx->ctx_weakreflist = NULL;
     355                 :          0 :         _Py_NewReference((PyObject *)ctx);
     356                 :            :     }
     357                 :            :     else
     358                 :            : #endif
     359                 :            :     {
     360                 :          1 :         ctx = PyObject_GC_New(PyContext, &PyContext_Type);
     361         [ -  + ]:          1 :         if (ctx == NULL) {
     362                 :          0 :             return NULL;
     363                 :            :         }
     364                 :            :     }
     365                 :            : 
     366                 :          1 :     ctx->ctx_vars = NULL;
     367                 :          1 :     ctx->ctx_prev = NULL;
     368                 :          1 :     ctx->ctx_entered = 0;
     369                 :          1 :     ctx->ctx_weakreflist = NULL;
     370                 :            : 
     371                 :          1 :     return ctx;
     372                 :            : }
     373                 :            : 
     374                 :            : 
     375                 :            : static PyContext *
     376                 :          1 : context_new_empty(void)
     377                 :            : {
     378                 :          1 :     PyContext *ctx = _context_alloc();
     379         [ -  + ]:          1 :     if (ctx == NULL) {
     380                 :          0 :         return NULL;
     381                 :            :     }
     382                 :            : 
     383                 :          1 :     ctx->ctx_vars = _PyHamt_New();
     384         [ -  + ]:          1 :     if (ctx->ctx_vars == NULL) {
     385                 :          0 :         Py_DECREF(ctx);
     386                 :          0 :         return NULL;
     387                 :            :     }
     388                 :            : 
     389                 :          1 :     _PyObject_GC_TRACK(ctx);
     390                 :          1 :     return ctx;
     391                 :            : }
     392                 :            : 
     393                 :            : 
     394                 :            : static PyContext *
     395                 :          0 : context_new_from_vars(PyHamtObject *vars)
     396                 :            : {
     397                 :          0 :     PyContext *ctx = _context_alloc();
     398         [ #  # ]:          0 :     if (ctx == NULL) {
     399                 :          0 :         return NULL;
     400                 :            :     }
     401                 :            : 
     402                 :          0 :     ctx->ctx_vars = (PyHamtObject*)Py_NewRef(vars);
     403                 :            : 
     404                 :          0 :     _PyObject_GC_TRACK(ctx);
     405                 :          0 :     return ctx;
     406                 :            : }
     407                 :            : 
     408                 :            : 
     409                 :            : static inline PyContext *
     410                 :        122 : context_get(void)
     411                 :            : {
     412                 :        122 :     PyThreadState *ts = _PyThreadState_GET();
     413                 :            :     assert(ts != NULL);
     414                 :        122 :     PyContext *current_ctx = (PyContext *)ts->context;
     415         [ +  + ]:        122 :     if (current_ctx == NULL) {
     416                 :          1 :         current_ctx = context_new_empty();
     417         [ -  + ]:          1 :         if (current_ctx == NULL) {
     418                 :          0 :             return NULL;
     419                 :            :         }
     420                 :          1 :         ts->context = (PyObject *)current_ctx;
     421                 :            :     }
     422                 :        122 :     return current_ctx;
     423                 :            : }
     424                 :            : 
     425                 :            : static int
     426                 :          0 : context_check_key_type(PyObject *key)
     427                 :            : {
     428         [ #  # ]:          0 :     if (!PyContextVar_CheckExact(key)) {
     429                 :            :         // abort();
     430                 :          0 :         PyErr_Format(PyExc_TypeError,
     431                 :            :                      "a ContextVar key was expected, got %R", key);
     432                 :          0 :         return -1;
     433                 :            :     }
     434                 :          0 :     return 0;
     435                 :            : }
     436                 :            : 
     437                 :            : static PyObject *
     438                 :          0 : context_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     439                 :            : {
     440   [ #  #  #  #  :          0 :     if (PyTuple_Size(args) || (kwds != NULL && PyDict_Size(kwds))) {
                   #  # ]
     441                 :          0 :         PyErr_SetString(
     442                 :            :             PyExc_TypeError, "Context() does not accept any arguments");
     443                 :          0 :         return NULL;
     444                 :            :     }
     445                 :          0 :     return PyContext_New();
     446                 :            : }
     447                 :            : 
     448                 :            : static int
     449                 :          1 : context_tp_clear(PyContext *self)
     450                 :            : {
     451         [ -  + ]:          1 :     Py_CLEAR(self->ctx_prev);
     452         [ +  - ]:          1 :     Py_CLEAR(self->ctx_vars);
     453                 :          1 :     return 0;
     454                 :            : }
     455                 :            : 
     456                 :            : static int
     457                 :         26 : context_tp_traverse(PyContext *self, visitproc visit, void *arg)
     458                 :            : {
     459   [ -  +  -  - ]:         26 :     Py_VISIT(self->ctx_prev);
     460   [ +  -  -  + ]:         26 :     Py_VISIT(self->ctx_vars);
     461                 :         26 :     return 0;
     462                 :            : }
     463                 :            : 
     464                 :            : static void
     465                 :          1 : context_tp_dealloc(PyContext *self)
     466                 :            : {
     467                 :          1 :     _PyObject_GC_UNTRACK(self);
     468                 :            : 
     469         [ -  + ]:          1 :     if (self->ctx_weakreflist != NULL) {
     470                 :          0 :         PyObject_ClearWeakRefs((PyObject*)self);
     471                 :            :     }
     472                 :          1 :     (void)context_tp_clear(self);
     473                 :            : 
     474                 :            : #if PyContext_MAXFREELIST > 0
     475                 :          1 :     struct _Py_context_state *state = get_context_state();
     476                 :            : #ifdef Py_DEBUG
     477                 :            :     // _context_alloc() must not be called after _PyContext_Fini()
     478                 :            :     assert(state->numfree != -1);
     479                 :            : #endif
     480         [ +  - ]:          1 :     if (state->numfree < PyContext_MAXFREELIST) {
     481                 :          1 :         state->numfree++;
     482                 :          1 :         self->ctx_weakreflist = (PyObject *)state->freelist;
     483                 :          1 :         state->freelist = self;
     484                 :            :         OBJECT_STAT_INC(to_freelist);
     485                 :            :     }
     486                 :            :     else
     487                 :            : #endif
     488                 :            :     {
     489                 :          0 :         Py_TYPE(self)->tp_free(self);
     490                 :            :     }
     491                 :          1 : }
     492                 :            : 
     493                 :            : static PyObject *
     494                 :          0 : context_tp_iter(PyContext *self)
     495                 :            : {
     496                 :          0 :     return _PyHamt_NewIterKeys(self->ctx_vars);
     497                 :            : }
     498                 :            : 
     499                 :            : static PyObject *
     500                 :          0 : context_tp_richcompare(PyObject *v, PyObject *w, int op)
     501                 :            : {
     502   [ #  #  #  #  :          0 :     if (!PyContext_CheckExact(v) || !PyContext_CheckExact(w) ||
                   #  # ]
     503         [ #  # ]:          0 :             (op != Py_EQ && op != Py_NE))
     504                 :            :     {
     505                 :          0 :         Py_RETURN_NOTIMPLEMENTED;
     506                 :            :     }
     507                 :            : 
     508                 :          0 :     int res = _PyHamt_Eq(
     509                 :            :         ((PyContext *)v)->ctx_vars, ((PyContext *)w)->ctx_vars);
     510         [ #  # ]:          0 :     if (res < 0) {
     511                 :          0 :         return NULL;
     512                 :            :     }
     513                 :            : 
     514         [ #  # ]:          0 :     if (op == Py_NE) {
     515                 :          0 :         res = !res;
     516                 :            :     }
     517                 :            : 
     518         [ #  # ]:          0 :     if (res) {
     519                 :          0 :         Py_RETURN_TRUE;
     520                 :            :     }
     521                 :            :     else {
     522                 :          0 :         Py_RETURN_FALSE;
     523                 :            :     }
     524                 :            : }
     525                 :            : 
     526                 :            : static Py_ssize_t
     527                 :          0 : context_tp_len(PyContext *self)
     528                 :            : {
     529                 :          0 :     return _PyHamt_Len(self->ctx_vars);
     530                 :            : }
     531                 :            : 
     532                 :            : static PyObject *
     533                 :          0 : context_tp_subscript(PyContext *self, PyObject *key)
     534                 :            : {
     535         [ #  # ]:          0 :     if (context_check_key_type(key)) {
     536                 :          0 :         return NULL;
     537                 :            :     }
     538                 :          0 :     PyObject *val = NULL;
     539                 :          0 :     int found = _PyHamt_Find(self->ctx_vars, key, &val);
     540         [ #  # ]:          0 :     if (found < 0) {
     541                 :          0 :         return NULL;
     542                 :            :     }
     543         [ #  # ]:          0 :     if (found == 0) {
     544                 :          0 :         PyErr_SetObject(PyExc_KeyError, key);
     545                 :          0 :         return NULL;
     546                 :            :     }
     547                 :          0 :     return Py_NewRef(val);
     548                 :            : }
     549                 :            : 
     550                 :            : static int
     551                 :          0 : context_tp_contains(PyContext *self, PyObject *key)
     552                 :            : {
     553         [ #  # ]:          0 :     if (context_check_key_type(key)) {
     554                 :          0 :         return -1;
     555                 :            :     }
     556                 :          0 :     PyObject *val = NULL;
     557                 :          0 :     return _PyHamt_Find(self->ctx_vars, key, &val);
     558                 :            : }
     559                 :            : 
     560                 :            : 
     561                 :            : /*[clinic input]
     562                 :            : _contextvars.Context.get
     563                 :            :     key: object
     564                 :            :     default: object = None
     565                 :            :     /
     566                 :            : 
     567                 :            : Return the value for `key` if `key` has the value in the context object.
     568                 :            : 
     569                 :            : If `key` does not exist, return `default`. If `default` is not given,
     570                 :            : return None.
     571                 :            : [clinic start generated code]*/
     572                 :            : 
     573                 :            : static PyObject *
     574                 :          0 : _contextvars_Context_get_impl(PyContext *self, PyObject *key,
     575                 :            :                               PyObject *default_value)
     576                 :            : /*[clinic end generated code: output=0c54aa7664268189 input=c8eeb81505023995]*/
     577                 :            : {
     578         [ #  # ]:          0 :     if (context_check_key_type(key)) {
     579                 :          0 :         return NULL;
     580                 :            :     }
     581                 :            : 
     582                 :          0 :     PyObject *val = NULL;
     583                 :          0 :     int found = _PyHamt_Find(self->ctx_vars, key, &val);
     584         [ #  # ]:          0 :     if (found < 0) {
     585                 :          0 :         return NULL;
     586                 :            :     }
     587         [ #  # ]:          0 :     if (found == 0) {
     588                 :          0 :         return Py_NewRef(default_value);
     589                 :            :     }
     590                 :          0 :     return Py_NewRef(val);
     591                 :            : }
     592                 :            : 
     593                 :            : 
     594                 :            : /*[clinic input]
     595                 :            : _contextvars.Context.items
     596                 :            : 
     597                 :            : Return all variables and their values in the context object.
     598                 :            : 
     599                 :            : The result is returned as a list of 2-tuples (variable, value).
     600                 :            : [clinic start generated code]*/
     601                 :            : 
     602                 :            : static PyObject *
     603                 :          0 : _contextvars_Context_items_impl(PyContext *self)
     604                 :            : /*[clinic end generated code: output=fa1655c8a08502af input=00db64ae379f9f42]*/
     605                 :            : {
     606                 :          0 :     return _PyHamt_NewIterItems(self->ctx_vars);
     607                 :            : }
     608                 :            : 
     609                 :            : 
     610                 :            : /*[clinic input]
     611                 :            : _contextvars.Context.keys
     612                 :            : 
     613                 :            : Return a list of all variables in the context object.
     614                 :            : [clinic start generated code]*/
     615                 :            : 
     616                 :            : static PyObject *
     617                 :          0 : _contextvars_Context_keys_impl(PyContext *self)
     618                 :            : /*[clinic end generated code: output=177227c6b63ec0e2 input=114b53aebca3449c]*/
     619                 :            : {
     620                 :          0 :     return _PyHamt_NewIterKeys(self->ctx_vars);
     621                 :            : }
     622                 :            : 
     623                 :            : 
     624                 :            : /*[clinic input]
     625                 :            : _contextvars.Context.values
     626                 :            : 
     627                 :            : Return a list of all variables' values in the context object.
     628                 :            : [clinic start generated code]*/
     629                 :            : 
     630                 :            : static PyObject *
     631                 :          0 : _contextvars_Context_values_impl(PyContext *self)
     632                 :            : /*[clinic end generated code: output=d286dabfc8db6dde input=ce8075d04a6ea526]*/
     633                 :            : {
     634                 :          0 :     return _PyHamt_NewIterValues(self->ctx_vars);
     635                 :            : }
     636                 :            : 
     637                 :            : 
     638                 :            : /*[clinic input]
     639                 :            : _contextvars.Context.copy
     640                 :            : 
     641                 :            : Return a shallow copy of the context object.
     642                 :            : [clinic start generated code]*/
     643                 :            : 
     644                 :            : static PyObject *
     645                 :          0 : _contextvars_Context_copy_impl(PyContext *self)
     646                 :            : /*[clinic end generated code: output=30ba8896c4707a15 input=ebafdbdd9c72d592]*/
     647                 :            : {
     648                 :          0 :     return (PyObject *)context_new_from_vars(self->ctx_vars);
     649                 :            : }
     650                 :            : 
     651                 :            : 
     652                 :            : static PyObject *
     653                 :          0 : context_run(PyContext *self, PyObject *const *args,
     654                 :            :             Py_ssize_t nargs, PyObject *kwnames)
     655                 :            : {
     656                 :          0 :     PyThreadState *ts = _PyThreadState_GET();
     657                 :            : 
     658         [ #  # ]:          0 :     if (nargs < 1) {
     659                 :          0 :         _PyErr_SetString(ts, PyExc_TypeError,
     660                 :            :                          "run() missing 1 required positional argument");
     661                 :          0 :         return NULL;
     662                 :            :     }
     663                 :            : 
     664         [ #  # ]:          0 :     if (_PyContext_Enter(ts, (PyObject *)self)) {
     665                 :          0 :         return NULL;
     666                 :            :     }
     667                 :            : 
     668                 :          0 :     PyObject *call_result = _PyObject_VectorcallTstate(
     669                 :          0 :         ts, args[0], args + 1, nargs - 1, kwnames);
     670                 :            : 
     671         [ #  # ]:          0 :     if (_PyContext_Exit(ts, (PyObject *)self)) {
     672                 :          0 :         return NULL;
     673                 :            :     }
     674                 :            : 
     675                 :          0 :     return call_result;
     676                 :            : }
     677                 :            : 
     678                 :            : 
     679                 :            : static PyMethodDef PyContext_methods[] = {
     680                 :            :     _CONTEXTVARS_CONTEXT_GET_METHODDEF
     681                 :            :     _CONTEXTVARS_CONTEXT_ITEMS_METHODDEF
     682                 :            :     _CONTEXTVARS_CONTEXT_KEYS_METHODDEF
     683                 :            :     _CONTEXTVARS_CONTEXT_VALUES_METHODDEF
     684                 :            :     _CONTEXTVARS_CONTEXT_COPY_METHODDEF
     685                 :            :     {"run", _PyCFunction_CAST(context_run), METH_FASTCALL | METH_KEYWORDS, NULL},
     686                 :            :     {NULL, NULL}
     687                 :            : };
     688                 :            : 
     689                 :            : static PySequenceMethods PyContext_as_sequence = {
     690                 :            :     0,                                   /* sq_length */
     691                 :            :     0,                                   /* sq_concat */
     692                 :            :     0,                                   /* sq_repeat */
     693                 :            :     0,                                   /* sq_item */
     694                 :            :     0,                                   /* sq_slice */
     695                 :            :     0,                                   /* sq_ass_item */
     696                 :            :     0,                                   /* sq_ass_slice */
     697                 :            :     (objobjproc)context_tp_contains,     /* sq_contains */
     698                 :            :     0,                                   /* sq_inplace_concat */
     699                 :            :     0,                                   /* sq_inplace_repeat */
     700                 :            : };
     701                 :            : 
     702                 :            : static PyMappingMethods PyContext_as_mapping = {
     703                 :            :     (lenfunc)context_tp_len,             /* mp_length */
     704                 :            :     (binaryfunc)context_tp_subscript,    /* mp_subscript */
     705                 :            : };
     706                 :            : 
     707                 :            : PyTypeObject PyContext_Type = {
     708                 :            :     PyVarObject_HEAD_INIT(&PyType_Type, 0)
     709                 :            :     "_contextvars.Context",
     710                 :            :     sizeof(PyContext),
     711                 :            :     .tp_methods = PyContext_methods,
     712                 :            :     .tp_as_mapping = &PyContext_as_mapping,
     713                 :            :     .tp_as_sequence = &PyContext_as_sequence,
     714                 :            :     .tp_iter = (getiterfunc)context_tp_iter,
     715                 :            :     .tp_dealloc = (destructor)context_tp_dealloc,
     716                 :            :     .tp_getattro = PyObject_GenericGetAttr,
     717                 :            :     .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
     718                 :            :     .tp_richcompare = context_tp_richcompare,
     719                 :            :     .tp_traverse = (traverseproc)context_tp_traverse,
     720                 :            :     .tp_clear = (inquiry)context_tp_clear,
     721                 :            :     .tp_new = context_tp_new,
     722                 :            :     .tp_weaklistoffset = offsetof(PyContext, ctx_weakreflist),
     723                 :            :     .tp_hash = PyObject_HashNotImplemented,
     724                 :            : };
     725                 :            : 
     726                 :            : 
     727                 :            : /////////////////////////// ContextVar
     728                 :            : 
     729                 :            : 
     730                 :            : static int
     731                 :         61 : contextvar_set(PyContextVar *var, PyObject *val)
     732                 :            : {
     733                 :         61 :     var->var_cached = NULL;
     734                 :         61 :     PyThreadState *ts = _PyThreadState_GET();
     735                 :            : 
     736                 :         61 :     PyContext *ctx = context_get();
     737         [ -  + ]:         61 :     if (ctx == NULL) {
     738                 :          0 :         return -1;
     739                 :            :     }
     740                 :            : 
     741                 :         61 :     PyHamtObject *new_vars = _PyHamt_Assoc(
     742                 :            :         ctx->ctx_vars, (PyObject *)var, val);
     743         [ -  + ]:         61 :     if (new_vars == NULL) {
     744                 :          0 :         return -1;
     745                 :            :     }
     746                 :            : 
     747                 :         61 :     Py_SETREF(ctx->ctx_vars, new_vars);
     748                 :            : 
     749                 :         61 :     var->var_cached = val;  /* borrow */
     750                 :         61 :     var->var_cached_tsid = ts->id;
     751                 :         61 :     var->var_cached_tsver = ts->context_ver;
     752                 :         61 :     return 0;
     753                 :            : }
     754                 :            : 
     755                 :            : static int
     756                 :          0 : contextvar_del(PyContextVar *var)
     757                 :            : {
     758                 :          0 :     var->var_cached = NULL;
     759                 :            : 
     760                 :          0 :     PyContext *ctx = context_get();
     761         [ #  # ]:          0 :     if (ctx == NULL) {
     762                 :          0 :         return -1;
     763                 :            :     }
     764                 :            : 
     765                 :          0 :     PyHamtObject *vars = ctx->ctx_vars;
     766                 :          0 :     PyHamtObject *new_vars = _PyHamt_Without(vars, (PyObject *)var);
     767         [ #  # ]:          0 :     if (new_vars == NULL) {
     768                 :          0 :         return -1;
     769                 :            :     }
     770                 :            : 
     771         [ #  # ]:          0 :     if (vars == new_vars) {
     772                 :          0 :         Py_DECREF(new_vars);
     773                 :          0 :         PyErr_SetObject(PyExc_LookupError, (PyObject *)var);
     774                 :          0 :         return -1;
     775                 :            :     }
     776                 :            : 
     777                 :          0 :     Py_SETREF(ctx->ctx_vars, new_vars);
     778                 :          0 :     return 0;
     779                 :            : }
     780                 :            : 
     781                 :            : static Py_hash_t
     782                 :          2 : contextvar_generate_hash(void *addr, PyObject *name)
     783                 :            : {
     784                 :            :     /* Take hash of `name` and XOR it with the object's addr.
     785                 :            : 
     786                 :            :        The structure of the tree is encoded in objects' hashes, which
     787                 :            :        means that sufficiently similar hashes would result in tall trees
     788                 :            :        with many Collision nodes.  Which would, in turn, result in slower
     789                 :            :        get and set operations.
     790                 :            : 
     791                 :            :        The XORing helps to ensure that:
     792                 :            : 
     793                 :            :        (1) sequentially allocated ContextVar objects have
     794                 :            :            different hashes;
     795                 :            : 
     796                 :            :        (2) context variables with equal names have
     797                 :            :            different hashes.
     798                 :            :     */
     799                 :            : 
     800                 :          2 :     Py_hash_t name_hash = PyObject_Hash(name);
     801         [ -  + ]:          2 :     if (name_hash == -1) {
     802                 :          0 :         return -1;
     803                 :            :     }
     804                 :            : 
     805                 :          2 :     Py_hash_t res = _Py_HashPointer(addr) ^ name_hash;
     806         [ +  - ]:          2 :     return res == -1 ? -2 : res;
     807                 :            : }
     808                 :            : 
     809                 :            : static PyContextVar *
     810                 :          2 : contextvar_new(PyObject *name, PyObject *def)
     811                 :            : {
     812         [ -  + ]:          2 :     if (!PyUnicode_Check(name)) {
     813                 :          0 :         PyErr_SetString(PyExc_TypeError,
     814                 :            :                         "context variable name must be a str");
     815                 :          0 :         return NULL;
     816                 :            :     }
     817                 :            : 
     818                 :          2 :     PyContextVar *var = PyObject_GC_New(PyContextVar, &PyContextVar_Type);
     819         [ -  + ]:          2 :     if (var == NULL) {
     820                 :          0 :         return NULL;
     821                 :            :     }
     822                 :            : 
     823                 :          2 :     var->var_hash = contextvar_generate_hash(var, name);
     824         [ -  + ]:          2 :     if (var->var_hash == -1) {
     825                 :          0 :         Py_DECREF(var);
     826                 :          0 :         return NULL;
     827                 :            :     }
     828                 :            : 
     829                 :          2 :     var->var_name = Py_NewRef(name);
     830                 :            : 
     831                 :          2 :     var->var_default = Py_XNewRef(def);
     832                 :            : 
     833                 :          2 :     var->var_cached = NULL;
     834                 :          2 :     var->var_cached_tsid = 0;
     835                 :          2 :     var->var_cached_tsver = 0;
     836                 :            : 
     837   [ +  -  -  + ]:          2 :     if (_PyObject_GC_MAY_BE_TRACKED(name) ||
     838         [ #  # ]:          0 :             (def != NULL && _PyObject_GC_MAY_BE_TRACKED(def)))
     839                 :            :     {
     840                 :          0 :         PyObject_GC_Track(var);
     841                 :            :     }
     842                 :          2 :     return var;
     843                 :            : }
     844                 :            : 
     845                 :            : 
     846                 :            : /*[clinic input]
     847                 :            : class _contextvars.ContextVar "PyContextVar *" "&PyContextVar_Type"
     848                 :            : [clinic start generated code]*/
     849                 :            : /*[clinic end generated code: output=da39a3ee5e6b4b0d input=445da935fa8883c3]*/
     850                 :            : 
     851                 :            : 
     852                 :            : static PyObject *
     853                 :          0 : contextvar_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     854                 :            : {
     855                 :            :     static char *kwlist[] = {"", "default", NULL};
     856                 :            :     PyObject *name;
     857                 :          0 :     PyObject *def = NULL;
     858                 :            : 
     859         [ #  # ]:          0 :     if (!PyArg_ParseTupleAndKeywords(
     860                 :            :             args, kwds, "O|$O:ContextVar", kwlist, &name, &def))
     861                 :            :     {
     862                 :          0 :         return NULL;
     863                 :            :     }
     864                 :            : 
     865                 :          0 :     return (PyObject *)contextvar_new(name, def);
     866                 :            : }
     867                 :            : 
     868                 :            : static int
     869                 :          0 : contextvar_tp_clear(PyContextVar *self)
     870                 :            : {
     871         [ #  # ]:          0 :     Py_CLEAR(self->var_name);
     872         [ #  # ]:          0 :     Py_CLEAR(self->var_default);
     873                 :          0 :     self->var_cached = NULL;
     874                 :          0 :     self->var_cached_tsid = 0;
     875                 :          0 :     self->var_cached_tsver = 0;
     876                 :          0 :     return 0;
     877                 :            : }
     878                 :            : 
     879                 :            : static int
     880                 :          0 : contextvar_tp_traverse(PyContextVar *self, visitproc visit, void *arg)
     881                 :            : {
     882   [ #  #  #  # ]:          0 :     Py_VISIT(self->var_name);
     883   [ #  #  #  # ]:          0 :     Py_VISIT(self->var_default);
     884                 :          0 :     return 0;
     885                 :            : }
     886                 :            : 
     887                 :            : static void
     888                 :          0 : contextvar_tp_dealloc(PyContextVar *self)
     889                 :            : {
     890                 :          0 :     PyObject_GC_UnTrack(self);
     891                 :          0 :     (void)contextvar_tp_clear(self);
     892                 :          0 :     Py_TYPE(self)->tp_free(self);
     893                 :          0 : }
     894                 :            : 
     895                 :            : static Py_hash_t
     896                 :        121 : contextvar_tp_hash(PyContextVar *self)
     897                 :            : {
     898                 :        121 :     return self->var_hash;
     899                 :            : }
     900                 :            : 
     901                 :            : static PyObject *
     902                 :          0 : contextvar_tp_repr(PyContextVar *self)
     903                 :            : {
     904                 :            :     _PyUnicodeWriter writer;
     905                 :            : 
     906                 :          0 :     _PyUnicodeWriter_Init(&writer);
     907                 :            : 
     908         [ #  # ]:          0 :     if (_PyUnicodeWriter_WriteASCIIString(
     909                 :            :             &writer, "<ContextVar name=", 17) < 0)
     910                 :            :     {
     911                 :          0 :         goto error;
     912                 :            :     }
     913                 :            : 
     914                 :          0 :     PyObject *name = PyObject_Repr(self->var_name);
     915         [ #  # ]:          0 :     if (name == NULL) {
     916                 :          0 :         goto error;
     917                 :            :     }
     918         [ #  # ]:          0 :     if (_PyUnicodeWriter_WriteStr(&writer, name) < 0) {
     919                 :          0 :         Py_DECREF(name);
     920                 :          0 :         goto error;
     921                 :            :     }
     922                 :          0 :     Py_DECREF(name);
     923                 :            : 
     924         [ #  # ]:          0 :     if (self->var_default != NULL) {
     925         [ #  # ]:          0 :         if (_PyUnicodeWriter_WriteASCIIString(&writer, " default=", 9) < 0) {
     926                 :          0 :             goto error;
     927                 :            :         }
     928                 :            : 
     929                 :          0 :         PyObject *def = PyObject_Repr(self->var_default);
     930         [ #  # ]:          0 :         if (def == NULL) {
     931                 :          0 :             goto error;
     932                 :            :         }
     933         [ #  # ]:          0 :         if (_PyUnicodeWriter_WriteStr(&writer, def) < 0) {
     934                 :          0 :             Py_DECREF(def);
     935                 :          0 :             goto error;
     936                 :            :         }
     937                 :          0 :         Py_DECREF(def);
     938                 :            :     }
     939                 :            : 
     940                 :          0 :     PyObject *addr = PyUnicode_FromFormat(" at %p>", self);
     941         [ #  # ]:          0 :     if (addr == NULL) {
     942                 :          0 :         goto error;
     943                 :            :     }
     944         [ #  # ]:          0 :     if (_PyUnicodeWriter_WriteStr(&writer, addr) < 0) {
     945                 :          0 :         Py_DECREF(addr);
     946                 :          0 :         goto error;
     947                 :            :     }
     948                 :          0 :     Py_DECREF(addr);
     949                 :            : 
     950                 :          0 :     return _PyUnicodeWriter_Finish(&writer);
     951                 :            : 
     952                 :          0 : error:
     953                 :          0 :     _PyUnicodeWriter_Dealloc(&writer);
     954                 :          0 :     return NULL;
     955                 :            : }
     956                 :            : 
     957                 :            : 
     958                 :            : /*[clinic input]
     959                 :            : _contextvars.ContextVar.get
     960                 :            :     default: object = NULL
     961                 :            :     /
     962                 :            : 
     963                 :            : Return a value for the context variable for the current context.
     964                 :            : 
     965                 :            : If there is no value for the variable in the current context, the method will:
     966                 :            :  * return the value of the default argument of the method, if provided; or
     967                 :            :  * return the default value for the context variable, if it was created
     968                 :            :    with one; or
     969                 :            :  * raise a LookupError.
     970                 :            : [clinic start generated code]*/
     971                 :            : 
     972                 :            : static PyObject *
     973                 :          0 : _contextvars_ContextVar_get_impl(PyContextVar *self, PyObject *default_value)
     974                 :            : /*[clinic end generated code: output=0746bd0aa2ced7bf input=30aa2ab9e433e401]*/
     975                 :            : {
     976         [ #  # ]:          0 :     if (!PyContextVar_CheckExact(self)) {
     977                 :          0 :         PyErr_SetString(
     978                 :            :             PyExc_TypeError, "an instance of ContextVar was expected");
     979                 :          0 :         return NULL;
     980                 :            :     }
     981                 :            : 
     982                 :            :     PyObject *val;
     983         [ #  # ]:          0 :     if (PyContextVar_Get((PyObject *)self, default_value, &val) < 0) {
     984                 :          0 :         return NULL;
     985                 :            :     }
     986                 :            : 
     987         [ #  # ]:          0 :     if (val == NULL) {
     988                 :          0 :         PyErr_SetObject(PyExc_LookupError, (PyObject *)self);
     989                 :          0 :         return NULL;
     990                 :            :     }
     991                 :            : 
     992                 :          0 :     return val;
     993                 :            : }
     994                 :            : 
     995                 :            : /*[clinic input]
     996                 :            : _contextvars.ContextVar.set
     997                 :            :     value: object
     998                 :            :     /
     999                 :            : 
    1000                 :            : Call to set a new value for the context variable in the current context.
    1001                 :            : 
    1002                 :            : The required value argument is the new value for the context variable.
    1003                 :            : 
    1004                 :            : Returns a Token object that can be used to restore the variable to its previous
    1005                 :            : value via the `ContextVar.reset()` method.
    1006                 :            : [clinic start generated code]*/
    1007                 :            : 
    1008                 :            : static PyObject *
    1009                 :          0 : _contextvars_ContextVar_set(PyContextVar *self, PyObject *value)
    1010                 :            : /*[clinic end generated code: output=446ed5e820d6d60b input=c0a6887154227453]*/
    1011                 :            : {
    1012                 :          0 :     return PyContextVar_Set((PyObject *)self, value);
    1013                 :            : }
    1014                 :            : 
    1015                 :            : /*[clinic input]
    1016                 :            : _contextvars.ContextVar.reset
    1017                 :            :     token: object
    1018                 :            :     /
    1019                 :            : 
    1020                 :            : Reset the context variable.
    1021                 :            : 
    1022                 :            : The variable is reset to the value it had before the `ContextVar.set()` that
    1023                 :            : created the token was used.
    1024                 :            : [clinic start generated code]*/
    1025                 :            : 
    1026                 :            : static PyObject *
    1027                 :          0 : _contextvars_ContextVar_reset(PyContextVar *self, PyObject *token)
    1028                 :            : /*[clinic end generated code: output=d4ee34d0742d62ee input=ebe2881e5af4ffda]*/
    1029                 :            : {
    1030         [ #  # ]:          0 :     if (!PyContextToken_CheckExact(token)) {
    1031                 :          0 :         PyErr_Format(PyExc_TypeError,
    1032                 :            :                      "expected an instance of Token, got %R", token);
    1033                 :          0 :         return NULL;
    1034                 :            :     }
    1035                 :            : 
    1036         [ #  # ]:          0 :     if (PyContextVar_Reset((PyObject *)self, token)) {
    1037                 :          0 :         return NULL;
    1038                 :            :     }
    1039                 :            : 
    1040                 :          0 :     Py_RETURN_NONE;
    1041                 :            : }
    1042                 :            : 
    1043                 :            : 
    1044                 :            : static PyMemberDef PyContextVar_members[] = {
    1045                 :            :     {"name", T_OBJECT, offsetof(PyContextVar, var_name), READONLY},
    1046                 :            :     {NULL}
    1047                 :            : };
    1048                 :            : 
    1049                 :            : static PyMethodDef PyContextVar_methods[] = {
    1050                 :            :     _CONTEXTVARS_CONTEXTVAR_GET_METHODDEF
    1051                 :            :     _CONTEXTVARS_CONTEXTVAR_SET_METHODDEF
    1052                 :            :     _CONTEXTVARS_CONTEXTVAR_RESET_METHODDEF
    1053                 :            :     {"__class_getitem__", Py_GenericAlias,
    1054                 :            :     METH_O|METH_CLASS,       PyDoc_STR("See PEP 585")},
    1055                 :            :     {NULL, NULL}
    1056                 :            : };
    1057                 :            : 
    1058                 :            : PyTypeObject PyContextVar_Type = {
    1059                 :            :     PyVarObject_HEAD_INIT(&PyType_Type, 0)
    1060                 :            :     "_contextvars.ContextVar",
    1061                 :            :     sizeof(PyContextVar),
    1062                 :            :     .tp_methods = PyContextVar_methods,
    1063                 :            :     .tp_members = PyContextVar_members,
    1064                 :            :     .tp_dealloc = (destructor)contextvar_tp_dealloc,
    1065                 :            :     .tp_getattro = PyObject_GenericGetAttr,
    1066                 :            :     .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
    1067                 :            :     .tp_traverse = (traverseproc)contextvar_tp_traverse,
    1068                 :            :     .tp_clear = (inquiry)contextvar_tp_clear,
    1069                 :            :     .tp_new = contextvar_tp_new,
    1070                 :            :     .tp_free = PyObject_GC_Del,
    1071                 :            :     .tp_hash = (hashfunc)contextvar_tp_hash,
    1072                 :            :     .tp_repr = (reprfunc)contextvar_tp_repr,
    1073                 :            : };
    1074                 :            : 
    1075                 :            : 
    1076                 :            : /////////////////////////// Token
    1077                 :            : 
    1078                 :            : static PyObject * get_token_missing(void);
    1079                 :            : 
    1080                 :            : 
    1081                 :            : /*[clinic input]
    1082                 :            : class _contextvars.Token "PyContextToken *" "&PyContextToken_Type"
    1083                 :            : [clinic start generated code]*/
    1084                 :            : /*[clinic end generated code: output=da39a3ee5e6b4b0d input=338a5e2db13d3f5b]*/
    1085                 :            : 
    1086                 :            : 
    1087                 :            : static PyObject *
    1088                 :          0 : token_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
    1089                 :            : {
    1090                 :          0 :     PyErr_SetString(PyExc_RuntimeError,
    1091                 :            :                     "Tokens can only be created by ContextVars");
    1092                 :          0 :     return NULL;
    1093                 :            : }
    1094                 :            : 
    1095                 :            : static int
    1096                 :         61 : token_tp_clear(PyContextToken *self)
    1097                 :            : {
    1098         [ +  - ]:         61 :     Py_CLEAR(self->tok_ctx);
    1099         [ +  - ]:         61 :     Py_CLEAR(self->tok_var);
    1100         [ +  + ]:         61 :     Py_CLEAR(self->tok_oldval);
    1101                 :         61 :     return 0;
    1102                 :            : }
    1103                 :            : 
    1104                 :            : static int
    1105                 :          0 : token_tp_traverse(PyContextToken *self, visitproc visit, void *arg)
    1106                 :            : {
    1107   [ #  #  #  # ]:          0 :     Py_VISIT(self->tok_ctx);
    1108   [ #  #  #  # ]:          0 :     Py_VISIT(self->tok_var);
    1109   [ #  #  #  # ]:          0 :     Py_VISIT(self->tok_oldval);
    1110                 :          0 :     return 0;
    1111                 :            : }
    1112                 :            : 
    1113                 :            : static void
    1114                 :         61 : token_tp_dealloc(PyContextToken *self)
    1115                 :            : {
    1116                 :         61 :     PyObject_GC_UnTrack(self);
    1117                 :         61 :     (void)token_tp_clear(self);
    1118                 :         61 :     Py_TYPE(self)->tp_free(self);
    1119                 :         61 : }
    1120                 :            : 
    1121                 :            : static PyObject *
    1122                 :          0 : token_tp_repr(PyContextToken *self)
    1123                 :            : {
    1124                 :            :     _PyUnicodeWriter writer;
    1125                 :            : 
    1126                 :          0 :     _PyUnicodeWriter_Init(&writer);
    1127                 :            : 
    1128         [ #  # ]:          0 :     if (_PyUnicodeWriter_WriteASCIIString(&writer, "<Token", 6) < 0) {
    1129                 :          0 :         goto error;
    1130                 :            :     }
    1131                 :            : 
    1132         [ #  # ]:          0 :     if (self->tok_used) {
    1133         [ #  # ]:          0 :         if (_PyUnicodeWriter_WriteASCIIString(&writer, " used", 5) < 0) {
    1134                 :          0 :             goto error;
    1135                 :            :         }
    1136                 :            :     }
    1137                 :            : 
    1138         [ #  # ]:          0 :     if (_PyUnicodeWriter_WriteASCIIString(&writer, " var=", 5) < 0) {
    1139                 :          0 :         goto error;
    1140                 :            :     }
    1141                 :            : 
    1142                 :          0 :     PyObject *var = PyObject_Repr((PyObject *)self->tok_var);
    1143         [ #  # ]:          0 :     if (var == NULL) {
    1144                 :          0 :         goto error;
    1145                 :            :     }
    1146         [ #  # ]:          0 :     if (_PyUnicodeWriter_WriteStr(&writer, var) < 0) {
    1147                 :          0 :         Py_DECREF(var);
    1148                 :          0 :         goto error;
    1149                 :            :     }
    1150                 :          0 :     Py_DECREF(var);
    1151                 :            : 
    1152                 :          0 :     PyObject *addr = PyUnicode_FromFormat(" at %p>", self);
    1153         [ #  # ]:          0 :     if (addr == NULL) {
    1154                 :          0 :         goto error;
    1155                 :            :     }
    1156         [ #  # ]:          0 :     if (_PyUnicodeWriter_WriteStr(&writer, addr) < 0) {
    1157                 :          0 :         Py_DECREF(addr);
    1158                 :          0 :         goto error;
    1159                 :            :     }
    1160                 :          0 :     Py_DECREF(addr);
    1161                 :            : 
    1162                 :          0 :     return _PyUnicodeWriter_Finish(&writer);
    1163                 :            : 
    1164                 :          0 : error:
    1165                 :          0 :     _PyUnicodeWriter_Dealloc(&writer);
    1166                 :          0 :     return NULL;
    1167                 :            : }
    1168                 :            : 
    1169                 :            : static PyObject *
    1170                 :          0 : token_get_var(PyContextToken *self, void *Py_UNUSED(ignored))
    1171                 :            : {
    1172                 :          0 :     return Py_NewRef(self->tok_var);;
    1173                 :            : }
    1174                 :            : 
    1175                 :            : static PyObject *
    1176                 :          0 : token_get_old_value(PyContextToken *self, void *Py_UNUSED(ignored))
    1177                 :            : {
    1178         [ #  # ]:          0 :     if (self->tok_oldval == NULL) {
    1179                 :          0 :         return get_token_missing();
    1180                 :            :     }
    1181                 :            : 
    1182                 :          0 :     return Py_NewRef(self->tok_oldval);
    1183                 :            : }
    1184                 :            : 
    1185                 :            : static PyGetSetDef PyContextTokenType_getsetlist[] = {
    1186                 :            :     {"var", (getter)token_get_var, NULL, NULL},
    1187                 :            :     {"old_value", (getter)token_get_old_value, NULL, NULL},
    1188                 :            :     {NULL}
    1189                 :            : };
    1190                 :            : 
    1191                 :            : static PyMethodDef PyContextTokenType_methods[] = {
    1192                 :            :     {"__class_getitem__",    Py_GenericAlias,
    1193                 :            :     METH_O|METH_CLASS,       PyDoc_STR("See PEP 585")},
    1194                 :            :     {NULL}
    1195                 :            : };
    1196                 :            : 
    1197                 :            : PyTypeObject PyContextToken_Type = {
    1198                 :            :     PyVarObject_HEAD_INIT(&PyType_Type, 0)
    1199                 :            :     "_contextvars.Token",
    1200                 :            :     sizeof(PyContextToken),
    1201                 :            :     .tp_methods = PyContextTokenType_methods,
    1202                 :            :     .tp_getset = PyContextTokenType_getsetlist,
    1203                 :            :     .tp_dealloc = (destructor)token_tp_dealloc,
    1204                 :            :     .tp_getattro = PyObject_GenericGetAttr,
    1205                 :            :     .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
    1206                 :            :     .tp_traverse = (traverseproc)token_tp_traverse,
    1207                 :            :     .tp_clear = (inquiry)token_tp_clear,
    1208                 :            :     .tp_new = token_tp_new,
    1209                 :            :     .tp_free = PyObject_GC_Del,
    1210                 :            :     .tp_hash = PyObject_HashNotImplemented,
    1211                 :            :     .tp_repr = (reprfunc)token_tp_repr,
    1212                 :            : };
    1213                 :            : 
    1214                 :            : static PyContextToken *
    1215                 :         61 : token_new(PyContext *ctx, PyContextVar *var, PyObject *val)
    1216                 :            : {
    1217                 :         61 :     PyContextToken *tok = PyObject_GC_New(PyContextToken, &PyContextToken_Type);
    1218         [ -  + ]:         61 :     if (tok == NULL) {
    1219                 :          0 :         return NULL;
    1220                 :            :     }
    1221                 :            : 
    1222                 :         61 :     tok->tok_ctx = (PyContext*)Py_NewRef(ctx);
    1223                 :            : 
    1224                 :         61 :     tok->tok_var = (PyContextVar*)Py_NewRef(var);
    1225                 :            : 
    1226                 :         61 :     tok->tok_oldval = Py_XNewRef(val);
    1227                 :            : 
    1228                 :         61 :     tok->tok_used = 0;
    1229                 :            : 
    1230                 :         61 :     PyObject_GC_Track(tok);
    1231                 :         61 :     return tok;
    1232                 :            : }
    1233                 :            : 
    1234                 :            : 
    1235                 :            : /////////////////////////// Token.MISSING
    1236                 :            : 
    1237                 :            : 
    1238                 :            : static PyObject *
    1239                 :          0 : context_token_missing_tp_repr(PyObject *self)
    1240                 :            : {
    1241                 :          0 :     return PyUnicode_FromString("<Token.MISSING>");
    1242                 :            : }
    1243                 :            : 
    1244                 :            : static void
    1245                 :          0 : context_token_missing_tp_dealloc(_PyContextTokenMissing *Py_UNUSED(self))
    1246                 :            : {
    1247                 :            : #ifdef Py_DEBUG
    1248                 :            :     /* The singleton is statically allocated. */
    1249                 :            :     _Py_FatalRefcountError("deallocating the token missing singleton");
    1250                 :            : #else
    1251                 :          0 :     return;
    1252                 :            : #endif
    1253                 :            : }
    1254                 :            : 
    1255                 :            : 
    1256                 :            : PyTypeObject _PyContextTokenMissing_Type = {
    1257                 :            :     PyVarObject_HEAD_INIT(&PyType_Type, 0)
    1258                 :            :     "Token.MISSING",
    1259                 :            :     sizeof(_PyContextTokenMissing),
    1260                 :            :     .tp_dealloc = (destructor)context_token_missing_tp_dealloc,
    1261                 :            :     .tp_getattro = PyObject_GenericGetAttr,
    1262                 :            :     .tp_flags = Py_TPFLAGS_DEFAULT,
    1263                 :            :     .tp_repr = context_token_missing_tp_repr,
    1264                 :            : };
    1265                 :            : 
    1266                 :            : 
    1267                 :            : static PyObject *
    1268                 :         29 : get_token_missing(void)
    1269                 :            : {
    1270                 :         29 :     return Py_NewRef(&_Py_SINGLETON(context_token_missing));
    1271                 :            : }
    1272                 :            : 
    1273                 :            : 
    1274                 :            : ///////////////////////////
    1275                 :            : 
    1276                 :            : 
    1277                 :            : void
    1278                 :        137 : _PyContext_ClearFreeList(PyInterpreterState *interp)
    1279                 :            : {
    1280                 :            : #if PyContext_MAXFREELIST > 0
    1281                 :        137 :     struct _Py_context_state *state = &interp->context;
    1282         [ +  + ]:        138 :     for (; state->numfree; state->numfree--) {
    1283                 :          1 :         PyContext *ctx = state->freelist;
    1284                 :          1 :         state->freelist = (PyContext *)ctx->ctx_weakreflist;
    1285                 :          1 :         ctx->ctx_weakreflist = NULL;
    1286                 :          1 :         PyObject_GC_Del(ctx);
    1287                 :            :     }
    1288                 :            : #endif
    1289                 :        137 : }
    1290                 :            : 
    1291                 :            : 
    1292                 :            : void
    1293                 :         25 : _PyContext_Fini(PyInterpreterState *interp)
    1294                 :            : {
    1295                 :         25 :     _PyContext_ClearFreeList(interp);
    1296                 :            : #if defined(Py_DEBUG) && PyContext_MAXFREELIST > 0
    1297                 :            :     struct _Py_context_state *state = &interp->context;
    1298                 :            :     state->numfree = -1;
    1299                 :            : #endif
    1300                 :         25 : }
    1301                 :            : 
    1302                 :            : 
    1303                 :            : PyStatus
    1304                 :         29 : _PyContext_Init(PyInterpreterState *interp)
    1305                 :            : {
    1306         [ -  + ]:         29 :     if (!_Py_IsMainInterpreter(interp)) {
    1307                 :          0 :         return _PyStatus_OK();
    1308                 :            :     }
    1309                 :            : 
    1310                 :         29 :     PyObject *missing = get_token_missing();
    1311         [ -  + ]:         29 :     if (PyDict_SetItemString(
    1312                 :            :         PyContextToken_Type.tp_dict, "MISSING", missing))
    1313                 :            :     {
    1314                 :          0 :         Py_DECREF(missing);
    1315                 :          0 :         return _PyStatus_ERR("can't init context types");
    1316                 :            :     }
    1317                 :         29 :     Py_DECREF(missing);
    1318                 :            : 
    1319                 :         29 :     return _PyStatus_OK();
    1320                 :            : }

Generated by: LCOV version 1.14