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 : : }
|