1 #ifndef Py_BUILD_CORE_BUILTIN
2 # define Py_BUILD_CORE_MODULE 1
3 #endif
4
5 #include "Python.h"
6 #include "pycore_dict.h" // _PyDict_GetItem_KnownHash()
7 #include "pycore_modsupport.h" // _PyArg_CheckPositional()
8 #include "pycore_moduleobject.h" // _PyModule_GetState()
9 #include "pycore_pyerrors.h" // _PyErr_ClearExcState()
10 #include "pycore_pylifecycle.h" // _Py_IsInterpreterFinalizing()
11 #include "pycore_pystate.h" // _PyThreadState_GET()
12 #include "pycore_runtime_init.h" // _Py_ID()
13
14 #include <stddef.h> // offsetof()
15
16
17 /*[clinic input]
18 module _asyncio
19 [clinic start generated code]*/
20 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=8fd17862aa989c69]*/
21
22
23 #define FI_FREELIST_MAXLEN 255
24
25 typedef struct futureiterobject futureiterobject;
26
27 /* State of the _asyncio module */
28 typedef struct {
29 PyTypeObject *FutureIterType;
30 PyTypeObject *TaskStepMethWrapper_Type;
31 PyTypeObject *FutureType;
32 PyTypeObject *TaskType;
33
34 PyObject *asyncio_mod;
35 PyObject *context_kwname;
36
37 /* Dictionary containing tasks that are currently active in
38 all running event loops. {EventLoop: Task} */
39 PyObject *current_tasks;
40
41 /* WeakSet containing all tasks scheduled to run on event loops. */
42 PyObject *scheduled_tasks;
43
44 /* Set containing all eagerly executing tasks. */
45 PyObject *eager_tasks;
46
47 /* An isinstance type cache for the 'is_coroutine()' function. */
48 PyObject *iscoroutine_typecache;
49
50 /* Imports from asyncio.events. */
51 PyObject *asyncio_get_event_loop_policy;
52
53 /* Imports from asyncio.base_futures. */
54 PyObject *asyncio_future_repr_func;
55
56 /* Imports from asyncio.exceptions. */
57 PyObject *asyncio_CancelledError;
58 PyObject *asyncio_InvalidStateError;
59
60 /* Imports from asyncio.base_tasks. */
61 PyObject *asyncio_task_get_stack_func;
62 PyObject *asyncio_task_print_stack_func;
63 PyObject *asyncio_task_repr_func;
64
65 /* Imports from asyncio.coroutines. */
66 PyObject *asyncio_iscoroutine_func;
67
68 /* Imports from traceback. */
69 PyObject *traceback_extract_stack;
70
71 /* Counter for autogenerated Task names */
72 uint64_t task_name_counter;
73
74 #ifndef Py_GIL_DISABLED
75 futureiterobject *fi_freelist;
76 Py_ssize_t fi_freelist_len;
77 #endif
78 } asyncio_state;
79
80 static inline asyncio_state *
get_asyncio_state(PyObject * mod)81 get_asyncio_state(PyObject *mod)
82 {
83 asyncio_state *state = _PyModule_GetState(mod);
84 assert(state != NULL);
85 return state;
86 }
87
88 static inline asyncio_state *
get_asyncio_state_by_cls(PyTypeObject * cls)89 get_asyncio_state_by_cls(PyTypeObject *cls)
90 {
91 asyncio_state *state = (asyncio_state *)_PyType_GetModuleState(cls);
92 assert(state != NULL);
93 return state;
94 }
95
96 static struct PyModuleDef _asynciomodule;
97
98 static inline asyncio_state *
get_asyncio_state_by_def(PyObject * self)99 get_asyncio_state_by_def(PyObject *self)
100 {
101 PyTypeObject *tp = Py_TYPE(self);
102 PyObject *mod = PyType_GetModuleByDef(tp, &_asynciomodule);
103 assert(mod != NULL);
104 return get_asyncio_state(mod);
105 }
106
107 typedef enum {
108 STATE_PENDING,
109 STATE_CANCELLED,
110 STATE_FINISHED
111 } fut_state;
112
113 #define FutureObj_HEAD(prefix) \
114 PyObject_HEAD \
115 PyObject *prefix##_loop; \
116 PyObject *prefix##_callback0; \
117 PyObject *prefix##_context0; \
118 PyObject *prefix##_callbacks; \
119 PyObject *prefix##_exception; \
120 PyObject *prefix##_exception_tb; \
121 PyObject *prefix##_result; \
122 PyObject *prefix##_source_tb; \
123 PyObject *prefix##_cancel_msg; \
124 PyObject *prefix##_cancelled_exc; \
125 fut_state prefix##_state; \
126 /* These bitfields need to be at the end of the struct
127 so that these and bitfields from TaskObj are contiguous.
128 */ \
129 unsigned prefix##_log_tb: 1; \
130 unsigned prefix##_blocking: 1;
131
132 typedef struct {
133 FutureObj_HEAD(fut)
134 } FutureObj;
135
136 typedef struct {
137 FutureObj_HEAD(task)
138 unsigned task_must_cancel: 1;
139 unsigned task_log_destroy_pending: 1;
140 int task_num_cancels_requested;
141 PyObject *task_fut_waiter;
142 PyObject *task_coro;
143 PyObject *task_name;
144 PyObject *task_context;
145 } TaskObj;
146
147 typedef struct {
148 PyObject_HEAD
149 TaskObj *sw_task;
150 PyObject *sw_arg;
151 } TaskStepMethWrapper;
152
153
154 #define Future_CheckExact(state, obj) Py_IS_TYPE(obj, state->FutureType)
155 #define Task_CheckExact(state, obj) Py_IS_TYPE(obj, state->TaskType)
156
157 #define Future_Check(state, obj) PyObject_TypeCheck(obj, state->FutureType)
158 #define Task_Check(state, obj) PyObject_TypeCheck(obj, state->TaskType)
159
160 #include "clinic/_asynciomodule.c.h"
161
162
163 /*[clinic input]
164 class _asyncio.Future "FutureObj *" "&Future_Type"
165 [clinic start generated code]*/
166 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=00d3e4abca711e0f]*/
167
168
169 /* Get FutureIter from Future */
170 static PyObject * future_new_iter(PyObject *);
171
172 static PyObject *
173 task_step_handle_result_impl(asyncio_state *state, TaskObj *task, PyObject *result);
174
175
176 static int
_is_coroutine(asyncio_state * state,PyObject * coro)177 _is_coroutine(asyncio_state *state, PyObject *coro)
178 {
179 /* 'coro' is not a native coroutine, call asyncio.iscoroutine()
180 to check if it's another coroutine flavour.
181
182 Do this check after 'future_init()'; in case we need to raise
183 an error, __del__ needs a properly initialized object.
184 */
185 PyObject *res = PyObject_CallOneArg(state->asyncio_iscoroutine_func, coro);
186 if (res == NULL) {
187 return -1;
188 }
189
190 int is_res_true = PyObject_IsTrue(res);
191 Py_DECREF(res);
192 if (is_res_true <= 0) {
193 return is_res_true;
194 }
195
196 if (PySet_GET_SIZE(state->iscoroutine_typecache) < 100) {
197 /* Just in case we don't want to cache more than 100
198 positive types. That shouldn't ever happen, unless
199 someone stressing the system on purpose.
200 */
201 if (PySet_Add(state->iscoroutine_typecache, (PyObject*) Py_TYPE(coro))) {
202 return -1;
203 }
204 }
205
206 return 1;
207 }
208
209
210 static inline int
is_coroutine(asyncio_state * state,PyObject * coro)211 is_coroutine(asyncio_state *state, PyObject *coro)
212 {
213 if (PyCoro_CheckExact(coro)) {
214 return 1;
215 }
216
217 /* Check if `type(coro)` is in the cache.
218 Caching makes is_coroutine() function almost as fast as
219 PyCoro_CheckExact() for non-native coroutine-like objects
220 (like coroutines compiled with Cython).
221
222 asyncio.iscoroutine() has its own type caching mechanism.
223 This cache allows us to avoid the cost of even calling
224 a pure-Python function in 99.9% cases.
225 */
226 int has_it = PySet_Contains(
227 state->iscoroutine_typecache, (PyObject*) Py_TYPE(coro));
228 if (has_it == 0) {
229 /* type(coro) is not in iscoroutine_typecache */
230 return _is_coroutine(state, coro);
231 }
232
233 /* either an error has occurred or
234 type(coro) is in iscoroutine_typecache
235 */
236 return has_it;
237 }
238
239
240 static PyObject *
get_future_loop(asyncio_state * state,PyObject * fut)241 get_future_loop(asyncio_state *state, PyObject *fut)
242 {
243 /* Implementation of `asyncio.futures._get_loop` */
244
245 PyObject *getloop;
246
247 if (Future_CheckExact(state, fut) || Task_CheckExact(state, fut)) {
248 PyObject *loop = ((FutureObj *)fut)->fut_loop;
249 return Py_NewRef(loop);
250 }
251
252 if (PyObject_GetOptionalAttr(fut, &_Py_ID(get_loop), &getloop) < 0) {
253 return NULL;
254 }
255 if (getloop != NULL) {
256 PyObject *res = PyObject_CallNoArgs(getloop);
257 Py_DECREF(getloop);
258 return res;
259 }
260
261 return PyObject_GetAttr(fut, &_Py_ID(_loop));
262 }
263
264 static PyObject *
get_event_loop(asyncio_state * state)265 get_event_loop(asyncio_state *state)
266 {
267 PyObject *loop;
268 PyObject *policy;
269
270 _PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET();
271 loop = Py_XNewRef(ts->asyncio_running_loop);
272
273 if (loop != NULL) {
274 return loop;
275 }
276
277 policy = PyObject_CallNoArgs(state->asyncio_get_event_loop_policy);
278 if (policy == NULL) {
279 return NULL;
280 }
281
282 loop = PyObject_CallMethodNoArgs(policy, &_Py_ID(get_event_loop));
283 Py_DECREF(policy);
284 return loop;
285 }
286
287
288 static int
call_soon(asyncio_state * state,PyObject * loop,PyObject * func,PyObject * arg,PyObject * ctx)289 call_soon(asyncio_state *state, PyObject *loop, PyObject *func, PyObject *arg,
290 PyObject *ctx)
291 {
292 PyObject *handle;
293
294 if (ctx == NULL) {
295 PyObject *stack[] = {loop, func, arg};
296 size_t nargsf = 3 | PY_VECTORCALL_ARGUMENTS_OFFSET;
297 handle = PyObject_VectorcallMethod(&_Py_ID(call_soon), stack, nargsf, NULL);
298 }
299 else {
300 /* All refs in 'stack' are borrowed. */
301 PyObject *stack[4];
302 size_t nargs = 2;
303 stack[0] = loop;
304 stack[1] = func;
305 if (arg != NULL) {
306 stack[2] = arg;
307 nargs++;
308 }
309 stack[nargs] = (PyObject *)ctx;
310 size_t nargsf = nargs | PY_VECTORCALL_ARGUMENTS_OFFSET;
311 handle = PyObject_VectorcallMethod(&_Py_ID(call_soon), stack, nargsf,
312 state->context_kwname);
313 }
314
315 if (handle == NULL) {
316 return -1;
317 }
318 Py_DECREF(handle);
319 return 0;
320 }
321
322
323 static inline int
future_is_alive(FutureObj * fut)324 future_is_alive(FutureObj *fut)
325 {
326 return fut->fut_loop != NULL;
327 }
328
329
330 static inline int
future_ensure_alive(FutureObj * fut)331 future_ensure_alive(FutureObj *fut)
332 {
333 if (!future_is_alive(fut)) {
334 PyErr_SetString(PyExc_RuntimeError,
335 "Future object is not initialized.");
336 return -1;
337 }
338 return 0;
339 }
340
341
342 #define ENSURE_FUTURE_ALIVE(state, fut) \
343 do { \
344 assert(Future_Check(state, fut) || Task_Check(state, fut)); \
345 (void)state; \
346 if (future_ensure_alive((FutureObj*)fut)) { \
347 return NULL; \
348 } \
349 } while(0);
350
351
352 static int
future_schedule_callbacks(asyncio_state * state,FutureObj * fut)353 future_schedule_callbacks(asyncio_state *state, FutureObj *fut)
354 {
355 if (fut->fut_callback0 != NULL) {
356 /* There's a 1st callback */
357
358 // Beware: An evil call_soon could alter fut_callback0 or fut_context0.
359 // Since we are anyway clearing them after the call, whether call_soon
360 // succeeds or not, the idea is to transfer ownership so that external
361 // code is not able to alter them during the call.
362 PyObject *fut_callback0 = fut->fut_callback0;
363 fut->fut_callback0 = NULL;
364 PyObject *fut_context0 = fut->fut_context0;
365 fut->fut_context0 = NULL;
366
367 int ret = call_soon(state, fut->fut_loop, fut_callback0,
368 (PyObject *)fut, fut_context0);
369 Py_CLEAR(fut_callback0);
370 Py_CLEAR(fut_context0);
371 if (ret) {
372 /* If an error occurs in pure-Python implementation,
373 all callbacks are cleared. */
374 Py_CLEAR(fut->fut_callbacks);
375 return ret;
376 }
377
378 /* we called the first callback, now try calling
379 callbacks from the 'fut_callbacks' list. */
380 }
381
382 if (fut->fut_callbacks == NULL) {
383 /* No more callbacks, return. */
384 return 0;
385 }
386
387 // Beware: An evil call_soon could change fut->fut_callbacks.
388 // The idea is to transfer the ownership of the callbacks list
389 // so that external code is not able to mutate the list during
390 // the iteration.
391 PyObject *callbacks = fut->fut_callbacks;
392 fut->fut_callbacks = NULL;
393 Py_ssize_t n = PyList_GET_SIZE(callbacks);
394 for (Py_ssize_t i = 0; i < n; i++) {
395 assert(PyList_GET_SIZE(callbacks) == n);
396 PyObject *cb_tup = PyList_GET_ITEM(callbacks, i);
397 PyObject *cb = PyTuple_GET_ITEM(cb_tup, 0);
398 PyObject *ctx = PyTuple_GET_ITEM(cb_tup, 1);
399
400 if (call_soon(state, fut->fut_loop, cb, (PyObject *)fut, ctx)) {
401 Py_DECREF(callbacks);
402 return -1;
403 }
404 }
405 Py_DECREF(callbacks);
406 return 0;
407 }
408
409
410 static int
future_init(FutureObj * fut,PyObject * loop)411 future_init(FutureObj *fut, PyObject *loop)
412 {
413 PyObject *res;
414 int is_true;
415
416 Py_CLEAR(fut->fut_loop);
417 Py_CLEAR(fut->fut_callback0);
418 Py_CLEAR(fut->fut_context0);
419 Py_CLEAR(fut->fut_callbacks);
420 Py_CLEAR(fut->fut_result);
421 Py_CLEAR(fut->fut_exception);
422 Py_CLEAR(fut->fut_exception_tb);
423 Py_CLEAR(fut->fut_source_tb);
424 Py_CLEAR(fut->fut_cancel_msg);
425 Py_CLEAR(fut->fut_cancelled_exc);
426
427 fut->fut_state = STATE_PENDING;
428 fut->fut_log_tb = 0;
429 fut->fut_blocking = 0;
430
431 if (loop == Py_None) {
432 asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut);
433 loop = get_event_loop(state);
434 if (loop == NULL) {
435 return -1;
436 }
437 }
438 else {
439 Py_INCREF(loop);
440 }
441 fut->fut_loop = loop;
442
443 res = PyObject_CallMethodNoArgs(fut->fut_loop, &_Py_ID(get_debug));
444 if (res == NULL) {
445 return -1;
446 }
447 is_true = PyObject_IsTrue(res);
448 Py_DECREF(res);
449 if (is_true < 0) {
450 return -1;
451 }
452 if (is_true && !_Py_IsInterpreterFinalizing(_PyInterpreterState_GET())) {
453 /* Only try to capture the traceback if the interpreter is not being
454 finalized. The original motivation to add a `Py_IsFinalizing()`
455 call was to prevent SIGSEGV when a Future is created in a __del__
456 method, which is called during the interpreter shutdown and the
457 traceback module is already unloaded.
458 */
459 asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut);
460 fut->fut_source_tb = PyObject_CallNoArgs(state->traceback_extract_stack);
461 if (fut->fut_source_tb == NULL) {
462 return -1;
463 }
464 }
465
466 return 0;
467 }
468
469 static PyObject *
future_set_result(asyncio_state * state,FutureObj * fut,PyObject * res)470 future_set_result(asyncio_state *state, FutureObj *fut, PyObject *res)
471 {
472 if (future_ensure_alive(fut)) {
473 return NULL;
474 }
475
476 if (fut->fut_state != STATE_PENDING) {
477 PyErr_SetString(state->asyncio_InvalidStateError, "invalid state");
478 return NULL;
479 }
480
481 assert(!fut->fut_result);
482 fut->fut_result = Py_NewRef(res);
483 fut->fut_state = STATE_FINISHED;
484
485 if (future_schedule_callbacks(state, fut) == -1) {
486 return NULL;
487 }
488 Py_RETURN_NONE;
489 }
490
491 static PyObject *
future_set_exception(asyncio_state * state,FutureObj * fut,PyObject * exc)492 future_set_exception(asyncio_state *state, FutureObj *fut, PyObject *exc)
493 {
494 PyObject *exc_val = NULL;
495
496 if (fut->fut_state != STATE_PENDING) {
497 PyErr_SetString(state->asyncio_InvalidStateError, "invalid state");
498 return NULL;
499 }
500
501 if (PyExceptionClass_Check(exc)) {
502 exc_val = PyObject_CallNoArgs(exc);
503 if (exc_val == NULL) {
504 return NULL;
505 }
506 if (fut->fut_state != STATE_PENDING) {
507 Py_DECREF(exc_val);
508 PyErr_SetString(state->asyncio_InvalidStateError, "invalid state");
509 return NULL;
510 }
511 }
512 else {
513 exc_val = Py_NewRef(exc);
514 }
515 if (!PyExceptionInstance_Check(exc_val)) {
516 Py_DECREF(exc_val);
517 PyErr_SetString(PyExc_TypeError, "invalid exception object");
518 return NULL;
519 }
520 if (PyErr_GivenExceptionMatches(exc_val, PyExc_StopIteration)) {
521 const char *msg = "StopIteration interacts badly with "
522 "generators and cannot be raised into a "
523 "Future";
524 PyObject *message = PyUnicode_FromString(msg);
525 if (message == NULL) {
526 Py_DECREF(exc_val);
527 return NULL;
528 }
529 PyObject *err = PyObject_CallOneArg(PyExc_RuntimeError, message);
530 Py_DECREF(message);
531 if (err == NULL) {
532 Py_DECREF(exc_val);
533 return NULL;
534 }
535 assert(PyExceptionInstance_Check(err));
536
537 PyException_SetCause(err, Py_NewRef(exc_val));
538 PyException_SetContext(err, Py_NewRef(exc_val));
539 Py_DECREF(exc_val);
540 exc_val = err;
541 }
542
543 assert(!fut->fut_exception);
544 assert(!fut->fut_exception_tb);
545 fut->fut_exception = exc_val;
546 fut->fut_exception_tb = PyException_GetTraceback(exc_val);
547 fut->fut_state = STATE_FINISHED;
548
549 if (future_schedule_callbacks(state, fut) == -1) {
550 return NULL;
551 }
552
553 fut->fut_log_tb = 1;
554 Py_RETURN_NONE;
555 }
556
557 static PyObject *
create_cancelled_error(asyncio_state * state,FutureObj * fut)558 create_cancelled_error(asyncio_state *state, FutureObj *fut)
559 {
560 PyObject *exc;
561 if (fut->fut_cancelled_exc != NULL) {
562 /* transfer ownership */
563 exc = fut->fut_cancelled_exc;
564 fut->fut_cancelled_exc = NULL;
565 return exc;
566 }
567 PyObject *msg = fut->fut_cancel_msg;
568 if (msg == NULL || msg == Py_None) {
569 exc = PyObject_CallNoArgs(state->asyncio_CancelledError);
570 } else {
571 exc = PyObject_CallOneArg(state->asyncio_CancelledError, msg);
572 }
573 return exc;
574 }
575
576 static void
future_set_cancelled_error(asyncio_state * state,FutureObj * fut)577 future_set_cancelled_error(asyncio_state *state, FutureObj *fut)
578 {
579 PyObject *exc = create_cancelled_error(state, fut);
580 if (exc == NULL) {
581 return;
582 }
583 PyErr_SetObject(state->asyncio_CancelledError, exc);
584 Py_DECREF(exc);
585 }
586
587 static int
future_get_result(asyncio_state * state,FutureObj * fut,PyObject ** result)588 future_get_result(asyncio_state *state, FutureObj *fut, PyObject **result)
589 {
590 if (fut->fut_state == STATE_CANCELLED) {
591 future_set_cancelled_error(state, fut);
592 return -1;
593 }
594
595 if (fut->fut_state != STATE_FINISHED) {
596 PyErr_SetString(state->asyncio_InvalidStateError,
597 "Result is not set.");
598 return -1;
599 }
600
601 fut->fut_log_tb = 0;
602 if (fut->fut_exception != NULL) {
603 PyObject *tb = fut->fut_exception_tb;
604 if (tb == NULL) {
605 tb = Py_None;
606 }
607 if (PyException_SetTraceback(fut->fut_exception, tb) < 0) {
608 return -1;
609 }
610 *result = Py_NewRef(fut->fut_exception);
611 Py_CLEAR(fut->fut_exception_tb);
612 return 1;
613 }
614
615 *result = Py_NewRef(fut->fut_result);
616 return 0;
617 }
618
619 static PyObject *
future_add_done_callback(asyncio_state * state,FutureObj * fut,PyObject * arg,PyObject * ctx)620 future_add_done_callback(asyncio_state *state, FutureObj *fut, PyObject *arg,
621 PyObject *ctx)
622 {
623 if (!future_is_alive(fut)) {
624 PyErr_SetString(PyExc_RuntimeError, "uninitialized Future object");
625 return NULL;
626 }
627
628 if (fut->fut_state != STATE_PENDING) {
629 /* The future is done/cancelled, so schedule the callback
630 right away. */
631 if (call_soon(state, fut->fut_loop, arg, (PyObject*) fut, ctx)) {
632 return NULL;
633 }
634 }
635 else {
636 /* The future is pending, add a callback.
637
638 Callbacks in the future object are stored as follows:
639
640 callback0 -- a pointer to the first callback
641 callbacks -- a list of 2nd, 3rd, ... callbacks
642
643 Invariants:
644
645 * callbacks != NULL:
646 There are some callbacks in in the list. Just
647 add the new callback to it.
648
649 * callbacks == NULL and callback0 == NULL:
650 This is the first callback. Set it to callback0.
651
652 * callbacks == NULL and callback0 != NULL:
653 This is a second callback. Initialize callbacks
654 with a new list and add the new callback to it.
655 */
656
657 if (fut->fut_callbacks == NULL && fut->fut_callback0 == NULL) {
658 fut->fut_callback0 = Py_NewRef(arg);
659 fut->fut_context0 = Py_NewRef(ctx);
660 }
661 else {
662 PyObject *tup = PyTuple_New(2);
663 if (tup == NULL) {
664 return NULL;
665 }
666 Py_INCREF(arg);
667 PyTuple_SET_ITEM(tup, 0, arg);
668 Py_INCREF(ctx);
669 PyTuple_SET_ITEM(tup, 1, (PyObject *)ctx);
670
671 if (fut->fut_callbacks != NULL) {
672 int err = PyList_Append(fut->fut_callbacks, tup);
673 if (err) {
674 Py_DECREF(tup);
675 return NULL;
676 }
677 Py_DECREF(tup);
678 }
679 else {
680 fut->fut_callbacks = PyList_New(1);
681 if (fut->fut_callbacks == NULL) {
682 Py_DECREF(tup);
683 return NULL;
684 }
685
686 PyList_SET_ITEM(fut->fut_callbacks, 0, tup); /* borrow */
687 }
688 }
689 }
690
691 Py_RETURN_NONE;
692 }
693
694 static PyObject *
future_cancel(asyncio_state * state,FutureObj * fut,PyObject * msg)695 future_cancel(asyncio_state *state, FutureObj *fut, PyObject *msg)
696 {
697 fut->fut_log_tb = 0;
698
699 if (fut->fut_state != STATE_PENDING) {
700 Py_RETURN_FALSE;
701 }
702 fut->fut_state = STATE_CANCELLED;
703
704 Py_XINCREF(msg);
705 Py_XSETREF(fut->fut_cancel_msg, msg);
706
707 if (future_schedule_callbacks(state, fut) == -1) {
708 return NULL;
709 }
710
711 Py_RETURN_TRUE;
712 }
713
714 /*[clinic input]
715 _asyncio.Future.__init__
716
717 *
718 loop: object = None
719
720 This class is *almost* compatible with concurrent.futures.Future.
721
722 Differences:
723
724 - result() and exception() do not take a timeout argument and
725 raise an exception when the future isn't done yet.
726
727 - Callbacks registered with add_done_callback() are always called
728 via the event loop's call_soon_threadsafe().
729
730 - This class is not compatible with the wait() and as_completed()
731 methods in the concurrent.futures package.
732 [clinic start generated code]*/
733
734 static int
_asyncio_Future___init___impl(FutureObj * self,PyObject * loop)735 _asyncio_Future___init___impl(FutureObj *self, PyObject *loop)
736 /*[clinic end generated code: output=9ed75799eaccb5d6 input=89af317082bc0bf8]*/
737
738 {
739 return future_init(self, loop);
740 }
741
742 static int
FutureObj_clear(FutureObj * fut)743 FutureObj_clear(FutureObj *fut)
744 {
745 Py_CLEAR(fut->fut_loop);
746 Py_CLEAR(fut->fut_callback0);
747 Py_CLEAR(fut->fut_context0);
748 Py_CLEAR(fut->fut_callbacks);
749 Py_CLEAR(fut->fut_result);
750 Py_CLEAR(fut->fut_exception);
751 Py_CLEAR(fut->fut_exception_tb);
752 Py_CLEAR(fut->fut_source_tb);
753 Py_CLEAR(fut->fut_cancel_msg);
754 Py_CLEAR(fut->fut_cancelled_exc);
755 PyObject_ClearManagedDict((PyObject *)fut);
756 return 0;
757 }
758
759 static int
FutureObj_traverse(FutureObj * fut,visitproc visit,void * arg)760 FutureObj_traverse(FutureObj *fut, visitproc visit, void *arg)
761 {
762 Py_VISIT(Py_TYPE(fut));
763 Py_VISIT(fut->fut_loop);
764 Py_VISIT(fut->fut_callback0);
765 Py_VISIT(fut->fut_context0);
766 Py_VISIT(fut->fut_callbacks);
767 Py_VISIT(fut->fut_result);
768 Py_VISIT(fut->fut_exception);
769 Py_VISIT(fut->fut_exception_tb);
770 Py_VISIT(fut->fut_source_tb);
771 Py_VISIT(fut->fut_cancel_msg);
772 Py_VISIT(fut->fut_cancelled_exc);
773 PyObject_VisitManagedDict((PyObject *)fut, visit, arg);
774 return 0;
775 }
776
777 /*[clinic input]
778 _asyncio.Future.result
779
780 Return the result this future represents.
781
782 If the future has been cancelled, raises CancelledError. If the
783 future's result isn't yet available, raises InvalidStateError. If
784 the future is done and has an exception set, this exception is raised.
785 [clinic start generated code]*/
786
787 static PyObject *
_asyncio_Future_result_impl(FutureObj * self)788 _asyncio_Future_result_impl(FutureObj *self)
789 /*[clinic end generated code: output=f35f940936a4b1e5 input=49ecf9cf5ec50dc5]*/
790 {
791 asyncio_state *state = get_asyncio_state_by_def((PyObject *)self);
792 PyObject *result;
793
794 if (!future_is_alive(self)) {
795 PyErr_SetString(state->asyncio_InvalidStateError,
796 "Future object is not initialized.");
797 return NULL;
798 }
799
800 int res = future_get_result(state, self, &result);
801
802 if (res == -1) {
803 return NULL;
804 }
805
806 if (res == 0) {
807 return result;
808 }
809
810 assert(res == 1);
811
812 PyErr_SetObject(PyExceptionInstance_Class(result), result);
813 Py_DECREF(result);
814 return NULL;
815 }
816
817 /*[clinic input]
818 _asyncio.Future.exception
819
820 cls: defining_class
821 /
822
823 Return the exception that was set on this future.
824
825 The exception (or None if no exception was set) is returned only if
826 the future is done. If the future has been cancelled, raises
827 CancelledError. If the future isn't done yet, raises
828 InvalidStateError.
829 [clinic start generated code]*/
830
831 static PyObject *
_asyncio_Future_exception_impl(FutureObj * self,PyTypeObject * cls)832 _asyncio_Future_exception_impl(FutureObj *self, PyTypeObject *cls)
833 /*[clinic end generated code: output=ce75576b187c905b input=3faf15c22acdb60d]*/
834 {
835 if (!future_is_alive(self)) {
836 asyncio_state *state = get_asyncio_state_by_cls(cls);
837 PyErr_SetString(state->asyncio_InvalidStateError,
838 "Future object is not initialized.");
839 return NULL;
840 }
841
842 if (self->fut_state == STATE_CANCELLED) {
843 asyncio_state *state = get_asyncio_state_by_cls(cls);
844 future_set_cancelled_error(state, self);
845 return NULL;
846 }
847
848 if (self->fut_state != STATE_FINISHED) {
849 asyncio_state *state = get_asyncio_state_by_cls(cls);
850 PyErr_SetString(state->asyncio_InvalidStateError,
851 "Exception is not set.");
852 return NULL;
853 }
854
855 if (self->fut_exception != NULL) {
856 self->fut_log_tb = 0;
857 return Py_NewRef(self->fut_exception);
858 }
859
860 Py_RETURN_NONE;
861 }
862
863 /*[clinic input]
864 _asyncio.Future.set_result
865
866 cls: defining_class
867 result: object
868 /
869
870 Mark the future done and set its result.
871
872 If the future is already done when this method is called, raises
873 InvalidStateError.
874 [clinic start generated code]*/
875
876 static PyObject *
_asyncio_Future_set_result_impl(FutureObj * self,PyTypeObject * cls,PyObject * result)877 _asyncio_Future_set_result_impl(FutureObj *self, PyTypeObject *cls,
878 PyObject *result)
879 /*[clinic end generated code: output=99afbbe78f99c32d input=d5a41c1e353acc2e]*/
880 {
881 asyncio_state *state = get_asyncio_state_by_cls(cls);
882 ENSURE_FUTURE_ALIVE(state, self)
883 return future_set_result(state, self, result);
884 }
885
886 /*[clinic input]
887 _asyncio.Future.set_exception
888
889 cls: defining_class
890 exception: object
891 /
892
893 Mark the future done and set an exception.
894
895 If the future is already done when this method is called, raises
896 InvalidStateError.
897 [clinic start generated code]*/
898
899 static PyObject *
_asyncio_Future_set_exception_impl(FutureObj * self,PyTypeObject * cls,PyObject * exception)900 _asyncio_Future_set_exception_impl(FutureObj *self, PyTypeObject *cls,
901 PyObject *exception)
902 /*[clinic end generated code: output=0a5e8b5a52f058d6 input=a245cd49d3df939b]*/
903 {
904 asyncio_state *state = get_asyncio_state_by_cls(cls);
905 ENSURE_FUTURE_ALIVE(state, self)
906 return future_set_exception(state, self, exception);
907 }
908
909 /*[clinic input]
910 _asyncio.Future.add_done_callback
911
912 cls: defining_class
913 fn: object
914 /
915 *
916 context: object = NULL
917
918 Add a callback to be run when the future becomes done.
919
920 The callback is called with a single argument - the future object. If
921 the future is already done when this is called, the callback is
922 scheduled with call_soon.
923 [clinic start generated code]*/
924
925 static PyObject *
_asyncio_Future_add_done_callback_impl(FutureObj * self,PyTypeObject * cls,PyObject * fn,PyObject * context)926 _asyncio_Future_add_done_callback_impl(FutureObj *self, PyTypeObject *cls,
927 PyObject *fn, PyObject *context)
928 /*[clinic end generated code: output=922e9a4cbd601167 input=599261c521458cc2]*/
929 {
930 asyncio_state *state = get_asyncio_state_by_cls(cls);
931 if (context == NULL) {
932 context = PyContext_CopyCurrent();
933 if (context == NULL) {
934 return NULL;
935 }
936 PyObject *res = future_add_done_callback(state, self, fn, context);
937 Py_DECREF(context);
938 return res;
939 }
940 return future_add_done_callback(state, self, fn, context);
941 }
942
943 /*[clinic input]
944 _asyncio.Future.remove_done_callback
945
946 cls: defining_class
947 fn: object
948 /
949
950 Remove all instances of a callback from the "call when done" list.
951
952 Returns the number of callbacks removed.
953 [clinic start generated code]*/
954
955 static PyObject *
_asyncio_Future_remove_done_callback_impl(FutureObj * self,PyTypeObject * cls,PyObject * fn)956 _asyncio_Future_remove_done_callback_impl(FutureObj *self, PyTypeObject *cls,
957 PyObject *fn)
958 /*[clinic end generated code: output=2da35ccabfe41b98 input=c7518709b86fc747]*/
959 {
960 PyObject *newlist;
961 Py_ssize_t len, i, j=0;
962 Py_ssize_t cleared_callback0 = 0;
963
964 asyncio_state *state = get_asyncio_state_by_cls(cls);
965 ENSURE_FUTURE_ALIVE(state, self)
966
967 if (self->fut_callback0 != NULL) {
968 // Beware: An evil PyObject_RichCompareBool could free fut_callback0
969 // before a recursive call is made with that same arg. For details, see
970 // https://github.com/python/cpython/pull/125967#discussion_r1816593340.
971 PyObject *fut_callback0 = Py_NewRef(self->fut_callback0);
972 int cmp = PyObject_RichCompareBool(fut_callback0, fn, Py_EQ);
973 Py_DECREF(fut_callback0);
974 if (cmp == -1) {
975 return NULL;
976 }
977 if (cmp == 1) {
978 /* callback0 == fn */
979 Py_CLEAR(self->fut_callback0);
980 Py_CLEAR(self->fut_context0);
981 cleared_callback0 = 1;
982 }
983 }
984
985 if (self->fut_callbacks == NULL) {
986 return PyLong_FromSsize_t(cleared_callback0);
987 }
988
989 len = PyList_GET_SIZE(self->fut_callbacks);
990 if (len == 0) {
991 Py_CLEAR(self->fut_callbacks);
992 return PyLong_FromSsize_t(cleared_callback0);
993 }
994
995 if (len == 1) {
996 PyObject *cb_tup = PyList_GET_ITEM(self->fut_callbacks, 0);
997 Py_INCREF(cb_tup);
998 int cmp = PyObject_RichCompareBool(
999 PyTuple_GET_ITEM(cb_tup, 0), fn, Py_EQ);
1000 Py_DECREF(cb_tup);
1001 if (cmp == -1) {
1002 return NULL;
1003 }
1004 if (cmp == 1) {
1005 /* callbacks[0] == fn */
1006 Py_CLEAR(self->fut_callbacks);
1007 return PyLong_FromSsize_t(1 + cleared_callback0);
1008 }
1009 /* callbacks[0] != fn and len(callbacks) == 1 */
1010 return PyLong_FromSsize_t(cleared_callback0);
1011 }
1012
1013 newlist = PyList_New(len);
1014 if (newlist == NULL) {
1015 return NULL;
1016 }
1017
1018 // Beware: PyObject_RichCompareBool below may change fut_callbacks.
1019 // See GH-97592.
1020 for (i = 0;
1021 self->fut_callbacks != NULL && i < PyList_GET_SIZE(self->fut_callbacks);
1022 i++) {
1023 int ret;
1024 PyObject *item = PyList_GET_ITEM(self->fut_callbacks, i);
1025 Py_INCREF(item);
1026 ret = PyObject_RichCompareBool(PyTuple_GET_ITEM(item, 0), fn, Py_EQ);
1027 if (ret == 0) {
1028 if (j < len) {
1029 PyList_SET_ITEM(newlist, j, item);
1030 j++;
1031 continue;
1032 }
1033 ret = PyList_Append(newlist, item);
1034 }
1035 Py_DECREF(item);
1036 if (ret < 0) {
1037 goto fail;
1038 }
1039 }
1040
1041 // Note: fut_callbacks may have been cleared.
1042 if (j == 0 || self->fut_callbacks == NULL) {
1043 Py_CLEAR(self->fut_callbacks);
1044 Py_DECREF(newlist);
1045 return PyLong_FromSsize_t(len + cleared_callback0);
1046 }
1047
1048 if (j < len) {
1049 Py_SET_SIZE(newlist, j);
1050 }
1051 j = PyList_GET_SIZE(newlist);
1052 len = PyList_GET_SIZE(self->fut_callbacks);
1053 if (j != len) {
1054 if (PyList_SetSlice(self->fut_callbacks, 0, len, newlist) < 0) {
1055 goto fail;
1056 }
1057 }
1058 Py_DECREF(newlist);
1059 return PyLong_FromSsize_t(len - j + cleared_callback0);
1060
1061 fail:
1062 Py_DECREF(newlist);
1063 return NULL;
1064 }
1065
1066 /*[clinic input]
1067 _asyncio.Future.cancel
1068
1069 cls: defining_class
1070 /
1071 msg: object = None
1072
1073 Cancel the future and schedule callbacks.
1074
1075 If the future is already done or cancelled, return False. Otherwise,
1076 change the future's state to cancelled, schedule the callbacks and
1077 return True.
1078 [clinic start generated code]*/
1079
1080 static PyObject *
_asyncio_Future_cancel_impl(FutureObj * self,PyTypeObject * cls,PyObject * msg)1081 _asyncio_Future_cancel_impl(FutureObj *self, PyTypeObject *cls,
1082 PyObject *msg)
1083 /*[clinic end generated code: output=074956f35904b034 input=bba8f8b786941a94]*/
1084 {
1085 asyncio_state *state = get_asyncio_state_by_cls(cls);
1086 ENSURE_FUTURE_ALIVE(state, self)
1087 return future_cancel(state, self, msg);
1088 }
1089
1090 /*[clinic input]
1091 _asyncio.Future.cancelled
1092
1093 Return True if the future was cancelled.
1094 [clinic start generated code]*/
1095
1096 static PyObject *
_asyncio_Future_cancelled_impl(FutureObj * self)1097 _asyncio_Future_cancelled_impl(FutureObj *self)
1098 /*[clinic end generated code: output=145197ced586357d input=943ab8b7b7b17e45]*/
1099 {
1100 if (future_is_alive(self) && self->fut_state == STATE_CANCELLED) {
1101 Py_RETURN_TRUE;
1102 }
1103 else {
1104 Py_RETURN_FALSE;
1105 }
1106 }
1107
1108 /*[clinic input]
1109 _asyncio.Future.done
1110
1111 Return True if the future is done.
1112
1113 Done means either that a result / exception are available, or that the
1114 future was cancelled.
1115 [clinic start generated code]*/
1116
1117 static PyObject *
_asyncio_Future_done_impl(FutureObj * self)1118 _asyncio_Future_done_impl(FutureObj *self)
1119 /*[clinic end generated code: output=244c5ac351145096 input=28d7b23fdb65d2ac]*/
1120 {
1121 if (!future_is_alive(self) || self->fut_state == STATE_PENDING) {
1122 Py_RETURN_FALSE;
1123 }
1124 else {
1125 Py_RETURN_TRUE;
1126 }
1127 }
1128
1129 /*[clinic input]
1130 _asyncio.Future.get_loop
1131
1132 cls: defining_class
1133 /
1134
1135 Return the event loop the Future is bound to.
1136 [clinic start generated code]*/
1137
1138 static PyObject *
_asyncio_Future_get_loop_impl(FutureObj * self,PyTypeObject * cls)1139 _asyncio_Future_get_loop_impl(FutureObj *self, PyTypeObject *cls)
1140 /*[clinic end generated code: output=f50ea6c374d9ee97 input=163c2c498b45a1f0]*/
1141 {
1142 asyncio_state *state = get_asyncio_state_by_cls(cls);
1143 ENSURE_FUTURE_ALIVE(state, self)
1144 return Py_NewRef(self->fut_loop);
1145 }
1146
1147 static PyObject *
FutureObj_get_blocking(FutureObj * fut,void * Py_UNUSED (ignored))1148 FutureObj_get_blocking(FutureObj *fut, void *Py_UNUSED(ignored))
1149 {
1150 if (future_is_alive(fut) && fut->fut_blocking) {
1151 Py_RETURN_TRUE;
1152 }
1153 else {
1154 Py_RETURN_FALSE;
1155 }
1156 }
1157
1158 static int
FutureObj_set_blocking(FutureObj * fut,PyObject * val,void * Py_UNUSED (ignored))1159 FutureObj_set_blocking(FutureObj *fut, PyObject *val, void *Py_UNUSED(ignored))
1160 {
1161 if (future_ensure_alive(fut)) {
1162 return -1;
1163 }
1164 if (val == NULL) {
1165 PyErr_SetString(PyExc_AttributeError, "cannot delete attribute");
1166 return -1;
1167 }
1168
1169 int is_true = PyObject_IsTrue(val);
1170 if (is_true < 0) {
1171 return -1;
1172 }
1173 fut->fut_blocking = is_true;
1174 return 0;
1175 }
1176
1177 static PyObject *
FutureObj_get_log_traceback(FutureObj * fut,void * Py_UNUSED (ignored))1178 FutureObj_get_log_traceback(FutureObj *fut, void *Py_UNUSED(ignored))
1179 {
1180 asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut);
1181 ENSURE_FUTURE_ALIVE(state, fut)
1182 if (fut->fut_log_tb) {
1183 Py_RETURN_TRUE;
1184 }
1185 else {
1186 Py_RETURN_FALSE;
1187 }
1188 }
1189
1190 static int
FutureObj_set_log_traceback(FutureObj * fut,PyObject * val,void * Py_UNUSED (ignored))1191 FutureObj_set_log_traceback(FutureObj *fut, PyObject *val, void *Py_UNUSED(ignored))
1192 {
1193 if (val == NULL) {
1194 PyErr_SetString(PyExc_AttributeError, "cannot delete attribute");
1195 return -1;
1196 }
1197 int is_true = PyObject_IsTrue(val);
1198 if (is_true < 0) {
1199 return -1;
1200 }
1201 if (is_true) {
1202 PyErr_SetString(PyExc_ValueError,
1203 "_log_traceback can only be set to False");
1204 return -1;
1205 }
1206 fut->fut_log_tb = is_true;
1207 return 0;
1208 }
1209
1210 static PyObject *
FutureObj_get_loop(FutureObj * fut,void * Py_UNUSED (ignored))1211 FutureObj_get_loop(FutureObj *fut, void *Py_UNUSED(ignored))
1212 {
1213 if (!future_is_alive(fut)) {
1214 Py_RETURN_NONE;
1215 }
1216 return Py_NewRef(fut->fut_loop);
1217 }
1218
1219 static PyObject *
FutureObj_get_callbacks(FutureObj * fut,void * Py_UNUSED (ignored))1220 FutureObj_get_callbacks(FutureObj *fut, void *Py_UNUSED(ignored))
1221 {
1222 asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut);
1223 ENSURE_FUTURE_ALIVE(state, fut)
1224
1225 Py_ssize_t len = 0;
1226 if (fut->fut_callback0 != NULL) {
1227 len++;
1228 }
1229 if (fut->fut_callbacks != NULL) {
1230 len += PyList_GET_SIZE(fut->fut_callbacks);
1231 }
1232
1233 if (len == 0) {
1234 Py_RETURN_NONE;
1235 }
1236
1237 PyObject *callbacks = PyList_New(len);
1238 if (callbacks == NULL) {
1239 return NULL;
1240 }
1241
1242 Py_ssize_t i = 0;
1243 if (fut->fut_callback0 != NULL) {
1244 PyObject *tup0 = PyTuple_New(2);
1245 if (tup0 == NULL) {
1246 Py_DECREF(callbacks);
1247 return NULL;
1248 }
1249 PyTuple_SET_ITEM(tup0, 0, Py_NewRef(fut->fut_callback0));
1250 assert(fut->fut_context0 != NULL);
1251 PyTuple_SET_ITEM(tup0, 1, Py_NewRef(fut->fut_context0));
1252 PyList_SET_ITEM(callbacks, i, tup0);
1253 i++;
1254 }
1255
1256 if (fut->fut_callbacks != NULL) {
1257 for (Py_ssize_t j = 0; j < PyList_GET_SIZE(fut->fut_callbacks); j++) {
1258 PyObject *cb = PyList_GET_ITEM(fut->fut_callbacks, j);
1259 Py_INCREF(cb);
1260 PyList_SET_ITEM(callbacks, i, cb);
1261 i++;
1262 }
1263 }
1264
1265 return callbacks;
1266 }
1267
1268 static PyObject *
FutureObj_get_result(FutureObj * fut,void * Py_UNUSED (ignored))1269 FutureObj_get_result(FutureObj *fut, void *Py_UNUSED(ignored))
1270 {
1271 asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut);
1272 ENSURE_FUTURE_ALIVE(state, fut)
1273 if (fut->fut_result == NULL) {
1274 Py_RETURN_NONE;
1275 }
1276 return Py_NewRef(fut->fut_result);
1277 }
1278
1279 static PyObject *
FutureObj_get_exception(FutureObj * fut,void * Py_UNUSED (ignored))1280 FutureObj_get_exception(FutureObj *fut, void *Py_UNUSED(ignored))
1281 {
1282 asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut);
1283 ENSURE_FUTURE_ALIVE(state, fut)
1284 if (fut->fut_exception == NULL) {
1285 Py_RETURN_NONE;
1286 }
1287 return Py_NewRef(fut->fut_exception);
1288 }
1289
1290 static PyObject *
FutureObj_get_source_traceback(FutureObj * fut,void * Py_UNUSED (ignored))1291 FutureObj_get_source_traceback(FutureObj *fut, void *Py_UNUSED(ignored))
1292 {
1293 if (!future_is_alive(fut) || fut->fut_source_tb == NULL) {
1294 Py_RETURN_NONE;
1295 }
1296 return Py_NewRef(fut->fut_source_tb);
1297 }
1298
1299 static PyObject *
FutureObj_get_cancel_message(FutureObj * fut,void * Py_UNUSED (ignored))1300 FutureObj_get_cancel_message(FutureObj *fut, void *Py_UNUSED(ignored))
1301 {
1302 if (fut->fut_cancel_msg == NULL) {
1303 Py_RETURN_NONE;
1304 }
1305 return Py_NewRef(fut->fut_cancel_msg);
1306 }
1307
1308 static int
FutureObj_set_cancel_message(FutureObj * fut,PyObject * msg,void * Py_UNUSED (ignored))1309 FutureObj_set_cancel_message(FutureObj *fut, PyObject *msg,
1310 void *Py_UNUSED(ignored))
1311 {
1312 if (msg == NULL) {
1313 PyErr_SetString(PyExc_AttributeError, "cannot delete attribute");
1314 return -1;
1315 }
1316 Py_INCREF(msg);
1317 Py_XSETREF(fut->fut_cancel_msg, msg);
1318 return 0;
1319 }
1320
1321 static PyObject *
FutureObj_get_state(FutureObj * fut,void * Py_UNUSED (ignored))1322 FutureObj_get_state(FutureObj *fut, void *Py_UNUSED(ignored))
1323 {
1324 asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut);
1325 PyObject *ret = NULL;
1326
1327 ENSURE_FUTURE_ALIVE(state, fut)
1328
1329 switch (fut->fut_state) {
1330 case STATE_PENDING:
1331 ret = &_Py_ID(PENDING);
1332 break;
1333 case STATE_CANCELLED:
1334 ret = &_Py_ID(CANCELLED);
1335 break;
1336 case STATE_FINISHED:
1337 ret = &_Py_ID(FINISHED);
1338 break;
1339 default:
1340 assert (0);
1341 }
1342 assert(_Py_IsImmortalLoose(ret));
1343 return ret;
1344 }
1345
1346 static PyObject *
FutureObj_repr(FutureObj * fut)1347 FutureObj_repr(FutureObj *fut)
1348 {
1349 asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut);
1350 ENSURE_FUTURE_ALIVE(state, fut)
1351 return PyObject_CallOneArg(state->asyncio_future_repr_func, (PyObject *)fut);
1352 }
1353
1354 /*[clinic input]
1355 _asyncio.Future._make_cancelled_error
1356
1357 Create the CancelledError to raise if the Future is cancelled.
1358
1359 This should only be called once when handling a cancellation since
1360 it erases the context exception value.
1361 [clinic start generated code]*/
1362
1363 static PyObject *
_asyncio_Future__make_cancelled_error_impl(FutureObj * self)1364 _asyncio_Future__make_cancelled_error_impl(FutureObj *self)
1365 /*[clinic end generated code: output=a5df276f6c1213de input=ac6effe4ba795ecc]*/
1366 {
1367 asyncio_state *state = get_asyncio_state_by_def((PyObject *)self);
1368 return create_cancelled_error(state, self);
1369 }
1370
1371 static void
FutureObj_finalize(FutureObj * fut)1372 FutureObj_finalize(FutureObj *fut)
1373 {
1374 PyObject *context;
1375 PyObject *message = NULL;
1376 PyObject *func;
1377
1378 if (!fut->fut_log_tb) {
1379 return;
1380 }
1381 assert(fut->fut_exception != NULL);
1382 fut->fut_log_tb = 0;
1383
1384 /* Save the current exception, if any. */
1385 PyObject *exc = PyErr_GetRaisedException();
1386
1387 context = PyDict_New();
1388 if (context == NULL) {
1389 goto finally;
1390 }
1391
1392 message = PyUnicode_FromFormat(
1393 "%s exception was never retrieved", _PyType_Name(Py_TYPE(fut)));
1394 if (message == NULL) {
1395 goto finally;
1396 }
1397
1398 if (PyDict_SetItem(context, &_Py_ID(message), message) < 0 ||
1399 PyDict_SetItem(context, &_Py_ID(exception), fut->fut_exception) < 0 ||
1400 PyDict_SetItem(context, &_Py_ID(future), (PyObject*)fut) < 0) {
1401 goto finally;
1402 }
1403 if (fut->fut_source_tb != NULL) {
1404 if (PyDict_SetItem(context, &_Py_ID(source_traceback),
1405 fut->fut_source_tb) < 0) {
1406 goto finally;
1407 }
1408 }
1409
1410 func = PyObject_GetAttr(fut->fut_loop, &_Py_ID(call_exception_handler));
1411 if (func != NULL) {
1412 PyObject *res = PyObject_CallOneArg(func, context);
1413 if (res == NULL) {
1414 PyErr_WriteUnraisable(func);
1415 }
1416 else {
1417 Py_DECREF(res);
1418 }
1419 Py_DECREF(func);
1420 }
1421
1422 finally:
1423 Py_XDECREF(context);
1424 Py_XDECREF(message);
1425
1426 /* Restore the saved exception. */
1427 PyErr_SetRaisedException(exc);
1428 }
1429
1430 static PyMethodDef FutureType_methods[] = {
1431 _ASYNCIO_FUTURE_RESULT_METHODDEF
1432 _ASYNCIO_FUTURE_EXCEPTION_METHODDEF
1433 _ASYNCIO_FUTURE_SET_RESULT_METHODDEF
1434 _ASYNCIO_FUTURE_SET_EXCEPTION_METHODDEF
1435 _ASYNCIO_FUTURE_ADD_DONE_CALLBACK_METHODDEF
1436 _ASYNCIO_FUTURE_REMOVE_DONE_CALLBACK_METHODDEF
1437 _ASYNCIO_FUTURE_CANCEL_METHODDEF
1438 _ASYNCIO_FUTURE_CANCELLED_METHODDEF
1439 _ASYNCIO_FUTURE_DONE_METHODDEF
1440 _ASYNCIO_FUTURE_GET_LOOP_METHODDEF
1441 _ASYNCIO_FUTURE__MAKE_CANCELLED_ERROR_METHODDEF
1442 {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
1443 {NULL, NULL} /* Sentinel */
1444 };
1445
1446 #define FUTURE_COMMON_GETSETLIST \
1447 {"_state", (getter)FutureObj_get_state, NULL, NULL}, \
1448 {"_asyncio_future_blocking", (getter)FutureObj_get_blocking, \
1449 (setter)FutureObj_set_blocking, NULL}, \
1450 {"_loop", (getter)FutureObj_get_loop, NULL, NULL}, \
1451 {"_callbacks", (getter)FutureObj_get_callbacks, NULL, NULL}, \
1452 {"_result", (getter)FutureObj_get_result, NULL, NULL}, \
1453 {"_exception", (getter)FutureObj_get_exception, NULL, NULL}, \
1454 {"_log_traceback", (getter)FutureObj_get_log_traceback, \
1455 (setter)FutureObj_set_log_traceback, NULL}, \
1456 {"_source_traceback", (getter)FutureObj_get_source_traceback, \
1457 NULL, NULL}, \
1458 {"_cancel_message", (getter)FutureObj_get_cancel_message, \
1459 (setter)FutureObj_set_cancel_message, NULL},
1460
1461 static PyGetSetDef FutureType_getsetlist[] = {
1462 FUTURE_COMMON_GETSETLIST
1463 {NULL} /* Sentinel */
1464 };
1465
1466 static void FutureObj_dealloc(PyObject *self);
1467
1468 static PyType_Slot Future_slots[] = {
1469 {Py_tp_dealloc, FutureObj_dealloc},
1470 {Py_tp_repr, (reprfunc)FutureObj_repr},
1471 {Py_tp_doc, (void *)_asyncio_Future___init____doc__},
1472 {Py_tp_traverse, (traverseproc)FutureObj_traverse},
1473 {Py_tp_clear, (inquiry)FutureObj_clear},
1474 {Py_tp_iter, (getiterfunc)future_new_iter},
1475 {Py_tp_methods, FutureType_methods},
1476 {Py_tp_getset, FutureType_getsetlist},
1477 {Py_tp_init, (initproc)_asyncio_Future___init__},
1478 {Py_tp_new, PyType_GenericNew},
1479 {Py_tp_finalize, (destructor)FutureObj_finalize},
1480
1481 // async slots
1482 {Py_am_await, (unaryfunc)future_new_iter},
1483 {0, NULL},
1484 };
1485
1486 static PyType_Spec Future_spec = {
1487 .name = "_asyncio.Future",
1488 .basicsize = sizeof(FutureObj),
1489 .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE |
1490 Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_MANAGED_DICT |
1491 Py_TPFLAGS_MANAGED_WEAKREF),
1492 .slots = Future_slots,
1493 };
1494
1495 static void
FutureObj_dealloc(PyObject * self)1496 FutureObj_dealloc(PyObject *self)
1497 {
1498 FutureObj *fut = (FutureObj *)self;
1499
1500 if (PyObject_CallFinalizerFromDealloc(self) < 0) {
1501 // resurrected.
1502 return;
1503 }
1504
1505 PyTypeObject *tp = Py_TYPE(fut);
1506 PyObject_GC_UnTrack(self);
1507
1508 PyObject_ClearWeakRefs(self);
1509
1510 (void)FutureObj_clear(fut);
1511 tp->tp_free(fut);
1512 Py_DECREF(tp);
1513 }
1514
1515
1516 /*********************** Future Iterator **************************/
1517
1518 typedef struct futureiterobject {
1519 PyObject_HEAD
1520 FutureObj *future;
1521 } futureiterobject;
1522
1523
1524 static void
FutureIter_dealloc(futureiterobject * it)1525 FutureIter_dealloc(futureiterobject *it)
1526 {
1527 PyTypeObject *tp = Py_TYPE(it);
1528
1529 assert(_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE));
1530
1531 PyObject_GC_UnTrack(it);
1532 tp->tp_clear((PyObject *)it);
1533
1534 #ifndef Py_GIL_DISABLED
1535 // GH-115874: We can't use PyType_GetModuleByDef here as the type might have
1536 // already been cleared, which is also why we must check if ht_module != NULL.
1537 PyObject *module = ((PyHeapTypeObject*)tp)->ht_module;
1538 asyncio_state *state = NULL;
1539 if (module && _PyModule_GetDef(module) == &_asynciomodule) {
1540 state = get_asyncio_state(module);
1541 }
1542
1543 // TODO GH-121621: This should be moved to thread state as well.
1544 if (state && state->fi_freelist_len < FI_FREELIST_MAXLEN) {
1545 state->fi_freelist_len++;
1546 it->future = (FutureObj*) state->fi_freelist;
1547 state->fi_freelist = it;
1548 }
1549 else
1550 #endif
1551 {
1552 PyObject_GC_Del(it);
1553 Py_DECREF(tp);
1554 }
1555 }
1556
1557 static PySendResult
FutureIter_am_send(futureiterobject * it,PyObject * Py_UNUSED (arg),PyObject ** result)1558 FutureIter_am_send(futureiterobject *it,
1559 PyObject *Py_UNUSED(arg),
1560 PyObject **result)
1561 {
1562 /* arg is unused, see the comment on FutureIter_send for clarification */
1563
1564 PyObject *res;
1565 FutureObj *fut = it->future;
1566
1567 *result = NULL;
1568 if (fut == NULL) {
1569 return PYGEN_ERROR;
1570 }
1571
1572 if (fut->fut_state == STATE_PENDING) {
1573 if (!fut->fut_blocking) {
1574 fut->fut_blocking = 1;
1575 *result = Py_NewRef(fut);
1576 return PYGEN_NEXT;
1577 }
1578 PyErr_SetString(PyExc_RuntimeError,
1579 "await wasn't used with future");
1580 return PYGEN_ERROR;
1581 }
1582
1583 it->future = NULL;
1584 res = _asyncio_Future_result_impl(fut);
1585 if (res != NULL) {
1586 Py_DECREF(fut);
1587 *result = res;
1588 return PYGEN_RETURN;
1589 }
1590
1591 Py_DECREF(fut);
1592 return PYGEN_ERROR;
1593 }
1594
1595 static PyObject *
FutureIter_iternext(futureiterobject * it)1596 FutureIter_iternext(futureiterobject *it)
1597 {
1598 PyObject *result;
1599 switch (FutureIter_am_send(it, Py_None, &result)) {
1600 case PYGEN_RETURN:
1601 (void)_PyGen_SetStopIterationValue(result);
1602 Py_DECREF(result);
1603 return NULL;
1604 case PYGEN_NEXT:
1605 return result;
1606 case PYGEN_ERROR:
1607 return NULL;
1608 default:
1609 Py_UNREACHABLE();
1610 }
1611 }
1612
1613 static PyObject *
FutureIter_send(futureiterobject * self,PyObject * unused)1614 FutureIter_send(futureiterobject *self, PyObject *unused)
1615 {
1616 /* Future.__iter__ doesn't care about values that are pushed to the
1617 * generator, it just returns self.result().
1618 */
1619 return FutureIter_iternext(self);
1620 }
1621
1622 static PyObject *
FutureIter_throw(futureiterobject * self,PyObject * const * args,Py_ssize_t nargs)1623 FutureIter_throw(futureiterobject *self, PyObject *const *args, Py_ssize_t nargs)
1624 {
1625 PyObject *type, *val = NULL, *tb = NULL;
1626 if (!_PyArg_CheckPositional("throw", nargs, 1, 3)) {
1627 return NULL;
1628 }
1629 if (nargs > 1) {
1630 if (PyErr_WarnEx(PyExc_DeprecationWarning,
1631 "the (type, exc, tb) signature of throw() is deprecated, "
1632 "use the single-arg signature instead.",
1633 1) < 0) {
1634 return NULL;
1635 }
1636 }
1637
1638 type = args[0];
1639 if (nargs == 3) {
1640 val = args[1];
1641 tb = args[2];
1642 }
1643 else if (nargs == 2) {
1644 val = args[1];
1645 }
1646
1647 if (val == Py_None) {
1648 val = NULL;
1649 }
1650 if (tb == Py_None ) {
1651 tb = NULL;
1652 } else if (tb != NULL && !PyTraceBack_Check(tb)) {
1653 PyErr_SetString(PyExc_TypeError, "throw() third argument must be a traceback");
1654 return NULL;
1655 }
1656
1657 Py_INCREF(type);
1658 Py_XINCREF(val);
1659 Py_XINCREF(tb);
1660
1661 if (PyExceptionClass_Check(type)) {
1662 PyErr_NormalizeException(&type, &val, &tb);
1663 /* No need to call PyException_SetTraceback since we'll be calling
1664 PyErr_Restore for `type`, `val`, and `tb`. */
1665 } else if (PyExceptionInstance_Check(type)) {
1666 if (val) {
1667 PyErr_SetString(PyExc_TypeError,
1668 "instance exception may not have a separate value");
1669 goto fail;
1670 }
1671 val = type;
1672 type = PyExceptionInstance_Class(type);
1673 Py_INCREF(type);
1674 if (tb == NULL)
1675 tb = PyException_GetTraceback(val);
1676 } else {
1677 PyErr_SetString(PyExc_TypeError,
1678 "exceptions must be classes deriving BaseException or "
1679 "instances of such a class");
1680 goto fail;
1681 }
1682
1683 Py_CLEAR(self->future);
1684
1685 PyErr_Restore(type, val, tb);
1686
1687 return NULL;
1688
1689 fail:
1690 Py_DECREF(type);
1691 Py_XDECREF(val);
1692 Py_XDECREF(tb);
1693 return NULL;
1694 }
1695
1696 static int
FutureIter_clear(futureiterobject * it)1697 FutureIter_clear(futureiterobject *it)
1698 {
1699 Py_CLEAR(it->future);
1700 return 0;
1701 }
1702
1703 static PyObject *
FutureIter_close(futureiterobject * self,PyObject * arg)1704 FutureIter_close(futureiterobject *self, PyObject *arg)
1705 {
1706 (void)FutureIter_clear(self);
1707 Py_RETURN_NONE;
1708 }
1709
1710 static int
FutureIter_traverse(futureiterobject * it,visitproc visit,void * arg)1711 FutureIter_traverse(futureiterobject *it, visitproc visit, void *arg)
1712 {
1713 Py_VISIT(Py_TYPE(it));
1714 Py_VISIT(it->future);
1715 return 0;
1716 }
1717
1718 static PyMethodDef FutureIter_methods[] = {
1719 {"send", (PyCFunction)FutureIter_send, METH_O, NULL},
1720 {"throw", _PyCFunction_CAST(FutureIter_throw), METH_FASTCALL, NULL},
1721 {"close", (PyCFunction)FutureIter_close, METH_NOARGS, NULL},
1722 {NULL, NULL} /* Sentinel */
1723 };
1724
1725 static PyType_Slot FutureIter_slots[] = {
1726 {Py_tp_dealloc, (destructor)FutureIter_dealloc},
1727 {Py_tp_getattro, PyObject_GenericGetAttr},
1728 {Py_tp_traverse, (traverseproc)FutureIter_traverse},
1729 {Py_tp_clear, FutureIter_clear},
1730 {Py_tp_iter, PyObject_SelfIter},
1731 {Py_tp_iternext, (iternextfunc)FutureIter_iternext},
1732 {Py_tp_methods, FutureIter_methods},
1733
1734 // async methods
1735 {Py_am_send, (sendfunc)FutureIter_am_send},
1736 {0, NULL},
1737 };
1738
1739 static PyType_Spec FutureIter_spec = {
1740 .name = "_asyncio.FutureIter",
1741 .basicsize = sizeof(futureiterobject),
1742 .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
1743 Py_TPFLAGS_IMMUTABLETYPE),
1744 .slots = FutureIter_slots,
1745 };
1746
1747 static PyObject *
future_new_iter(PyObject * fut)1748 future_new_iter(PyObject *fut)
1749 {
1750 futureiterobject *it;
1751
1752 asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut);
1753 ENSURE_FUTURE_ALIVE(state, fut)
1754
1755 #ifndef Py_GIL_DISABLED
1756 if (state->fi_freelist_len) {
1757 state->fi_freelist_len--;
1758 it = state->fi_freelist;
1759 state->fi_freelist = (futureiterobject*) it->future;
1760 it->future = NULL;
1761 _Py_NewReference((PyObject*) it);
1762 }
1763 else
1764 #endif
1765 {
1766 it = PyObject_GC_New(futureiterobject, state->FutureIterType);
1767 if (it == NULL) {
1768 return NULL;
1769 }
1770 }
1771
1772 it->future = (FutureObj*)Py_NewRef(fut);
1773 PyObject_GC_Track(it);
1774 return (PyObject*)it;
1775 }
1776
1777
1778 /*********************** Task **************************/
1779
1780
1781 /*[clinic input]
1782 class _asyncio.Task "TaskObj *" "&Task_Type"
1783 [clinic start generated code]*/
1784 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=719dcef0fcc03b37]*/
1785
1786 static int task_call_step_soon(asyncio_state *state, TaskObj *, PyObject *);
1787 static PyObject * task_wakeup(TaskObj *, PyObject *);
1788 static PyObject * task_step(asyncio_state *, TaskObj *, PyObject *);
1789 static int task_eager_start(asyncio_state *state, TaskObj *task);
1790
1791 /* ----- Task._step wrapper */
1792
1793 static int
TaskStepMethWrapper_clear(TaskStepMethWrapper * o)1794 TaskStepMethWrapper_clear(TaskStepMethWrapper *o)
1795 {
1796 Py_CLEAR(o->sw_task);
1797 Py_CLEAR(o->sw_arg);
1798 return 0;
1799 }
1800
1801 static void
TaskStepMethWrapper_dealloc(TaskStepMethWrapper * o)1802 TaskStepMethWrapper_dealloc(TaskStepMethWrapper *o)
1803 {
1804 PyTypeObject *tp = Py_TYPE(o);
1805 PyObject_GC_UnTrack(o);
1806 (void)TaskStepMethWrapper_clear(o);
1807 Py_TYPE(o)->tp_free(o);
1808 Py_DECREF(tp);
1809 }
1810
1811 static PyObject *
TaskStepMethWrapper_call(TaskStepMethWrapper * o,PyObject * args,PyObject * kwds)1812 TaskStepMethWrapper_call(TaskStepMethWrapper *o,
1813 PyObject *args, PyObject *kwds)
1814 {
1815 if (kwds != NULL && PyDict_GET_SIZE(kwds) != 0) {
1816 PyErr_SetString(PyExc_TypeError, "function takes no keyword arguments");
1817 return NULL;
1818 }
1819 if (args != NULL && PyTuple_GET_SIZE(args) != 0) {
1820 PyErr_SetString(PyExc_TypeError, "function takes no positional arguments");
1821 return NULL;
1822 }
1823 asyncio_state *state = get_asyncio_state_by_def((PyObject *)o);
1824 return task_step(state, o->sw_task, o->sw_arg);
1825 }
1826
1827 static int
TaskStepMethWrapper_traverse(TaskStepMethWrapper * o,visitproc visit,void * arg)1828 TaskStepMethWrapper_traverse(TaskStepMethWrapper *o,
1829 visitproc visit, void *arg)
1830 {
1831 Py_VISIT(Py_TYPE(o));
1832 Py_VISIT(o->sw_task);
1833 Py_VISIT(o->sw_arg);
1834 return 0;
1835 }
1836
1837 static PyObject *
TaskStepMethWrapper_get___self__(TaskStepMethWrapper * o,void * Py_UNUSED (ignored))1838 TaskStepMethWrapper_get___self__(TaskStepMethWrapper *o, void *Py_UNUSED(ignored))
1839 {
1840 if (o->sw_task) {
1841 return Py_NewRef(o->sw_task);
1842 }
1843 Py_RETURN_NONE;
1844 }
1845
1846 static PyGetSetDef TaskStepMethWrapper_getsetlist[] = {
1847 {"__self__", (getter)TaskStepMethWrapper_get___self__, NULL, NULL},
1848 {NULL} /* Sentinel */
1849 };
1850
1851 static PyType_Slot TaskStepMethWrapper_slots[] = {
1852 {Py_tp_getset, TaskStepMethWrapper_getsetlist},
1853 {Py_tp_dealloc, (destructor)TaskStepMethWrapper_dealloc},
1854 {Py_tp_call, (ternaryfunc)TaskStepMethWrapper_call},
1855 {Py_tp_getattro, PyObject_GenericGetAttr},
1856 {Py_tp_traverse, (traverseproc)TaskStepMethWrapper_traverse},
1857 {Py_tp_clear, (inquiry)TaskStepMethWrapper_clear},
1858 {0, NULL},
1859 };
1860
1861 static PyType_Spec TaskStepMethWrapper_spec = {
1862 .name = "_asyncio.TaskStepMethWrapper",
1863 .basicsize = sizeof(TaskStepMethWrapper),
1864 .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
1865 Py_TPFLAGS_IMMUTABLETYPE),
1866 .slots = TaskStepMethWrapper_slots,
1867 };
1868
1869 static PyObject *
TaskStepMethWrapper_new(TaskObj * task,PyObject * arg)1870 TaskStepMethWrapper_new(TaskObj *task, PyObject *arg)
1871 {
1872 asyncio_state *state = get_asyncio_state_by_def((PyObject *)task);
1873 TaskStepMethWrapper *o;
1874 o = PyObject_GC_New(TaskStepMethWrapper, state->TaskStepMethWrapper_Type);
1875 if (o == NULL) {
1876 return NULL;
1877 }
1878
1879 o->sw_task = (TaskObj*)Py_NewRef(task);
1880 o->sw_arg = Py_XNewRef(arg);
1881
1882 PyObject_GC_Track(o);
1883 return (PyObject*) o;
1884 }
1885
1886 /* ----- Task._wakeup implementation */
1887
1888 static PyMethodDef TaskWakeupDef = {
1889 "task_wakeup",
1890 (PyCFunction)task_wakeup,
1891 METH_O,
1892 NULL
1893 };
1894
1895 /* ----- Task introspection helpers */
1896
1897 static int
register_task(asyncio_state * state,PyObject * task)1898 register_task(asyncio_state *state, PyObject *task)
1899 {
1900 PyObject *res = PyObject_CallMethodOneArg(state->scheduled_tasks,
1901 &_Py_ID(add), task);
1902 if (res == NULL) {
1903 return -1;
1904 }
1905 Py_DECREF(res);
1906 return 0;
1907 }
1908
1909 static int
register_eager_task(asyncio_state * state,PyObject * task)1910 register_eager_task(asyncio_state *state, PyObject *task)
1911 {
1912 return PySet_Add(state->eager_tasks, task);
1913 }
1914
1915 static int
unregister_task(asyncio_state * state,PyObject * task)1916 unregister_task(asyncio_state *state, PyObject *task)
1917 {
1918 PyObject *res = PyObject_CallMethodOneArg(state->scheduled_tasks,
1919 &_Py_ID(discard), task);
1920 if (res == NULL) {
1921 return -1;
1922 }
1923 Py_DECREF(res);
1924 return 0;
1925 }
1926
1927 static int
unregister_eager_task(asyncio_state * state,PyObject * task)1928 unregister_eager_task(asyncio_state *state, PyObject *task)
1929 {
1930 return PySet_Discard(state->eager_tasks, task);
1931 }
1932
1933 static int
enter_task(asyncio_state * state,PyObject * loop,PyObject * task)1934 enter_task(asyncio_state *state, PyObject *loop, PyObject *task)
1935 {
1936 PyObject *item;
1937 int res = PyDict_SetDefaultRef(state->current_tasks, loop, task, &item);
1938 if (res < 0) {
1939 return -1;
1940 }
1941 else if (res == 1) {
1942 PyErr_Format(
1943 PyExc_RuntimeError,
1944 "Cannot enter into task %R while another " \
1945 "task %R is being executed.",
1946 task, item, NULL);
1947 Py_DECREF(item);
1948 return -1;
1949 }
1950 Py_DECREF(item);
1951 return 0;
1952 }
1953
1954 static int
err_leave_task(PyObject * item,PyObject * task)1955 err_leave_task(PyObject *item, PyObject *task)
1956 {
1957 PyErr_Format(
1958 PyExc_RuntimeError,
1959 "Leaving task %R does not match the current task %R.",
1960 task, item);
1961 return -1;
1962 }
1963
1964 static int
leave_task_predicate(PyObject * item,void * task)1965 leave_task_predicate(PyObject *item, void *task)
1966 {
1967 if (item != task) {
1968 return err_leave_task(item, (PyObject *)task);
1969 }
1970 return 1;
1971 }
1972
1973 static int
leave_task(asyncio_state * state,PyObject * loop,PyObject * task)1974 leave_task(asyncio_state *state, PyObject *loop, PyObject *task)
1975 /*[clinic end generated code: output=0ebf6db4b858fb41 input=51296a46313d1ad8]*/
1976 {
1977 int res = _PyDict_DelItemIf(state->current_tasks, loop,
1978 leave_task_predicate, task);
1979 if (res == 0) {
1980 // task was not found
1981 return err_leave_task(Py_None, task);
1982 }
1983 return res;
1984 }
1985
1986 static PyObject *
swap_current_task_lock_held(PyDictObject * current_tasks,PyObject * loop,Py_hash_t hash,PyObject * task)1987 swap_current_task_lock_held(PyDictObject *current_tasks, PyObject *loop,
1988 Py_hash_t hash, PyObject *task)
1989 {
1990 PyObject *prev_task;
1991 if (_PyDict_GetItemRef_KnownHash_LockHeld(current_tasks, loop, hash, &prev_task) < 0) {
1992 return NULL;
1993 }
1994 if (_PyDict_SetItem_KnownHash_LockHeld(current_tasks, loop, task, hash) < 0) {
1995 Py_XDECREF(prev_task);
1996 return NULL;
1997 }
1998 if (prev_task == NULL) {
1999 Py_RETURN_NONE;
2000 }
2001 return prev_task;
2002 }
2003
2004 static PyObject *
swap_current_task(asyncio_state * state,PyObject * loop,PyObject * task)2005 swap_current_task(asyncio_state *state, PyObject *loop, PyObject *task)
2006 {
2007 PyObject *prev_task;
2008
2009 if (task == Py_None) {
2010 if (PyDict_Pop(state->current_tasks, loop, &prev_task) < 0) {
2011 return NULL;
2012 }
2013 if (prev_task == NULL) {
2014 Py_RETURN_NONE;
2015 }
2016 return prev_task;
2017 }
2018
2019 Py_hash_t hash = PyObject_Hash(loop);
2020 if (hash == -1) {
2021 return NULL;
2022 }
2023
2024 PyDictObject *current_tasks = (PyDictObject *)state->current_tasks;
2025 Py_BEGIN_CRITICAL_SECTION(current_tasks);
2026 prev_task = swap_current_task_lock_held(current_tasks, loop, hash, task);
2027 Py_END_CRITICAL_SECTION();
2028 return prev_task;
2029 }
2030
2031 /* ----- Task */
2032
2033 /*[clinic input]
2034 _asyncio.Task.__init__
2035
2036 coro: object
2037 *
2038 loop: object = None
2039 name: object = None
2040 context: object = None
2041 eager_start: bool = False
2042
2043 A coroutine wrapped in a Future.
2044 [clinic start generated code]*/
2045
2046 static int
_asyncio_Task___init___impl(TaskObj * self,PyObject * coro,PyObject * loop,PyObject * name,PyObject * context,int eager_start)2047 _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop,
2048 PyObject *name, PyObject *context,
2049 int eager_start)
2050 /*[clinic end generated code: output=7aced2d27836f1a1 input=18e3f113a51b829d]*/
2051 {
2052 if (future_init((FutureObj*)self, loop)) {
2053 return -1;
2054 }
2055
2056 asyncio_state *state = get_asyncio_state_by_def((PyObject *)self);
2057 int is_coro = is_coroutine(state, coro);
2058 if (is_coro == -1) {
2059 return -1;
2060 }
2061 if (is_coro == 0) {
2062 self->task_log_destroy_pending = 0;
2063 PyErr_Format(PyExc_TypeError,
2064 "a coroutine was expected, got %R",
2065 coro, NULL);
2066 return -1;
2067 }
2068
2069 if (context == Py_None) {
2070 Py_XSETREF(self->task_context, PyContext_CopyCurrent());
2071 if (self->task_context == NULL) {
2072 return -1;
2073 }
2074 } else {
2075 Py_XSETREF(self->task_context, Py_NewRef(context));
2076 }
2077
2078 Py_CLEAR(self->task_fut_waiter);
2079 self->task_must_cancel = 0;
2080 self->task_log_destroy_pending = 1;
2081 self->task_num_cancels_requested = 0;
2082 Py_INCREF(coro);
2083 Py_XSETREF(self->task_coro, coro);
2084
2085 if (name == Py_None) {
2086 // optimization: defer task name formatting
2087 // store the task counter as PyLong in the name
2088 // for deferred formatting in get_name
2089 #ifdef Py_GIL_DISABLED
2090 unsigned long long counter = _Py_atomic_add_uint64(&state->task_name_counter, 1) + 1;
2091 #else
2092 unsigned long long counter = ++state->task_name_counter;
2093 #endif
2094 name = PyLong_FromUnsignedLongLong(counter);
2095 } else if (!PyUnicode_CheckExact(name)) {
2096 name = PyObject_Str(name);
2097 } else {
2098 Py_INCREF(name);
2099 }
2100 Py_XSETREF(self->task_name, name);
2101 if (self->task_name == NULL) {
2102 return -1;
2103 }
2104
2105 if (eager_start) {
2106 PyObject *res = PyObject_CallMethodNoArgs(loop, &_Py_ID(is_running));
2107 if (res == NULL) {
2108 return -1;
2109 }
2110 int is_loop_running = Py_IsTrue(res);
2111 Py_DECREF(res);
2112 if (is_loop_running) {
2113 if (task_eager_start(state, self)) {
2114 return -1;
2115 }
2116 return 0;
2117 }
2118 }
2119
2120 if (task_call_step_soon(state, self, NULL)) {
2121 return -1;
2122 }
2123 return register_task(state, (PyObject*)self);
2124 }
2125
2126 static int
TaskObj_clear(TaskObj * task)2127 TaskObj_clear(TaskObj *task)
2128 {
2129 (void)FutureObj_clear((FutureObj*) task);
2130 Py_CLEAR(task->task_context);
2131 Py_CLEAR(task->task_coro);
2132 Py_CLEAR(task->task_name);
2133 Py_CLEAR(task->task_fut_waiter);
2134 return 0;
2135 }
2136
2137 static int
TaskObj_traverse(TaskObj * task,visitproc visit,void * arg)2138 TaskObj_traverse(TaskObj *task, visitproc visit, void *arg)
2139 {
2140 Py_VISIT(Py_TYPE(task));
2141 Py_VISIT(task->task_context);
2142 Py_VISIT(task->task_coro);
2143 Py_VISIT(task->task_name);
2144 Py_VISIT(task->task_fut_waiter);
2145 FutureObj *fut = (FutureObj *)task;
2146 Py_VISIT(fut->fut_loop);
2147 Py_VISIT(fut->fut_callback0);
2148 Py_VISIT(fut->fut_context0);
2149 Py_VISIT(fut->fut_callbacks);
2150 Py_VISIT(fut->fut_result);
2151 Py_VISIT(fut->fut_exception);
2152 Py_VISIT(fut->fut_exception_tb);
2153 Py_VISIT(fut->fut_source_tb);
2154 Py_VISIT(fut->fut_cancel_msg);
2155 Py_VISIT(fut->fut_cancelled_exc);
2156 PyObject_VisitManagedDict((PyObject *)fut, visit, arg);
2157 return 0;
2158 }
2159
2160 static PyObject *
TaskObj_get_log_destroy_pending(TaskObj * task,void * Py_UNUSED (ignored))2161 TaskObj_get_log_destroy_pending(TaskObj *task, void *Py_UNUSED(ignored))
2162 {
2163 if (task->task_log_destroy_pending) {
2164 Py_RETURN_TRUE;
2165 }
2166 else {
2167 Py_RETURN_FALSE;
2168 }
2169 }
2170
2171 static int
TaskObj_set_log_destroy_pending(TaskObj * task,PyObject * val,void * Py_UNUSED (ignored))2172 TaskObj_set_log_destroy_pending(TaskObj *task, PyObject *val, void *Py_UNUSED(ignored))
2173 {
2174 if (val == NULL) {
2175 PyErr_SetString(PyExc_AttributeError, "cannot delete attribute");
2176 return -1;
2177 }
2178 int is_true = PyObject_IsTrue(val);
2179 if (is_true < 0) {
2180 return -1;
2181 }
2182 task->task_log_destroy_pending = is_true;
2183 return 0;
2184 }
2185
2186 static PyObject *
TaskObj_get_must_cancel(TaskObj * task,void * Py_UNUSED (ignored))2187 TaskObj_get_must_cancel(TaskObj *task, void *Py_UNUSED(ignored))
2188 {
2189 if (task->task_must_cancel) {
2190 Py_RETURN_TRUE;
2191 }
2192 else {
2193 Py_RETURN_FALSE;
2194 }
2195 }
2196
2197 static PyObject *
TaskObj_get_coro(TaskObj * task,void * Py_UNUSED (ignored))2198 TaskObj_get_coro(TaskObj *task, void *Py_UNUSED(ignored))
2199 {
2200 if (task->task_coro) {
2201 return Py_NewRef(task->task_coro);
2202 }
2203
2204 Py_RETURN_NONE;
2205 }
2206
2207 static PyObject *
TaskObj_get_fut_waiter(TaskObj * task,void * Py_UNUSED (ignored))2208 TaskObj_get_fut_waiter(TaskObj *task, void *Py_UNUSED(ignored))
2209 {
2210 if (task->task_fut_waiter) {
2211 return Py_NewRef(task->task_fut_waiter);
2212 }
2213
2214 Py_RETURN_NONE;
2215 }
2216
2217 static PyObject *
TaskObj_repr(TaskObj * task)2218 TaskObj_repr(TaskObj *task)
2219 {
2220 asyncio_state *state = get_asyncio_state_by_def((PyObject *)task);
2221 return PyObject_CallOneArg(state->asyncio_task_repr_func,
2222 (PyObject *)task);
2223 }
2224
2225
2226 /*[clinic input]
2227 _asyncio.Task._make_cancelled_error
2228
2229 Create the CancelledError to raise if the Task is cancelled.
2230
2231 This should only be called once when handling a cancellation since
2232 it erases the context exception value.
2233 [clinic start generated code]*/
2234
2235 static PyObject *
_asyncio_Task__make_cancelled_error_impl(TaskObj * self)2236 _asyncio_Task__make_cancelled_error_impl(TaskObj *self)
2237 /*[clinic end generated code: output=55a819e8b4276fab input=52c0e32de8e2f840]*/
2238 {
2239 FutureObj *fut = (FutureObj*)self;
2240 return _asyncio_Future__make_cancelled_error_impl(fut);
2241 }
2242
2243
2244 /*[clinic input]
2245 _asyncio.Task.cancel
2246
2247 msg: object = None
2248
2249 Request that this task cancel itself.
2250
2251 This arranges for a CancelledError to be thrown into the
2252 wrapped coroutine on the next cycle through the event loop.
2253 The coroutine then has a chance to clean up or even deny
2254 the request using try/except/finally.
2255
2256 Unlike Future.cancel, this does not guarantee that the
2257 task will be cancelled: the exception might be caught and
2258 acted upon, delaying cancellation of the task or preventing
2259 cancellation completely. The task may also return a value or
2260 raise a different exception.
2261
2262 Immediately after this method is called, Task.cancelled() will
2263 not return True (unless the task was already cancelled). A
2264 task will be marked as cancelled when the wrapped coroutine
2265 terminates with a CancelledError exception (even if cancel()
2266 was not called).
2267
2268 This also increases the task's count of cancellation requests.
2269 [clinic start generated code]*/
2270
2271 static PyObject *
_asyncio_Task_cancel_impl(TaskObj * self,PyObject * msg)2272 _asyncio_Task_cancel_impl(TaskObj *self, PyObject *msg)
2273 /*[clinic end generated code: output=c66b60d41c74f9f1 input=7bb51bf25974c783]*/
2274 {
2275 self->task_log_tb = 0;
2276
2277 if (self->task_state != STATE_PENDING) {
2278 Py_RETURN_FALSE;
2279 }
2280
2281 self->task_num_cancels_requested += 1;
2282
2283 // These three lines are controversial. See discussion starting at
2284 // https://github.com/python/cpython/pull/31394#issuecomment-1053545331
2285 // and corresponding code in tasks.py.
2286 // if (self->task_num_cancels_requested > 1) {
2287 // Py_RETURN_FALSE;
2288 // }
2289
2290 if (self->task_fut_waiter) {
2291 PyObject *res;
2292 int is_true;
2293
2294 res = PyObject_CallMethodOneArg(self->task_fut_waiter,
2295 &_Py_ID(cancel), msg);
2296 if (res == NULL) {
2297 return NULL;
2298 }
2299
2300 is_true = PyObject_IsTrue(res);
2301 Py_DECREF(res);
2302 if (is_true < 0) {
2303 return NULL;
2304 }
2305
2306 if (is_true) {
2307 Py_RETURN_TRUE;
2308 }
2309 }
2310
2311 self->task_must_cancel = 1;
2312 Py_XINCREF(msg);
2313 Py_XSETREF(self->task_cancel_msg, msg);
2314 Py_RETURN_TRUE;
2315 }
2316
2317 /*[clinic input]
2318 _asyncio.Task.cancelling
2319
2320 Return the count of the task's cancellation requests.
2321
2322 This count is incremented when .cancel() is called
2323 and may be decremented using .uncancel().
2324 [clinic start generated code]*/
2325
2326 static PyObject *
_asyncio_Task_cancelling_impl(TaskObj * self)2327 _asyncio_Task_cancelling_impl(TaskObj *self)
2328 /*[clinic end generated code: output=803b3af96f917d7e input=b625224d310cbb17]*/
2329 /*[clinic end generated code]*/
2330 {
2331 return PyLong_FromLong(self->task_num_cancels_requested);
2332 }
2333
2334 /*[clinic input]
2335 _asyncio.Task.uncancel
2336
2337 Decrement the task's count of cancellation requests.
2338
2339 This should be used by tasks that catch CancelledError
2340 and wish to continue indefinitely until they are cancelled again.
2341
2342 Returns the remaining number of cancellation requests.
2343 [clinic start generated code]*/
2344
2345 static PyObject *
_asyncio_Task_uncancel_impl(TaskObj * self)2346 _asyncio_Task_uncancel_impl(TaskObj *self)
2347 /*[clinic end generated code: output=58184d236a817d3c input=68f81a4b90b46be2]*/
2348 /*[clinic end generated code]*/
2349 {
2350 if (self->task_num_cancels_requested > 0) {
2351 self->task_num_cancels_requested -= 1;
2352 if (self->task_num_cancels_requested == 0) {
2353 self->task_must_cancel = 0;
2354 }
2355 }
2356 return PyLong_FromLong(self->task_num_cancels_requested);
2357 }
2358
2359 /*[clinic input]
2360 _asyncio.Task.get_stack
2361
2362 cls: defining_class
2363 /
2364 *
2365 limit: object = None
2366
2367 Return the list of stack frames for this task's coroutine.
2368
2369 If the coroutine is not done, this returns the stack where it is
2370 suspended. If the coroutine has completed successfully or was
2371 cancelled, this returns an empty list. If the coroutine was
2372 terminated by an exception, this returns the list of traceback
2373 frames.
2374
2375 The frames are always ordered from oldest to newest.
2376
2377 The optional limit gives the maximum number of frames to
2378 return; by default all available frames are returned. Its
2379 meaning differs depending on whether a stack or a traceback is
2380 returned: the newest frames of a stack are returned, but the
2381 oldest frames of a traceback are returned. (This matches the
2382 behavior of the traceback module.)
2383
2384 For reasons beyond our control, only one stack frame is
2385 returned for a suspended coroutine.
2386 [clinic start generated code]*/
2387
2388 static PyObject *
_asyncio_Task_get_stack_impl(TaskObj * self,PyTypeObject * cls,PyObject * limit)2389 _asyncio_Task_get_stack_impl(TaskObj *self, PyTypeObject *cls,
2390 PyObject *limit)
2391 /*[clinic end generated code: output=6774dfc10d3857fa input=8e01c9b2618ae953]*/
2392 {
2393 asyncio_state *state = get_asyncio_state_by_cls(cls);
2394 PyObject *stack[] = {(PyObject *)self, limit};
2395 return PyObject_Vectorcall(state->asyncio_task_get_stack_func,
2396 stack, 2, NULL);
2397 }
2398
2399 /*[clinic input]
2400 _asyncio.Task.print_stack
2401
2402 cls: defining_class
2403 /
2404 *
2405 limit: object = None
2406 file: object = None
2407
2408 Print the stack or traceback for this task's coroutine.
2409
2410 This produces output similar to that of the traceback module,
2411 for the frames retrieved by get_stack(). The limit argument
2412 is passed to get_stack(). The file argument is an I/O stream
2413 to which the output is written; by default output is written
2414 to sys.stderr.
2415 [clinic start generated code]*/
2416
2417 static PyObject *
_asyncio_Task_print_stack_impl(TaskObj * self,PyTypeObject * cls,PyObject * limit,PyObject * file)2418 _asyncio_Task_print_stack_impl(TaskObj *self, PyTypeObject *cls,
2419 PyObject *limit, PyObject *file)
2420 /*[clinic end generated code: output=b38affe9289ec826 input=150b35ba2d3a7dee]*/
2421 {
2422 asyncio_state *state = get_asyncio_state_by_cls(cls);
2423 PyObject *stack[] = {(PyObject *)self, limit, file};
2424 return PyObject_Vectorcall(state->asyncio_task_print_stack_func,
2425 stack, 3, NULL);
2426 }
2427
2428 /*[clinic input]
2429 _asyncio.Task.set_result
2430
2431 result: object
2432 /
2433 [clinic start generated code]*/
2434
2435 static PyObject *
_asyncio_Task_set_result(TaskObj * self,PyObject * result)2436 _asyncio_Task_set_result(TaskObj *self, PyObject *result)
2437 /*[clinic end generated code: output=1dcae308bfcba318 input=9d1a00c07be41bab]*/
2438 {
2439 PyErr_SetString(PyExc_RuntimeError,
2440 "Task does not support set_result operation");
2441 return NULL;
2442 }
2443
2444 /*[clinic input]
2445 _asyncio.Task.set_exception
2446
2447 exception: object
2448 /
2449 [clinic start generated code]*/
2450
2451 static PyObject *
_asyncio_Task_set_exception(TaskObj * self,PyObject * exception)2452 _asyncio_Task_set_exception(TaskObj *self, PyObject *exception)
2453 /*[clinic end generated code: output=bc377fc28067303d input=9a8f65c83dcf893a]*/
2454 {
2455 PyErr_SetString(PyExc_RuntimeError,
2456 "Task does not support set_exception operation");
2457 return NULL;
2458 }
2459
2460 /*[clinic input]
2461 _asyncio.Task.get_coro
2462 [clinic start generated code]*/
2463
2464 static PyObject *
_asyncio_Task_get_coro_impl(TaskObj * self)2465 _asyncio_Task_get_coro_impl(TaskObj *self)
2466 /*[clinic end generated code: output=bcac27c8cc6c8073 input=d2e8606c42a7b403]*/
2467 {
2468 if (self->task_coro) {
2469 return Py_NewRef(self->task_coro);
2470 }
2471
2472 Py_RETURN_NONE;
2473 }
2474
2475 /*[clinic input]
2476 _asyncio.Task.get_context
2477 [clinic start generated code]*/
2478
2479 static PyObject *
_asyncio_Task_get_context_impl(TaskObj * self)2480 _asyncio_Task_get_context_impl(TaskObj *self)
2481 /*[clinic end generated code: output=6996f53d3dc01aef input=87c0b209b8fceeeb]*/
2482 {
2483 return Py_NewRef(self->task_context);
2484 }
2485
2486 /*[clinic input]
2487 _asyncio.Task.get_name
2488 [clinic start generated code]*/
2489
2490 static PyObject *
_asyncio_Task_get_name_impl(TaskObj * self)2491 _asyncio_Task_get_name_impl(TaskObj *self)
2492 /*[clinic end generated code: output=0ecf1570c3b37a8f input=a4a6595d12f4f0f8]*/
2493 {
2494 if (self->task_name) {
2495 if (PyLong_CheckExact(self->task_name)) {
2496 PyObject *name = PyUnicode_FromFormat("Task-%S", self->task_name);
2497 if (name == NULL) {
2498 return NULL;
2499 }
2500 Py_SETREF(self->task_name, name);
2501 }
2502 return Py_NewRef(self->task_name);
2503 }
2504
2505 Py_RETURN_NONE;
2506 }
2507
2508 /*[clinic input]
2509 _asyncio.Task.set_name
2510
2511 value: object
2512 /
2513 [clinic start generated code]*/
2514
2515 static PyObject *
_asyncio_Task_set_name(TaskObj * self,PyObject * value)2516 _asyncio_Task_set_name(TaskObj *self, PyObject *value)
2517 /*[clinic end generated code: output=138a8d51e32057d6 input=a8359b6e65f8fd31]*/
2518 {
2519 if (!PyUnicode_CheckExact(value)) {
2520 value = PyObject_Str(value);
2521 if (value == NULL) {
2522 return NULL;
2523 }
2524 } else {
2525 Py_INCREF(value);
2526 }
2527
2528 Py_XSETREF(self->task_name, value);
2529 Py_RETURN_NONE;
2530 }
2531
2532 static void
TaskObj_finalize(TaskObj * task)2533 TaskObj_finalize(TaskObj *task)
2534 {
2535 PyObject *context;
2536 PyObject *message = NULL;
2537 PyObject *func;
2538
2539 if (task->task_state != STATE_PENDING || !task->task_log_destroy_pending) {
2540 goto done;
2541 }
2542
2543 /* Save the current exception, if any. */
2544 PyObject *exc = PyErr_GetRaisedException();
2545
2546 context = PyDict_New();
2547 if (context == NULL) {
2548 goto finally;
2549 }
2550
2551 message = PyUnicode_FromString("Task was destroyed but it is pending!");
2552 if (message == NULL) {
2553 goto finally;
2554 }
2555
2556 if (PyDict_SetItem(context, &_Py_ID(message), message) < 0 ||
2557 PyDict_SetItem(context, &_Py_ID(task), (PyObject*)task) < 0)
2558 {
2559 goto finally;
2560 }
2561
2562 if (task->task_source_tb != NULL) {
2563 if (PyDict_SetItem(context, &_Py_ID(source_traceback),
2564 task->task_source_tb) < 0)
2565 {
2566 goto finally;
2567 }
2568 }
2569
2570 func = PyObject_GetAttr(task->task_loop, &_Py_ID(call_exception_handler));
2571 if (func != NULL) {
2572 PyObject *res = PyObject_CallOneArg(func, context);
2573 if (res == NULL) {
2574 PyErr_WriteUnraisable(func);
2575 }
2576 else {
2577 Py_DECREF(res);
2578 }
2579 Py_DECREF(func);
2580 }
2581
2582 finally:
2583 Py_XDECREF(context);
2584 Py_XDECREF(message);
2585
2586 /* Restore the saved exception. */
2587 PyErr_SetRaisedException(exc);
2588
2589 done:
2590 FutureObj_finalize((FutureObj*)task);
2591 }
2592
2593 static void TaskObj_dealloc(PyObject *); /* Needs Task_CheckExact */
2594
2595 static PyMethodDef TaskType_methods[] = {
2596 _ASYNCIO_FUTURE_RESULT_METHODDEF
2597 _ASYNCIO_FUTURE_EXCEPTION_METHODDEF
2598 _ASYNCIO_FUTURE_ADD_DONE_CALLBACK_METHODDEF
2599 _ASYNCIO_FUTURE_REMOVE_DONE_CALLBACK_METHODDEF
2600 _ASYNCIO_FUTURE_CANCELLED_METHODDEF
2601 _ASYNCIO_FUTURE_DONE_METHODDEF
2602 _ASYNCIO_TASK_SET_RESULT_METHODDEF
2603 _ASYNCIO_TASK_SET_EXCEPTION_METHODDEF
2604 _ASYNCIO_TASK_CANCEL_METHODDEF
2605 _ASYNCIO_TASK_CANCELLING_METHODDEF
2606 _ASYNCIO_TASK_UNCANCEL_METHODDEF
2607 _ASYNCIO_TASK_GET_STACK_METHODDEF
2608 _ASYNCIO_TASK_PRINT_STACK_METHODDEF
2609 _ASYNCIO_TASK__MAKE_CANCELLED_ERROR_METHODDEF
2610 _ASYNCIO_TASK_GET_NAME_METHODDEF
2611 _ASYNCIO_TASK_SET_NAME_METHODDEF
2612 _ASYNCIO_TASK_GET_CORO_METHODDEF
2613 _ASYNCIO_TASK_GET_CONTEXT_METHODDEF
2614 {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
2615 {NULL, NULL} /* Sentinel */
2616 };
2617
2618 static PyGetSetDef TaskType_getsetlist[] = {
2619 FUTURE_COMMON_GETSETLIST
2620 {"_log_destroy_pending", (getter)TaskObj_get_log_destroy_pending,
2621 (setter)TaskObj_set_log_destroy_pending, NULL},
2622 {"_must_cancel", (getter)TaskObj_get_must_cancel, NULL, NULL},
2623 {"_coro", (getter)TaskObj_get_coro, NULL, NULL},
2624 {"_fut_waiter", (getter)TaskObj_get_fut_waiter, NULL, NULL},
2625 {NULL} /* Sentinel */
2626 };
2627
2628 static PyType_Slot Task_slots[] = {
2629 {Py_tp_dealloc, TaskObj_dealloc},
2630 {Py_tp_repr, (reprfunc)TaskObj_repr},
2631 {Py_tp_doc, (void *)_asyncio_Task___init____doc__},
2632 {Py_tp_traverse, (traverseproc)TaskObj_traverse},
2633 {Py_tp_clear, (inquiry)TaskObj_clear},
2634 {Py_tp_iter, (getiterfunc)future_new_iter},
2635 {Py_tp_methods, TaskType_methods},
2636 {Py_tp_getset, TaskType_getsetlist},
2637 {Py_tp_init, (initproc)_asyncio_Task___init__},
2638 {Py_tp_new, PyType_GenericNew},
2639 {Py_tp_finalize, (destructor)TaskObj_finalize},
2640
2641 // async slots
2642 {Py_am_await, (unaryfunc)future_new_iter},
2643 {0, NULL},
2644 };
2645
2646 static PyType_Spec Task_spec = {
2647 .name = "_asyncio.Task",
2648 .basicsize = sizeof(TaskObj),
2649 .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE |
2650 Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_MANAGED_DICT |
2651 Py_TPFLAGS_MANAGED_WEAKREF),
2652 .slots = Task_slots,
2653 };
2654
2655 static void
TaskObj_dealloc(PyObject * self)2656 TaskObj_dealloc(PyObject *self)
2657 {
2658 TaskObj *task = (TaskObj *)self;
2659
2660 if (PyObject_CallFinalizerFromDealloc(self) < 0) {
2661 // resurrected.
2662 return;
2663 }
2664
2665 PyTypeObject *tp = Py_TYPE(task);
2666 PyObject_GC_UnTrack(self);
2667
2668 PyObject_ClearWeakRefs(self);
2669
2670 (void)TaskObj_clear(task);
2671 tp->tp_free(task);
2672 Py_DECREF(tp);
2673 }
2674
2675 static int
task_call_step_soon(asyncio_state * state,TaskObj * task,PyObject * arg)2676 task_call_step_soon(asyncio_state *state, TaskObj *task, PyObject *arg)
2677 {
2678 PyObject *cb = TaskStepMethWrapper_new(task, arg);
2679 if (cb == NULL) {
2680 return -1;
2681 }
2682
2683 // Beware: An evil call_soon could alter task_context.
2684 // See: https://github.com/python/cpython/issues/126080.
2685 PyObject *task_context = Py_NewRef(task->task_context);
2686 int ret = call_soon(state, task->task_loop, cb, NULL, task_context);
2687 Py_DECREF(task_context);
2688 Py_DECREF(cb);
2689 return ret;
2690 }
2691
2692 static PyObject *
task_set_error_soon(asyncio_state * state,TaskObj * task,PyObject * et,const char * format,...)2693 task_set_error_soon(asyncio_state *state, TaskObj *task, PyObject *et,
2694 const char *format, ...)
2695 {
2696 PyObject* msg;
2697
2698 va_list vargs;
2699 va_start(vargs, format);
2700 msg = PyUnicode_FromFormatV(format, vargs);
2701 va_end(vargs);
2702
2703 if (msg == NULL) {
2704 return NULL;
2705 }
2706
2707 PyObject *e = PyObject_CallOneArg(et, msg);
2708 Py_DECREF(msg);
2709 if (e == NULL) {
2710 return NULL;
2711 }
2712
2713 if (task_call_step_soon(state, task, e) == -1) {
2714 Py_DECREF(e);
2715 return NULL;
2716 }
2717
2718 Py_DECREF(e);
2719 Py_RETURN_NONE;
2720 }
2721
2722 static inline int
gen_status_from_result(PyObject ** result)2723 gen_status_from_result(PyObject **result)
2724 {
2725 if (*result != NULL) {
2726 return PYGEN_NEXT;
2727 }
2728 if (_PyGen_FetchStopIterationValue(result) == 0) {
2729 return PYGEN_RETURN;
2730 }
2731
2732 assert(PyErr_Occurred());
2733 return PYGEN_ERROR;
2734 }
2735
2736 static PyObject *
task_step_impl(asyncio_state * state,TaskObj * task,PyObject * exc)2737 task_step_impl(asyncio_state *state, TaskObj *task, PyObject *exc)
2738 {
2739 int clear_exc = 0;
2740 PyObject *result = NULL;
2741 PyObject *coro;
2742 PyObject *o;
2743
2744 if (task->task_state != STATE_PENDING) {
2745 PyErr_Format(state->asyncio_InvalidStateError,
2746 "_step(): already done: %R %R",
2747 task,
2748 exc ? exc : Py_None);
2749 goto fail;
2750 }
2751
2752 if (task->task_must_cancel) {
2753 assert(exc != Py_None);
2754
2755 if (!exc || !PyErr_GivenExceptionMatches(exc, state->asyncio_CancelledError)) {
2756 /* exc was not a CancelledError */
2757 exc = create_cancelled_error(state, (FutureObj*)task);
2758
2759 if (!exc) {
2760 goto fail;
2761 }
2762 clear_exc = 1;
2763 }
2764
2765 task->task_must_cancel = 0;
2766 }
2767
2768 Py_CLEAR(task->task_fut_waiter);
2769
2770 coro = task->task_coro;
2771 if (coro == NULL) {
2772 PyErr_SetString(PyExc_RuntimeError, "uninitialized Task object");
2773 if (clear_exc) {
2774 /* We created 'exc' during this call */
2775 Py_DECREF(exc);
2776 }
2777 return NULL;
2778 }
2779
2780 int gen_status = PYGEN_ERROR;
2781 if (exc == NULL) {
2782 gen_status = PyIter_Send(coro, Py_None, &result);
2783 }
2784 else {
2785 result = PyObject_CallMethodOneArg(coro, &_Py_ID(throw), exc);
2786 gen_status = gen_status_from_result(&result);
2787 if (clear_exc) {
2788 /* We created 'exc' during this call */
2789 Py_DECREF(exc);
2790 }
2791 }
2792
2793 if (gen_status == PYGEN_RETURN || gen_status == PYGEN_ERROR) {
2794 if (result != NULL) {
2795 /* The error is StopIteration and that means that
2796 the underlying coroutine has resolved */
2797
2798 PyObject *tmp;
2799 if (task->task_must_cancel) {
2800 // Task is cancelled right before coro stops.
2801 task->task_must_cancel = 0;
2802 tmp = future_cancel(state, (FutureObj*)task,
2803 task->task_cancel_msg);
2804 }
2805 else {
2806 tmp = future_set_result(state, (FutureObj*)task, result);
2807 }
2808
2809 Py_DECREF(result);
2810
2811 if (tmp == NULL) {
2812 return NULL;
2813 }
2814 Py_DECREF(tmp);
2815 Py_RETURN_NONE;
2816 }
2817
2818 if (PyErr_ExceptionMatches(state->asyncio_CancelledError)) {
2819 /* CancelledError */
2820
2821 PyObject *exc = PyErr_GetRaisedException();
2822 assert(exc);
2823
2824 FutureObj *fut = (FutureObj*)task;
2825 /* transfer ownership */
2826 fut->fut_cancelled_exc = exc;
2827
2828 return future_cancel(state, fut, NULL);
2829 }
2830
2831 /* Some other exception; pop it and call Task.set_exception() */
2832 PyObject *exc = PyErr_GetRaisedException();
2833 assert(exc);
2834
2835 o = future_set_exception(state, (FutureObj*)task, exc);
2836 if (!o) {
2837 /* An exception in Task.set_exception() */
2838 Py_DECREF(exc);
2839 goto fail;
2840 }
2841 assert(o == Py_None);
2842 Py_DECREF(o);
2843
2844 if (PyErr_GivenExceptionMatches(exc, PyExc_KeyboardInterrupt) ||
2845 PyErr_GivenExceptionMatches(exc, PyExc_SystemExit))
2846 {
2847 /* We've got a KeyboardInterrupt or a SystemError; re-raise it */
2848 PyErr_SetRaisedException(exc);
2849 goto fail;
2850 }
2851
2852 Py_DECREF(exc);
2853
2854 Py_RETURN_NONE;
2855 }
2856
2857 PyObject *ret = task_step_handle_result_impl(state, task, result);
2858 return ret;
2859
2860 fail:
2861 return NULL;
2862 }
2863
2864
2865 static PyObject *
task_step_handle_result_impl(asyncio_state * state,TaskObj * task,PyObject * result)2866 task_step_handle_result_impl(asyncio_state *state, TaskObj *task, PyObject *result)
2867 {
2868 int res;
2869 PyObject *o;
2870
2871 if (result == (PyObject*)task) {
2872 /* We have a task that wants to await on itself */
2873 goto self_await;
2874 }
2875
2876 /* Check if `result` is FutureObj or TaskObj (and not a subclass) */
2877 if (Future_CheckExact(state, result) || Task_CheckExact(state, result)) {
2878 PyObject *wrapper;
2879 PyObject *tmp;
2880 FutureObj *fut = (FutureObj*)result;
2881
2882 /* Check if `result` future is attached to a different loop */
2883 if (fut->fut_loop != task->task_loop) {
2884 goto different_loop;
2885 }
2886
2887 if (!fut->fut_blocking) {
2888 goto yield_insteadof_yf;
2889 }
2890
2891 fut->fut_blocking = 0;
2892
2893 /* result.add_done_callback(task._wakeup) */
2894 wrapper = PyCFunction_New(&TaskWakeupDef, (PyObject *)task);
2895 if (wrapper == NULL) {
2896 goto fail;
2897 }
2898 tmp = future_add_done_callback(state,
2899 (FutureObj*)result, wrapper, task->task_context);
2900 Py_DECREF(wrapper);
2901 if (tmp == NULL) {
2902 goto fail;
2903 }
2904 Py_DECREF(tmp);
2905
2906 /* task._fut_waiter = result */
2907 task->task_fut_waiter = result; /* no incref is necessary */
2908
2909 if (task->task_must_cancel) {
2910 PyObject *r;
2911 int is_true;
2912
2913 // Beware: An evil `__getattribute__` could
2914 // prematurely delete task->task_cancel_msg before the
2915 // task is cancelled, thereby causing a UAF crash.
2916 //
2917 // See https://github.com/python/cpython/issues/126138
2918 PyObject *task_cancel_msg = Py_NewRef(task->task_cancel_msg);
2919 r = PyObject_CallMethodOneArg(result, &_Py_ID(cancel),
2920 task_cancel_msg);
2921 Py_DECREF(task_cancel_msg);
2922
2923 if (r == NULL) {
2924 return NULL;
2925 }
2926 is_true = PyObject_IsTrue(r);
2927 Py_DECREF(r);
2928 if (is_true < 0) {
2929 return NULL;
2930 }
2931 else if (is_true) {
2932 task->task_must_cancel = 0;
2933 }
2934 }
2935
2936 Py_RETURN_NONE;
2937 }
2938
2939 /* Check if `result` is None */
2940 if (result == Py_None) {
2941 /* Bare yield relinquishes control for one event loop iteration. */
2942 if (task_call_step_soon(state, task, NULL)) {
2943 goto fail;
2944 }
2945 return result;
2946 }
2947
2948 /* Check if `result` is a Future-compatible object */
2949 if (PyObject_GetOptionalAttr(result, &_Py_ID(_asyncio_future_blocking), &o) < 0) {
2950 goto fail;
2951 }
2952 if (o != NULL && o != Py_None) {
2953 /* `result` is a Future-compatible object */
2954 PyObject *wrapper;
2955 PyObject *tmp;
2956
2957 int blocking = PyObject_IsTrue(o);
2958 Py_DECREF(o);
2959 if (blocking < 0) {
2960 goto fail;
2961 }
2962
2963 /* Check if `result` future is attached to a different loop */
2964 PyObject *oloop = get_future_loop(state, result);
2965 if (oloop == NULL) {
2966 goto fail;
2967 }
2968 if (oloop != task->task_loop) {
2969 Py_DECREF(oloop);
2970 goto different_loop;
2971 }
2972 Py_DECREF(oloop);
2973
2974 if (!blocking) {
2975 goto yield_insteadof_yf;
2976 }
2977
2978 /* result._asyncio_future_blocking = False */
2979 if (PyObject_SetAttr(
2980 result, &_Py_ID(_asyncio_future_blocking), Py_False) == -1) {
2981 goto fail;
2982 }
2983
2984 wrapper = PyCFunction_New(&TaskWakeupDef, (PyObject *)task);
2985 if (wrapper == NULL) {
2986 goto fail;
2987 }
2988
2989 /* result.add_done_callback(task._wakeup) */
2990 PyObject *add_cb = PyObject_GetAttr(
2991 result, &_Py_ID(add_done_callback));
2992 if (add_cb == NULL) {
2993 Py_DECREF(wrapper);
2994 goto fail;
2995 }
2996 PyObject *stack[2];
2997 stack[0] = wrapper;
2998 stack[1] = (PyObject *)task->task_context;
2999 EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_API, add_cb);
3000 tmp = PyObject_Vectorcall(add_cb, stack, 1, state->context_kwname);
3001 Py_DECREF(add_cb);
3002 Py_DECREF(wrapper);
3003 if (tmp == NULL) {
3004 goto fail;
3005 }
3006 Py_DECREF(tmp);
3007
3008 /* task._fut_waiter = result */
3009 task->task_fut_waiter = result; /* no incref is necessary */
3010
3011 if (task->task_must_cancel) {
3012 PyObject *r;
3013 int is_true;
3014
3015 // Beware: An evil `__getattribute__` could
3016 // prematurely delete task->task_cancel_msg before the
3017 // task is cancelled, thereby causing a UAF crash.
3018 //
3019 // See https://github.com/python/cpython/issues/126138
3020 PyObject *task_cancel_msg = Py_NewRef(task->task_cancel_msg);
3021 r = PyObject_CallMethodOneArg(result, &_Py_ID(cancel),
3022 task_cancel_msg);
3023 Py_DECREF(task_cancel_msg);
3024
3025 if (r == NULL) {
3026 return NULL;
3027 }
3028 is_true = PyObject_IsTrue(r);
3029 Py_DECREF(r);
3030 if (is_true < 0) {
3031 return NULL;
3032 }
3033 else if (is_true) {
3034 task->task_must_cancel = 0;
3035 }
3036 }
3037
3038 Py_RETURN_NONE;
3039 }
3040
3041 Py_XDECREF(o);
3042 /* Check if `result` is a generator */
3043 res = PyObject_IsInstance(result, (PyObject*)&PyGen_Type);
3044 if (res < 0) {
3045 goto fail;
3046 }
3047 if (res) {
3048 /* `result` is a generator */
3049 o = task_set_error_soon(
3050 state, task, PyExc_RuntimeError,
3051 "yield was used instead of yield from for "
3052 "generator in task %R with %R", task, result);
3053 Py_DECREF(result);
3054 return o;
3055 }
3056
3057 /* The `result` is none of the above */
3058 o = task_set_error_soon(
3059 state, task, PyExc_RuntimeError, "Task got bad yield: %R", result);
3060 Py_DECREF(result);
3061 return o;
3062
3063 self_await:
3064 o = task_set_error_soon(
3065 state, task, PyExc_RuntimeError,
3066 "Task cannot await on itself: %R", task);
3067 Py_DECREF(result);
3068 return o;
3069
3070 yield_insteadof_yf:
3071 o = task_set_error_soon(
3072 state, task, PyExc_RuntimeError,
3073 "yield was used instead of yield from "
3074 "in task %R with %R",
3075 task, result);
3076 Py_DECREF(result);
3077 return o;
3078
3079 different_loop:
3080 o = task_set_error_soon(
3081 state, task, PyExc_RuntimeError,
3082 "Task %R got Future %R attached to a different loop",
3083 task, result);
3084 Py_DECREF(result);
3085 return o;
3086
3087 fail:
3088 Py_XDECREF(result);
3089 return NULL;
3090 }
3091
3092 static PyObject *
task_step(asyncio_state * state,TaskObj * task,PyObject * exc)3093 task_step(asyncio_state *state, TaskObj *task, PyObject *exc)
3094 {
3095 PyObject *res;
3096
3097 if (enter_task(state, task->task_loop, (PyObject*)task) < 0) {
3098 return NULL;
3099 }
3100
3101 res = task_step_impl(state, task, exc);
3102
3103 if (res == NULL) {
3104 PyObject *exc = PyErr_GetRaisedException();
3105 leave_task(state, task->task_loop, (PyObject*)task);
3106 _PyErr_ChainExceptions1(exc);
3107 return NULL;
3108 }
3109 else {
3110 if (leave_task(state, task->task_loop, (PyObject*)task) < 0) {
3111 Py_DECREF(res);
3112 return NULL;
3113 }
3114 else {
3115 return res;
3116 }
3117 }
3118 }
3119
3120 static int
task_eager_start(asyncio_state * state,TaskObj * task)3121 task_eager_start(asyncio_state *state, TaskObj *task)
3122 {
3123 assert(task != NULL);
3124 PyObject *prevtask = swap_current_task(state, task->task_loop, (PyObject *)task);
3125 if (prevtask == NULL) {
3126 return -1;
3127 }
3128
3129 if (register_eager_task(state, (PyObject *)task) == -1) {
3130 Py_DECREF(prevtask);
3131 return -1;
3132 }
3133
3134 if (PyContext_Enter(task->task_context) == -1) {
3135 Py_DECREF(prevtask);
3136 return -1;
3137 }
3138
3139 int retval = 0;
3140
3141 PyObject *stepres = task_step_impl(state, task, NULL);
3142 if (stepres == NULL) {
3143 PyObject *exc = PyErr_GetRaisedException();
3144 _PyErr_ChainExceptions1(exc);
3145 retval = -1;
3146 } else {
3147 Py_DECREF(stepres);
3148 }
3149
3150 PyObject *curtask = swap_current_task(state, task->task_loop, prevtask);
3151 Py_DECREF(prevtask);
3152 if (curtask == NULL) {
3153 retval = -1;
3154 } else {
3155 assert(curtask == (PyObject *)task);
3156 Py_DECREF(curtask);
3157 }
3158
3159 if (unregister_eager_task(state, (PyObject *)task) == -1) {
3160 retval = -1;
3161 }
3162
3163 if (PyContext_Exit(task->task_context) == -1) {
3164 retval = -1;
3165 }
3166
3167 if (task->task_state == STATE_PENDING) {
3168 if (register_task(state, (PyObject *)task) == -1) {
3169 retval = -1;
3170 }
3171 } else {
3172 // This seems to really help performance on pyperformance benchmarks
3173 Py_CLEAR(task->task_coro);
3174 }
3175
3176 return retval;
3177 }
3178
3179 static PyObject *
task_wakeup(TaskObj * task,PyObject * o)3180 task_wakeup(TaskObj *task, PyObject *o)
3181 {
3182 PyObject *result;
3183 assert(o);
3184
3185 asyncio_state *state = get_asyncio_state_by_def((PyObject *)task);
3186 if (Future_CheckExact(state, o) || Task_CheckExact(state, o)) {
3187 PyObject *fut_result = NULL;
3188 int res = future_get_result(state, (FutureObj*)o, &fut_result);
3189
3190 switch(res) {
3191 case -1:
3192 assert(fut_result == NULL);
3193 break; /* exception raised */
3194 case 0:
3195 Py_DECREF(fut_result);
3196 return task_step(state, task, NULL);
3197 default:
3198 assert(res == 1);
3199 result = task_step(state, task, fut_result);
3200 Py_DECREF(fut_result);
3201 return result;
3202 }
3203 }
3204 else {
3205 PyObject *fut_result = PyObject_CallMethod(o, "result", NULL);
3206 if (fut_result != NULL) {
3207 Py_DECREF(fut_result);
3208 return task_step(state, task, NULL);
3209 }
3210 /* exception raised */
3211 }
3212
3213 PyObject *exc = PyErr_GetRaisedException();
3214 assert(exc);
3215
3216 result = task_step(state, task, exc);
3217
3218 Py_DECREF(exc);
3219
3220 return result;
3221 }
3222
3223
3224 /*********************** Functions **************************/
3225
3226
3227 /*[clinic input]
3228 _asyncio._get_running_loop
3229
3230 Return the running event loop or None.
3231
3232 This is a low-level function intended to be used by event loops.
3233 This function is thread-specific.
3234
3235 [clinic start generated code]*/
3236
3237 static PyObject *
_asyncio__get_running_loop_impl(PyObject * module)3238 _asyncio__get_running_loop_impl(PyObject *module)
3239 /*[clinic end generated code: output=b4390af721411a0a input=0a21627e25a4bd43]*/
3240 {
3241 _PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET();
3242 PyObject *loop = Py_XNewRef(ts->asyncio_running_loop);
3243 if (loop == NULL) {
3244 /* There's no currently running event loop */
3245 Py_RETURN_NONE;
3246 }
3247 return loop;
3248 }
3249
3250 /*[clinic input]
3251 _asyncio._set_running_loop
3252 loop: 'O'
3253 /
3254
3255 Set the running event loop.
3256
3257 This is a low-level function intended to be used by event loops.
3258 This function is thread-specific.
3259 [clinic start generated code]*/
3260
3261 static PyObject *
_asyncio__set_running_loop(PyObject * module,PyObject * loop)3262 _asyncio__set_running_loop(PyObject *module, PyObject *loop)
3263 /*[clinic end generated code: output=ae56bf7a28ca189a input=4c9720233d606604]*/
3264 {
3265 _PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET();
3266 if (loop == Py_None) {
3267 loop = NULL;
3268 }
3269 Py_XSETREF(ts->asyncio_running_loop, Py_XNewRef(loop));
3270 Py_RETURN_NONE;
3271 }
3272
3273 /*[clinic input]
3274 _asyncio.get_event_loop
3275
3276 Return an asyncio event loop.
3277
3278 When called from a coroutine or a callback (e.g. scheduled with
3279 call_soon or similar API), this function will always return the
3280 running event loop.
3281
3282 If there is no running event loop set, the function will return
3283 the result of `get_event_loop_policy().get_event_loop()` call.
3284 [clinic start generated code]*/
3285
3286 static PyObject *
_asyncio_get_event_loop_impl(PyObject * module)3287 _asyncio_get_event_loop_impl(PyObject *module)
3288 /*[clinic end generated code: output=2a2d8b2f824c648b input=9364bf2916c8655d]*/
3289 {
3290 asyncio_state *state = get_asyncio_state(module);
3291 return get_event_loop(state);
3292 }
3293
3294 /*[clinic input]
3295 _asyncio.get_running_loop
3296
3297 Return the running event loop. Raise a RuntimeError if there is none.
3298
3299 This function is thread-specific.
3300 [clinic start generated code]*/
3301
3302 static PyObject *
_asyncio_get_running_loop_impl(PyObject * module)3303 _asyncio_get_running_loop_impl(PyObject *module)
3304 /*[clinic end generated code: output=c247b5f9e529530e input=2a3bf02ba39f173d]*/
3305 {
3306 PyObject *loop;
3307 _PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET();
3308 loop = Py_XNewRef(ts->asyncio_running_loop);
3309 if (loop == NULL) {
3310 /* There's no currently running event loop */
3311 PyErr_SetString(
3312 PyExc_RuntimeError, "no running event loop");
3313 return NULL;
3314 }
3315 return loop;
3316 }
3317
3318 /*[clinic input]
3319 _asyncio._register_task
3320
3321 task: object
3322
3323 Register a new task in asyncio as executed by loop.
3324
3325 Returns None.
3326 [clinic start generated code]*/
3327
3328 static PyObject *
_asyncio__register_task_impl(PyObject * module,PyObject * task)3329 _asyncio__register_task_impl(PyObject *module, PyObject *task)
3330 /*[clinic end generated code: output=8672dadd69a7d4e2 input=21075aaea14dfbad]*/
3331 {
3332 asyncio_state *state = get_asyncio_state(module);
3333 if (register_task(state, task) < 0) {
3334 return NULL;
3335 }
3336 Py_RETURN_NONE;
3337 }
3338
3339 /*[clinic input]
3340 _asyncio._register_eager_task
3341
3342 task: object
3343
3344 Register a new task in asyncio as executed by loop.
3345
3346 Returns None.
3347 [clinic start generated code]*/
3348
3349 static PyObject *
_asyncio__register_eager_task_impl(PyObject * module,PyObject * task)3350 _asyncio__register_eager_task_impl(PyObject *module, PyObject *task)
3351 /*[clinic end generated code: output=dfe1d45367c73f1a input=237f684683398c51]*/
3352 {
3353 asyncio_state *state = get_asyncio_state(module);
3354 if (register_eager_task(state, task) < 0) {
3355 return NULL;
3356 }
3357 Py_RETURN_NONE;
3358 }
3359
3360
3361 /*[clinic input]
3362 _asyncio._unregister_task
3363
3364 task: object
3365
3366 Unregister a task.
3367
3368 Returns None.
3369 [clinic start generated code]*/
3370
3371 static PyObject *
_asyncio__unregister_task_impl(PyObject * module,PyObject * task)3372 _asyncio__unregister_task_impl(PyObject *module, PyObject *task)
3373 /*[clinic end generated code: output=6e5585706d568a46 input=28fb98c3975f7bdc]*/
3374 {
3375 asyncio_state *state = get_asyncio_state(module);
3376 if (unregister_task(state, task) < 0) {
3377 return NULL;
3378 }
3379 Py_RETURN_NONE;
3380 }
3381
3382 /*[clinic input]
3383 _asyncio._unregister_eager_task
3384
3385 task: object
3386
3387 Unregister a task.
3388
3389 Returns None.
3390 [clinic start generated code]*/
3391
3392 static PyObject *
_asyncio__unregister_eager_task_impl(PyObject * module,PyObject * task)3393 _asyncio__unregister_eager_task_impl(PyObject *module, PyObject *task)
3394 /*[clinic end generated code: output=a426922bd07f23d1 input=9d07401ef14ee048]*/
3395 {
3396 asyncio_state *state = get_asyncio_state(module);
3397 if (unregister_eager_task(state, task) < 0) {
3398 return NULL;
3399 }
3400 Py_RETURN_NONE;
3401 }
3402
3403
3404 /*[clinic input]
3405 _asyncio._enter_task
3406
3407 loop: object
3408 task: object
3409
3410 Enter into task execution or resume suspended task.
3411
3412 Task belongs to loop.
3413
3414 Returns None.
3415 [clinic start generated code]*/
3416
3417 static PyObject *
_asyncio__enter_task_impl(PyObject * module,PyObject * loop,PyObject * task)3418 _asyncio__enter_task_impl(PyObject *module, PyObject *loop, PyObject *task)
3419 /*[clinic end generated code: output=a22611c858035b73 input=de1b06dca70d8737]*/
3420 {
3421 asyncio_state *state = get_asyncio_state(module);
3422 if (enter_task(state, loop, task) < 0) {
3423 return NULL;
3424 }
3425 Py_RETURN_NONE;
3426 }
3427
3428
3429 /*[clinic input]
3430 _asyncio._leave_task
3431
3432 loop: object
3433 task: object
3434
3435 Leave task execution or suspend a task.
3436
3437 Task belongs to loop.
3438
3439 Returns None.
3440 [clinic start generated code]*/
3441
3442 static PyObject *
_asyncio__leave_task_impl(PyObject * module,PyObject * loop,PyObject * task)3443 _asyncio__leave_task_impl(PyObject *module, PyObject *loop, PyObject *task)
3444 /*[clinic end generated code: output=0ebf6db4b858fb41 input=51296a46313d1ad8]*/
3445 {
3446 asyncio_state *state = get_asyncio_state(module);
3447 if (leave_task(state, loop, task) < 0) {
3448 return NULL;
3449 }
3450 Py_RETURN_NONE;
3451 }
3452
3453
3454 /*[clinic input]
3455 _asyncio._swap_current_task
3456
3457 loop: object
3458 task: object
3459
3460 Temporarily swap in the supplied task and return the original one (or None).
3461
3462 This is intended for use during eager coroutine execution.
3463
3464 [clinic start generated code]*/
3465
3466 static PyObject *
_asyncio__swap_current_task_impl(PyObject * module,PyObject * loop,PyObject * task)3467 _asyncio__swap_current_task_impl(PyObject *module, PyObject *loop,
3468 PyObject *task)
3469 /*[clinic end generated code: output=9f88de958df74c7e input=c9c72208d3d38b6c]*/
3470 {
3471 return swap_current_task(get_asyncio_state(module), loop, task);
3472 }
3473
3474
3475 /*[clinic input]
3476 _asyncio.current_task
3477
3478 loop: object = None
3479
3480 Return a currently executed task.
3481
3482 [clinic start generated code]*/
3483
3484 static PyObject *
_asyncio_current_task_impl(PyObject * module,PyObject * loop)3485 _asyncio_current_task_impl(PyObject *module, PyObject *loop)
3486 /*[clinic end generated code: output=fe15ac331a7f981a input=58910f61a5627112]*/
3487 {
3488 PyObject *ret;
3489 asyncio_state *state = get_asyncio_state(module);
3490
3491 if (loop == Py_None) {
3492 loop = _asyncio_get_running_loop_impl(module);
3493 if (loop == NULL) {
3494 return NULL;
3495 }
3496 } else {
3497 Py_INCREF(loop);
3498 }
3499
3500 int rc = PyDict_GetItemRef(state->current_tasks, loop, &ret);
3501 Py_DECREF(loop);
3502 if (rc == 0) {
3503 Py_RETURN_NONE;
3504 }
3505 return ret;
3506 }
3507
3508
3509 /*********************** Module **************************/
3510
3511
3512 static void
module_free_freelists(asyncio_state * state)3513 module_free_freelists(asyncio_state *state)
3514 {
3515 #ifndef Py_GIL_DISABLED
3516 PyObject *next;
3517 PyObject *current;
3518
3519 next = (PyObject*) state->fi_freelist;
3520 while (next != NULL) {
3521 assert(state->fi_freelist_len > 0);
3522 state->fi_freelist_len--;
3523
3524 current = next;
3525 next = (PyObject*) ((futureiterobject*) current)->future;
3526 PyObject_GC_Del(current);
3527 }
3528 assert(state->fi_freelist_len == 0);
3529 state->fi_freelist = NULL;
3530 #endif
3531 }
3532
3533 static int
module_traverse(PyObject * mod,visitproc visit,void * arg)3534 module_traverse(PyObject *mod, visitproc visit, void *arg)
3535 {
3536 asyncio_state *state = get_asyncio_state(mod);
3537
3538 Py_VISIT(state->FutureIterType);
3539 Py_VISIT(state->TaskStepMethWrapper_Type);
3540 Py_VISIT(state->FutureType);
3541 Py_VISIT(state->TaskType);
3542
3543 Py_VISIT(state->asyncio_mod);
3544 Py_VISIT(state->traceback_extract_stack);
3545 Py_VISIT(state->asyncio_future_repr_func);
3546 Py_VISIT(state->asyncio_get_event_loop_policy);
3547 Py_VISIT(state->asyncio_iscoroutine_func);
3548 Py_VISIT(state->asyncio_task_get_stack_func);
3549 Py_VISIT(state->asyncio_task_print_stack_func);
3550 Py_VISIT(state->asyncio_task_repr_func);
3551 Py_VISIT(state->asyncio_InvalidStateError);
3552 Py_VISIT(state->asyncio_CancelledError);
3553
3554 Py_VISIT(state->scheduled_tasks);
3555 Py_VISIT(state->eager_tasks);
3556 Py_VISIT(state->current_tasks);
3557 Py_VISIT(state->iscoroutine_typecache);
3558
3559 Py_VISIT(state->context_kwname);
3560 return 0;
3561 }
3562
3563 static int
module_clear(PyObject * mod)3564 module_clear(PyObject *mod)
3565 {
3566 asyncio_state *state = get_asyncio_state(mod);
3567
3568 Py_CLEAR(state->FutureIterType);
3569 Py_CLEAR(state->TaskStepMethWrapper_Type);
3570 Py_CLEAR(state->FutureType);
3571 Py_CLEAR(state->TaskType);
3572
3573 Py_CLEAR(state->asyncio_mod);
3574 Py_CLEAR(state->traceback_extract_stack);
3575 Py_CLEAR(state->asyncio_future_repr_func);
3576 Py_CLEAR(state->asyncio_get_event_loop_policy);
3577 Py_CLEAR(state->asyncio_iscoroutine_func);
3578 Py_CLEAR(state->asyncio_task_get_stack_func);
3579 Py_CLEAR(state->asyncio_task_print_stack_func);
3580 Py_CLEAR(state->asyncio_task_repr_func);
3581 Py_CLEAR(state->asyncio_InvalidStateError);
3582 Py_CLEAR(state->asyncio_CancelledError);
3583
3584 Py_CLEAR(state->scheduled_tasks);
3585 Py_CLEAR(state->eager_tasks);
3586 Py_CLEAR(state->current_tasks);
3587 Py_CLEAR(state->iscoroutine_typecache);
3588
3589 Py_CLEAR(state->context_kwname);
3590
3591 module_free_freelists(state);
3592
3593 return 0;
3594 }
3595
3596 static void
module_free(void * mod)3597 module_free(void *mod)
3598 {
3599 (void)module_clear((PyObject *)mod);
3600 }
3601
3602 static int
module_init(asyncio_state * state)3603 module_init(asyncio_state *state)
3604 {
3605 PyObject *module = NULL;
3606
3607 state->asyncio_mod = PyImport_ImportModule("asyncio");
3608 if (state->asyncio_mod == NULL) {
3609 goto fail;
3610 }
3611
3612 state->current_tasks = PyDict_New();
3613 if (state->current_tasks == NULL) {
3614 goto fail;
3615 }
3616
3617 state->iscoroutine_typecache = PySet_New(NULL);
3618 if (state->iscoroutine_typecache == NULL) {
3619 goto fail;
3620 }
3621
3622
3623 state->context_kwname = Py_BuildValue("(s)", "context");
3624 if (state->context_kwname == NULL) {
3625 goto fail;
3626 }
3627
3628 #define WITH_MOD(NAME) \
3629 Py_CLEAR(module); \
3630 module = PyImport_ImportModule(NAME); \
3631 if (module == NULL) { \
3632 goto fail; \
3633 }
3634
3635 #define GET_MOD_ATTR(VAR, NAME) \
3636 VAR = PyObject_GetAttrString(module, NAME); \
3637 if (VAR == NULL) { \
3638 goto fail; \
3639 }
3640
3641 WITH_MOD("asyncio.events")
3642 GET_MOD_ATTR(state->asyncio_get_event_loop_policy, "get_event_loop_policy")
3643
3644 WITH_MOD("asyncio.base_futures")
3645 GET_MOD_ATTR(state->asyncio_future_repr_func, "_future_repr")
3646
3647 WITH_MOD("asyncio.exceptions")
3648 GET_MOD_ATTR(state->asyncio_InvalidStateError, "InvalidStateError")
3649 GET_MOD_ATTR(state->asyncio_CancelledError, "CancelledError")
3650
3651 WITH_MOD("asyncio.base_tasks")
3652 GET_MOD_ATTR(state->asyncio_task_repr_func, "_task_repr")
3653 GET_MOD_ATTR(state->asyncio_task_get_stack_func, "_task_get_stack")
3654 GET_MOD_ATTR(state->asyncio_task_print_stack_func, "_task_print_stack")
3655
3656 WITH_MOD("asyncio.coroutines")
3657 GET_MOD_ATTR(state->asyncio_iscoroutine_func, "iscoroutine")
3658
3659 WITH_MOD("traceback")
3660 GET_MOD_ATTR(state->traceback_extract_stack, "extract_stack")
3661
3662 PyObject *weak_set;
3663 WITH_MOD("weakref")
3664 GET_MOD_ATTR(weak_set, "WeakSet");
3665 state->scheduled_tasks = PyObject_CallNoArgs(weak_set);
3666 Py_CLEAR(weak_set);
3667 if (state->scheduled_tasks == NULL) {
3668 goto fail;
3669 }
3670
3671 state->eager_tasks = PySet_New(NULL);
3672 if (state->eager_tasks == NULL) {
3673 goto fail;
3674 }
3675
3676 Py_DECREF(module);
3677 return 0;
3678
3679 fail:
3680 Py_CLEAR(module);
3681 return -1;
3682
3683 #undef WITH_MOD
3684 #undef GET_MOD_ATTR
3685 }
3686
3687 PyDoc_STRVAR(module_doc, "Accelerator module for asyncio");
3688
3689 static PyMethodDef asyncio_methods[] = {
3690 _ASYNCIO_CURRENT_TASK_METHODDEF
3691 _ASYNCIO_GET_EVENT_LOOP_METHODDEF
3692 _ASYNCIO_GET_RUNNING_LOOP_METHODDEF
3693 _ASYNCIO__GET_RUNNING_LOOP_METHODDEF
3694 _ASYNCIO__SET_RUNNING_LOOP_METHODDEF
3695 _ASYNCIO__REGISTER_TASK_METHODDEF
3696 _ASYNCIO__REGISTER_EAGER_TASK_METHODDEF
3697 _ASYNCIO__UNREGISTER_TASK_METHODDEF
3698 _ASYNCIO__UNREGISTER_EAGER_TASK_METHODDEF
3699 _ASYNCIO__ENTER_TASK_METHODDEF
3700 _ASYNCIO__LEAVE_TASK_METHODDEF
3701 _ASYNCIO__SWAP_CURRENT_TASK_METHODDEF
3702 {NULL, NULL}
3703 };
3704
3705 static int
module_exec(PyObject * mod)3706 module_exec(PyObject *mod)
3707 {
3708 asyncio_state *state = get_asyncio_state(mod);
3709
3710 #define CREATE_TYPE(m, tp, spec, base) \
3711 do { \
3712 tp = (PyTypeObject *)PyType_FromMetaclass(NULL, m, spec, \
3713 (PyObject *)base); \
3714 if (tp == NULL) { \
3715 return -1; \
3716 } \
3717 } while (0)
3718
3719 CREATE_TYPE(mod, state->TaskStepMethWrapper_Type, &TaskStepMethWrapper_spec, NULL);
3720 CREATE_TYPE(mod, state->FutureIterType, &FutureIter_spec, NULL);
3721 CREATE_TYPE(mod, state->FutureType, &Future_spec, NULL);
3722 CREATE_TYPE(mod, state->TaskType, &Task_spec, state->FutureType);
3723
3724 #undef CREATE_TYPE
3725
3726 if (PyModule_AddType(mod, state->FutureType) < 0) {
3727 return -1;
3728 }
3729
3730 if (PyModule_AddType(mod, state->TaskType) < 0) {
3731 return -1;
3732 }
3733 // Must be done after types are added to avoid a circular dependency
3734 if (module_init(state) < 0) {
3735 return -1;
3736 }
3737
3738 if (PyModule_AddObjectRef(mod, "_scheduled_tasks", state->scheduled_tasks) < 0) {
3739 return -1;
3740 }
3741
3742 if (PyModule_AddObjectRef(mod, "_eager_tasks", state->eager_tasks) < 0) {
3743 return -1;
3744 }
3745
3746 if (PyModule_AddObjectRef(mod, "_current_tasks", state->current_tasks) < 0) {
3747 return -1;
3748 }
3749
3750
3751 return 0;
3752 }
3753
3754 static struct PyModuleDef_Slot module_slots[] = {
3755 {Py_mod_exec, module_exec},
3756 {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
3757 {Py_mod_gil, Py_MOD_GIL_NOT_USED},
3758 {0, NULL},
3759 };
3760
3761 static struct PyModuleDef _asynciomodule = {
3762 .m_base = PyModuleDef_HEAD_INIT,
3763 .m_name = "_asyncio",
3764 .m_doc = module_doc,
3765 .m_size = sizeof(asyncio_state),
3766 .m_methods = asyncio_methods,
3767 .m_slots = module_slots,
3768 .m_traverse = module_traverse,
3769 .m_clear = module_clear,
3770 .m_free = (freefunc)module_free,
3771 };
3772
3773 PyMODINIT_FUNC
PyInit__asyncio(void)3774 PyInit__asyncio(void)
3775 {
3776 return PyModuleDef_Init(&_asynciomodule);
3777 }
3778