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