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