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