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