• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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