blob: 37298cc46492a2108372b50b1acfdbdef2244acd [file] [log] [blame]
INADA Naoki9e4e38e2016-10-09 14:44:47 +09001#include "Python.h"
2#include "structmember.h"
3
4
5/* identifiers used from some functions */
6_Py_IDENTIFIER(call_soon);
7
8
INADA Naoki9f2ce252016-10-15 15:39:19 +09009/* State of the _asyncio module */
INADA Naoki9e4e38e2016-10-09 14:44:47 +090010static PyObject *traceback_extract_stack;
11static PyObject *asyncio_get_event_loop;
12static PyObject *asyncio_repr_info_func;
13static PyObject *asyncio_InvalidStateError;
14static PyObject *asyncio_CancelledError;
15
16
17/* Get FutureIter from Future */
18static PyObject* new_future_iter(PyObject *fut);
19
20
INADA Naoki9e4e38e2016-10-09 14:44:47 +090021typedef enum {
22 STATE_PENDING,
23 STATE_CANCELLED,
24 STATE_FINISHED
25} fut_state;
26
27
28typedef struct {
29 PyObject_HEAD
30 PyObject *fut_loop;
31 PyObject *fut_callbacks;
32 PyObject *fut_exception;
33 PyObject *fut_result;
34 PyObject *fut_source_tb;
35 fut_state fut_state;
36 int fut_log_tb;
37 int fut_blocking;
38 PyObject *dict;
39 PyObject *fut_weakreflist;
40} FutureObj;
41
42
43static int
44_schedule_callbacks(FutureObj *fut)
45{
46 Py_ssize_t len;
47 PyObject* iters;
48 int i;
49
50 if (fut->fut_callbacks == NULL) {
51 PyErr_SetString(PyExc_RuntimeError, "NULL callbacks");
52 return -1;
53 }
54
55 len = PyList_GET_SIZE(fut->fut_callbacks);
56 if (len == 0) {
57 return 0;
58 }
59
60 iters = PyList_GetSlice(fut->fut_callbacks, 0, len);
61 if (iters == NULL) {
62 return -1;
63 }
64 if (PyList_SetSlice(fut->fut_callbacks, 0, len, NULL) < 0) {
65 Py_DECREF(iters);
66 return -1;
67 }
68
69 for (i = 0; i < len; i++) {
70 PyObject *handle = NULL;
71 PyObject *cb = PyList_GET_ITEM(iters, i);
72
73 handle = _PyObject_CallMethodId(
74 fut->fut_loop, &PyId_call_soon, "OO", cb, fut, NULL);
75
76 if (handle == NULL) {
77 Py_DECREF(iters);
78 return -1;
79 }
80 else {
81 Py_DECREF(handle);
82 }
83 }
84
85 Py_DECREF(iters);
86 return 0;
87}
88
89static int
90FutureObj_init(FutureObj *fut, PyObject *args, PyObject *kwds)
91{
92 static char *kwlist[] = {"loop", NULL};
93 PyObject *loop = NULL;
94 PyObject *res = NULL;
95 _Py_IDENTIFIER(get_debug);
96
INADA Naoki9e4e38e2016-10-09 14:44:47 +090097 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|$O", kwlist, &loop)) {
98 return -1;
99 }
100 if (loop == NULL || loop == Py_None) {
101 loop = PyObject_CallObject(asyncio_get_event_loop, NULL);
102 if (loop == NULL) {
103 return -1;
104 }
105 }
106 else {
107 Py_INCREF(loop);
108 }
109 Py_CLEAR(fut->fut_loop);
110 fut->fut_loop = loop;
111
112 res = _PyObject_CallMethodId(fut->fut_loop, &PyId_get_debug, "()", NULL);
113 if (res == NULL) {
114 return -1;
115 }
116 if (PyObject_IsTrue(res)) {
117 Py_CLEAR(res);
118 fut->fut_source_tb = PyObject_CallObject(traceback_extract_stack, NULL);
119 if (fut->fut_source_tb == NULL) {
120 return -1;
121 }
122 }
123 else {
124 Py_CLEAR(res);
125 }
126
127 fut->fut_callbacks = PyList_New(0);
128 if (fut->fut_callbacks == NULL) {
129 return -1;
130 }
131 return 0;
132}
133
134static int
135FutureObj_clear(FutureObj *fut)
136{
137 Py_CLEAR(fut->fut_loop);
138 Py_CLEAR(fut->fut_callbacks);
139 Py_CLEAR(fut->fut_result);
140 Py_CLEAR(fut->fut_exception);
141 Py_CLEAR(fut->fut_source_tb);
142 Py_CLEAR(fut->dict);
143 return 0;
144}
145
146static int
147FutureObj_traverse(FutureObj *fut, visitproc visit, void *arg)
148{
149 Py_VISIT(fut->fut_loop);
150 Py_VISIT(fut->fut_callbacks);
151 Py_VISIT(fut->fut_result);
152 Py_VISIT(fut->fut_exception);
153 Py_VISIT(fut->fut_source_tb);
154 Py_VISIT(fut->dict);
155 return 0;
156}
157
158PyDoc_STRVAR(pydoc_result,
159 "Return the result this future represents.\n"
160 "\n"
161 "If the future has been cancelled, raises CancelledError. If the\n"
162 "future's result isn't yet available, raises InvalidStateError. If\n"
163 "the future is done and has an exception set, this exception is raised."
164);
165
166static PyObject *
167FutureObj_result(FutureObj *fut, PyObject *arg)
168{
169 if (fut->fut_state == STATE_CANCELLED) {
170 PyErr_SetString(asyncio_CancelledError, "");
171 return NULL;
172 }
173
174 if (fut->fut_state != STATE_FINISHED) {
175 PyErr_SetString(asyncio_InvalidStateError, "Result is not ready.");
176 return NULL;
177 }
178
179 fut->fut_log_tb = 0;
180 if (fut->fut_exception != NULL) {
181 PyObject *type = NULL;
182 type = PyExceptionInstance_Class(fut->fut_exception);
183 PyErr_SetObject(type, fut->fut_exception);
184 return NULL;
185 }
186
187 Py_INCREF(fut->fut_result);
188 return fut->fut_result;
189}
190
191PyDoc_STRVAR(pydoc_exception,
192 "Return the exception that was set on this future.\n"
193 "\n"
194 "The exception (or None if no exception was set) is returned only if\n"
195 "the future is done. If the future has been cancelled, raises\n"
196 "CancelledError. If the future isn't done yet, raises\n"
197 "InvalidStateError."
198);
199
200static PyObject *
201FutureObj_exception(FutureObj *fut, PyObject *arg)
202{
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900203 if (fut->fut_state == STATE_CANCELLED) {
204 PyErr_SetString(asyncio_CancelledError, "");
205 return NULL;
206 }
207
208 if (fut->fut_state != STATE_FINISHED) {
209 PyErr_SetString(asyncio_InvalidStateError, "Result is not ready.");
210 return NULL;
211 }
212
213 if (fut->fut_exception != NULL) {
214 fut->fut_log_tb = 0;
215 Py_INCREF(fut->fut_exception);
216 return fut->fut_exception;
217 }
218
219 Py_RETURN_NONE;
220}
221
222PyDoc_STRVAR(pydoc_set_result,
223 "Mark the future done and set its result.\n"
224 "\n"
225 "If the future is already done when this method is called, raises\n"
226 "InvalidStateError."
227);
228
229static PyObject *
230FutureObj_set_result(FutureObj *fut, PyObject *res)
231{
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900232 if (fut->fut_state != STATE_PENDING) {
233 PyErr_SetString(asyncio_InvalidStateError, "invalid state");
234 return NULL;
235 }
236
237 Py_INCREF(res);
238 fut->fut_result = res;
239 fut->fut_state = STATE_FINISHED;
240
241 if (_schedule_callbacks(fut) == -1) {
242 return NULL;
243 }
244 Py_RETURN_NONE;
245}
246
247PyDoc_STRVAR(pydoc_set_exception,
248 "Mark the future done and set an exception.\n"
249 "\n"
250 "If the future is already done when this method is called, raises\n"
251 "InvalidStateError."
252);
253
254static PyObject *
255FutureObj_set_exception(FutureObj *fut, PyObject *exc)
256{
257 PyObject *exc_val = NULL;
258
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900259 if (fut->fut_state != STATE_PENDING) {
260 PyErr_SetString(asyncio_InvalidStateError, "invalid state");
261 return NULL;
262 }
263
264 if (PyExceptionClass_Check(exc)) {
265 exc_val = PyObject_CallObject(exc, NULL);
266 if (exc_val == NULL) {
267 return NULL;
268 }
269 }
270 else {
271 exc_val = exc;
272 Py_INCREF(exc_val);
273 }
274 if (!PyExceptionInstance_Check(exc_val)) {
275 Py_DECREF(exc_val);
276 PyErr_SetString(PyExc_TypeError, "invalid exception object");
277 return NULL;
278 }
279 if ((PyObject*)Py_TYPE(exc_val) == PyExc_StopIteration) {
280 Py_DECREF(exc_val);
281 PyErr_SetString(PyExc_TypeError,
282 "StopIteration interacts badly with generators "
283 "and cannot be raised into a Future");
284 return NULL;
285 }
286
287 fut->fut_exception = exc_val;
288 fut->fut_state = STATE_FINISHED;
289
290 if (_schedule_callbacks(fut) == -1) {
291 return NULL;
292 }
293
294 fut->fut_log_tb = 1;
295 Py_RETURN_NONE;
296}
297
298PyDoc_STRVAR(pydoc_add_done_callback,
299 "Add a callback to be run when the future becomes done.\n"
300 "\n"
301 "The callback is called with a single argument - the future object. If\n"
302 "the future is already done when this is called, the callback is\n"
303 "scheduled with call_soon.";
304);
305
306static PyObject *
307FutureObj_add_done_callback(FutureObj *fut, PyObject *arg)
308{
309 if (fut->fut_state != STATE_PENDING) {
310 PyObject *handle = _PyObject_CallMethodId(
311 fut->fut_loop, &PyId_call_soon, "OO", arg, fut, NULL);
312
313 if (handle == NULL) {
314 return NULL;
315 }
316 else {
317 Py_DECREF(handle);
318 }
319 }
320 else {
321 int err = PyList_Append(fut->fut_callbacks, arg);
322 if (err != 0) {
323 return NULL;
324 }
325 }
326 Py_RETURN_NONE;
327}
328
329PyDoc_STRVAR(pydoc_remove_done_callback,
330 "Remove all instances of a callback from the \"call when done\" list.\n"
331 "\n"
332 "Returns the number of callbacks removed."
333);
334
335static PyObject *
336FutureObj_remove_done_callback(FutureObj *fut, PyObject *arg)
337{
338 PyObject *newlist;
339 Py_ssize_t len, i, j=0;
340
341 len = PyList_GET_SIZE(fut->fut_callbacks);
342 if (len == 0) {
343 return PyLong_FromSsize_t(0);
344 }
345
346 newlist = PyList_New(len);
347 if (newlist == NULL) {
348 return NULL;
349 }
350
351 for (i = 0; i < len; i++) {
352 int ret;
353 PyObject *item = PyList_GET_ITEM(fut->fut_callbacks, i);
354
355 if ((ret = PyObject_RichCompareBool(arg, item, Py_EQ)) < 0) {
356 goto fail;
357 }
358 if (ret == 0) {
359 Py_INCREF(item);
360 PyList_SET_ITEM(newlist, j, item);
361 j++;
362 }
363 }
364
365 if (PyList_SetSlice(newlist, j, len, NULL) < 0) {
366 goto fail;
367 }
368 if (PyList_SetSlice(fut->fut_callbacks, 0, len, newlist) < 0) {
369 goto fail;
370 }
371 Py_DECREF(newlist);
372 return PyLong_FromSsize_t(len - j);
373
374fail:
375 Py_DECREF(newlist);
376 return NULL;
377}
378
379PyDoc_STRVAR(pydoc_cancel,
380 "Cancel the future and schedule callbacks.\n"
381 "\n"
382 "If the future is already done or cancelled, return False. Otherwise,\n"
383 "change the future's state to cancelled, schedule the callbacks and\n"
384 "return True."
385);
386
387static PyObject *
388FutureObj_cancel(FutureObj *fut, PyObject *arg)
389{
390 if (fut->fut_state != STATE_PENDING) {
391 Py_RETURN_FALSE;
392 }
393 fut->fut_state = STATE_CANCELLED;
394
395 if (_schedule_callbacks(fut) == -1) {
396 return NULL;
397 }
398
399 Py_RETURN_TRUE;
400}
401
402PyDoc_STRVAR(pydoc_cancelled, "Return True if the future was cancelled.");
403
404static PyObject *
405FutureObj_cancelled(FutureObj *fut, PyObject *arg)
406{
407 if (fut->fut_state == STATE_CANCELLED) {
408 Py_RETURN_TRUE;
409 }
410 else {
411 Py_RETURN_FALSE;
412 }
413}
414
415PyDoc_STRVAR(pydoc_done,
416 "Return True if the future is done.\n"
417 "\n"
418 "Done means either that a result / exception are available, or that the\n"
419 "future was cancelled."
420);
421
422static PyObject *
423FutureObj_done(FutureObj *fut, PyObject *arg)
424{
425 if (fut->fut_state == STATE_PENDING) {
426 Py_RETURN_FALSE;
427 }
428 else {
429 Py_RETURN_TRUE;
430 }
431}
432
433static PyObject *
434FutureObj_get_blocking(FutureObj *fut)
435{
436 if (fut->fut_blocking) {
437 Py_RETURN_TRUE;
438 }
439 else {
440 Py_RETURN_FALSE;
441 }
442}
443
444static int
445FutureObj_set_blocking(FutureObj *fut, PyObject *val)
446{
447 int is_true = PyObject_IsTrue(val);
448 if (is_true < 0) {
449 return -1;
450 }
451 fut->fut_blocking = is_true;
452 return 0;
453}
454
455static PyObject *
456FutureObj_get_log_traceback(FutureObj *fut)
457{
458 if (fut->fut_log_tb) {
459 Py_RETURN_TRUE;
460 }
461 else {
462 Py_RETURN_FALSE;
463 }
464}
465
466static PyObject *
467FutureObj_get_loop(FutureObj *fut)
468{
469 if (fut->fut_loop == NULL) {
470 Py_RETURN_NONE;
471 }
472 Py_INCREF(fut->fut_loop);
473 return fut->fut_loop;
474}
475
476static PyObject *
477FutureObj_get_callbacks(FutureObj *fut)
478{
479 if (fut->fut_callbacks == NULL) {
480 Py_RETURN_NONE;
481 }
482 Py_INCREF(fut->fut_callbacks);
483 return fut->fut_callbacks;
484}
485
486static PyObject *
487FutureObj_get_result(FutureObj *fut)
488{
489 if (fut->fut_result == NULL) {
490 Py_RETURN_NONE;
491 }
492 Py_INCREF(fut->fut_result);
493 return fut->fut_result;
494}
495
496static PyObject *
497FutureObj_get_exception(FutureObj *fut)
498{
499 if (fut->fut_exception == NULL) {
500 Py_RETURN_NONE;
501 }
502 Py_INCREF(fut->fut_exception);
503 return fut->fut_exception;
504}
505
506static PyObject *
507FutureObj_get_source_traceback(FutureObj *fut)
508{
509 if (fut->fut_source_tb == NULL) {
510 Py_RETURN_NONE;
511 }
512 Py_INCREF(fut->fut_source_tb);
513 return fut->fut_source_tb;
514}
515
516static PyObject *
517FutureObj_get_state(FutureObj *fut)
518{
519 _Py_IDENTIFIER(PENDING);
520 _Py_IDENTIFIER(CANCELLED);
521 _Py_IDENTIFIER(FINISHED);
522 PyObject *ret = NULL;
523
524 switch (fut->fut_state) {
525 case STATE_PENDING:
526 ret = _PyUnicode_FromId(&PyId_PENDING);
527 break;
528 case STATE_CANCELLED:
529 ret = _PyUnicode_FromId(&PyId_CANCELLED);
530 break;
531 case STATE_FINISHED:
532 ret = _PyUnicode_FromId(&PyId_FINISHED);
533 break;
534 default:
535 assert (0);
536 }
537 Py_INCREF(ret);
538 return ret;
539}
540
541static PyObject*
542FutureObj__repr_info(FutureObj *fut)
543{
544 if (asyncio_repr_info_func == NULL) {
545 return PyList_New(0);
546 }
547 return PyObject_CallFunctionObjArgs(asyncio_repr_info_func, fut, NULL);
548}
549
550static PyObject *
551FutureObj_repr(FutureObj *fut)
552{
553 _Py_IDENTIFIER(_repr_info);
554
555 PyObject *_repr_info = _PyUnicode_FromId(&PyId__repr_info); // borrowed
556 if (_repr_info == NULL) {
557 return NULL;
558 }
559
560 PyObject *rinfo = PyObject_CallMethodObjArgs((PyObject*)fut, _repr_info,
561 NULL);
562 if (rinfo == NULL) {
563 return NULL;
564 }
565
566 PyObject *sp = PyUnicode_FromString(" ");
567 if (sp == NULL) {
568 Py_DECREF(rinfo);
569 return NULL;
570 }
571
572 PyObject *rinfo_s = PyUnicode_Join(sp, rinfo);
573 Py_DECREF(sp);
574 Py_DECREF(rinfo);
575 if (rinfo_s == NULL) {
576 return NULL;
577 }
578
579 PyObject *rstr = NULL;
580 PyObject *type_name = PyObject_GetAttrString((PyObject*)Py_TYPE(fut),
581 "__name__");
582 if (type_name != NULL) {
583 rstr = PyUnicode_FromFormat("<%S %S>", type_name, rinfo_s);
584 Py_DECREF(type_name);
585 }
586 Py_DECREF(rinfo_s);
587 return rstr;
588}
589
590static void
591FutureObj_finalize(FutureObj *fut)
592{
593 _Py_IDENTIFIER(call_exception_handler);
594 _Py_IDENTIFIER(message);
595 _Py_IDENTIFIER(exception);
596 _Py_IDENTIFIER(future);
597 _Py_IDENTIFIER(source_traceback);
598
599 if (!fut->fut_log_tb) {
600 return;
601 }
602 assert(fut->fut_exception != NULL);
603 fut->fut_log_tb = 0;;
604
605 PyObject *error_type, *error_value, *error_traceback;
606 /* Save the current exception, if any. */
607 PyErr_Fetch(&error_type, &error_value, &error_traceback);
608
609 PyObject *context = NULL;
610 PyObject *type_name = NULL;
611 PyObject *message = NULL;
612 PyObject *func = NULL;
613 PyObject *res = NULL;
614
615 context = PyDict_New();
616 if (context == NULL) {
617 goto finally;
618 }
619
620 type_name = PyObject_GetAttrString((PyObject*)Py_TYPE(fut), "__name__");
621 if (type_name == NULL) {
622 goto finally;
623 }
624
625 message = PyUnicode_FromFormat(
626 "%S exception was never retrieved", type_name);
627 if (message == NULL) {
628 goto finally;
629 }
630
631 if (_PyDict_SetItemId(context, &PyId_message, message) < 0 ||
632 _PyDict_SetItemId(context, &PyId_exception, fut->fut_exception) < 0 ||
633 _PyDict_SetItemId(context, &PyId_future, (PyObject*)fut) < 0) {
634 goto finally;
635 }
636 if (fut->fut_source_tb != NULL) {
637 if (_PyDict_SetItemId(context, &PyId_source_traceback,
638 fut->fut_source_tb) < 0) {
639 goto finally;
640 }
641 }
642
643 func = _PyObject_GetAttrId(fut->fut_loop, &PyId_call_exception_handler);
644 if (func != NULL) {
645 res = _PyObject_CallArg1(func, context);
646 if (res == NULL) {
647 PyErr_WriteUnraisable(func);
648 }
649 }
650
651finally:
652 Py_CLEAR(context);
653 Py_CLEAR(type_name);
654 Py_CLEAR(message);
655 Py_CLEAR(func);
656 Py_CLEAR(res);
657
658 /* Restore the saved exception. */
659 PyErr_Restore(error_type, error_value, error_traceback);
660}
661
662
663static PyAsyncMethods FutureType_as_async = {
664 (unaryfunc)new_future_iter, /* am_await */
665 0, /* am_aiter */
666 0 /* am_anext */
667};
668
669static PyMethodDef FutureType_methods[] = {
670 {"_repr_info", (PyCFunction)FutureObj__repr_info, METH_NOARGS, NULL},
671 {"add_done_callback",
672 (PyCFunction)FutureObj_add_done_callback,
673 METH_O, pydoc_add_done_callback},
674 {"remove_done_callback",
675 (PyCFunction)FutureObj_remove_done_callback,
676 METH_O, pydoc_remove_done_callback},
677 {"set_result",
678 (PyCFunction)FutureObj_set_result, METH_O, pydoc_set_result},
679 {"set_exception",
680 (PyCFunction)FutureObj_set_exception, METH_O, pydoc_set_exception},
681 {"cancel", (PyCFunction)FutureObj_cancel, METH_NOARGS, pydoc_cancel},
682 {"cancelled",
683 (PyCFunction)FutureObj_cancelled, METH_NOARGS, pydoc_cancelled},
684 {"done", (PyCFunction)FutureObj_done, METH_NOARGS, pydoc_done},
685 {"result", (PyCFunction)FutureObj_result, METH_NOARGS, pydoc_result},
686 {"exception",
687 (PyCFunction)FutureObj_exception, METH_NOARGS, pydoc_exception},
688 {NULL, NULL} /* Sentinel */
689};
690
691static PyGetSetDef FutureType_getsetlist[] = {
692 {"_state", (getter)FutureObj_get_state, NULL, NULL},
693 {"_asyncio_future_blocking", (getter)FutureObj_get_blocking,
694 (setter)FutureObj_set_blocking, NULL},
695 {"_loop", (getter)FutureObj_get_loop, NULL, NULL},
696 {"_callbacks", (getter)FutureObj_get_callbacks, NULL, NULL},
697 {"_result", (getter)FutureObj_get_result, NULL, NULL},
698 {"_exception", (getter)FutureObj_get_exception, NULL, NULL},
699 {"_log_traceback", (getter)FutureObj_get_log_traceback, NULL, NULL},
700 {"_source_traceback", (getter)FutureObj_get_source_traceback, NULL, NULL},
701 {NULL} /* Sentinel */
702};
703
704static void FutureObj_dealloc(PyObject *self);
705
706static PyTypeObject FutureType = {
707 PyVarObject_HEAD_INIT(0, 0)
INADA Naoki9f2ce252016-10-15 15:39:19 +0900708 "_asyncio.Future",
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900709 sizeof(FutureObj), /* tp_basicsize */
710 .tp_dealloc = FutureObj_dealloc,
711 .tp_as_async = &FutureType_as_async,
712 .tp_repr = (reprfunc)FutureObj_repr,
713 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE
714 | Py_TPFLAGS_HAVE_FINALIZE,
715 .tp_doc = "Fast asyncio.Future implementation.",
716 .tp_traverse = (traverseproc)FutureObj_traverse,
717 .tp_clear = (inquiry)FutureObj_clear,
718 .tp_weaklistoffset = offsetof(FutureObj, fut_weakreflist),
719 .tp_iter = (getiterfunc)new_future_iter,
720 .tp_methods = FutureType_methods,
721 .tp_getset = FutureType_getsetlist,
722 .tp_dictoffset = offsetof(FutureObj, dict),
723 .tp_init = (initproc)FutureObj_init,
724 .tp_new = PyType_GenericNew,
725 .tp_finalize = (destructor)FutureObj_finalize,
726};
727
728static void
729FutureObj_dealloc(PyObject *self)
730{
731 FutureObj *fut = (FutureObj *)self;
732
733 if (Py_TYPE(fut) == &FutureType) {
734 /* When fut is subclass of Future, finalizer is called from
735 * subtype_dealloc.
736 */
737 if (PyObject_CallFinalizerFromDealloc(self) < 0) {
738 // resurrected.
739 return;
740 }
741 }
742
743 if (fut->fut_weakreflist != NULL) {
744 PyObject_ClearWeakRefs(self);
745 }
746
747 FutureObj_clear(fut);
748 Py_TYPE(fut)->tp_free(fut);
749}
750
751
752/*********************** Future Iterator **************************/
753
754typedef struct {
755 PyObject_HEAD
756 FutureObj *future;
757} futureiterobject;
758
759static void
760FutureIter_dealloc(futureiterobject *it)
761{
762 _PyObject_GC_UNTRACK(it);
763 Py_XDECREF(it->future);
764 PyObject_GC_Del(it);
765}
766
767static PyObject *
768FutureIter_iternext(futureiterobject *it)
769{
770 PyObject *res;
771 FutureObj *fut = it->future;
772
773 if (fut == NULL) {
774 return NULL;
775 }
776
777 if (fut->fut_state == STATE_PENDING) {
778 if (!fut->fut_blocking) {
779 fut->fut_blocking = 1;
780 Py_INCREF(fut);
781 return (PyObject *)fut;
782 }
783 PyErr_Format(PyExc_AssertionError,
784 "yield from wasn't used with future");
785 return NULL;
786 }
787
788 res = FutureObj_result(fut, NULL);
789 if (res != NULL) {
Yury Selivanova4b884f2016-10-20 15:54:20 -0400790 /* The result of the Future is not an exception.
791
Yury Selivanov53478f82016-10-20 16:33:19 -0400792 We construct an exception instance manually with
Yury Selivanova4b884f2016-10-20 15:54:20 -0400793 PyObject_CallFunctionObjArgs and pass it to PyErr_SetObject
794 (similarly to what genobject.c does).
795
Yury Selivanov53478f82016-10-20 16:33:19 -0400796 We do this to handle a situation when "res" is a tuple, in which
Yury Selivanova4b884f2016-10-20 15:54:20 -0400797 case PyErr_SetObject would set the value of StopIteration to
798 the first element of the tuple.
799
800 (See PyErr_SetObject/_PyErr_CreateException code for details.)
801 */
802 PyObject *e = PyObject_CallFunctionObjArgs(
803 PyExc_StopIteration, res, NULL);
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900804 Py_DECREF(res);
Yury Selivanova4b884f2016-10-20 15:54:20 -0400805 if (e == NULL) {
806 return NULL;
807 }
808 PyErr_SetObject(PyExc_StopIteration, e);
809 Py_DECREF(e);
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900810 }
811
812 it->future = NULL;
813 Py_DECREF(fut);
814 return NULL;
815}
816
817static PyObject *
818FutureIter_send(futureiterobject *self, PyObject *arg)
819{
820 if (arg != Py_None) {
821 PyErr_Format(PyExc_TypeError,
822 "can't send non-None value to a FutureIter");
823 return NULL;
824 }
825 return FutureIter_iternext(self);
826}
827
828static PyObject *
829FutureIter_throw(futureiterobject *self, PyObject *args)
830{
831 PyObject *type=NULL, *val=NULL, *tb=NULL;
832 if (!PyArg_ParseTuple(args, "O|OO", &type, &val, &tb))
833 return NULL;
834
835 if (val == Py_None) {
836 val = NULL;
837 }
838 if (tb == Py_None) {
839 tb = NULL;
840 }
841
842 Py_CLEAR(self->future);
843
844 if (tb != NULL) {
845 PyErr_Restore(type, val, tb);
846 }
847 else if (val != NULL) {
848 PyErr_SetObject(type, val);
849 }
850 else {
851 if (PyExceptionClass_Check(type)) {
852 val = PyObject_CallObject(type, NULL);
853 }
854 else {
855 val = type;
856 assert (PyExceptionInstance_Check(val));
857 type = (PyObject*)Py_TYPE(val);
858 assert (PyExceptionClass_Check(type));
859 }
860 PyErr_SetObject(type, val);
861 }
862 return FutureIter_iternext(self);
863}
864
865static PyObject *
866FutureIter_close(futureiterobject *self, PyObject *arg)
867{
868 Py_CLEAR(self->future);
869 Py_RETURN_NONE;
870}
871
872static int
873FutureIter_traverse(futureiterobject *it, visitproc visit, void *arg)
874{
875 Py_VISIT(it->future);
876 return 0;
877}
878
879static PyMethodDef FutureIter_methods[] = {
880 {"send", (PyCFunction)FutureIter_send, METH_O, NULL},
881 {"throw", (PyCFunction)FutureIter_throw, METH_VARARGS, NULL},
882 {"close", (PyCFunction)FutureIter_close, METH_NOARGS, NULL},
883 {NULL, NULL} /* Sentinel */
884};
885
886static PyTypeObject FutureIterType = {
887 PyVarObject_HEAD_INIT(0, 0)
INADA Naoki9f2ce252016-10-15 15:39:19 +0900888 "_asyncio.FutureIter",
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900889 sizeof(futureiterobject), /* tp_basicsize */
890 0, /* tp_itemsize */
891 (destructor)FutureIter_dealloc, /* tp_dealloc */
892 0, /* tp_print */
893 0, /* tp_getattr */
894 0, /* tp_setattr */
895 0, /* tp_as_async */
896 0, /* tp_repr */
897 0, /* tp_as_number */
898 0, /* tp_as_sequence */
899 0, /* tp_as_mapping */
900 0, /* tp_hash */
901 0, /* tp_call */
902 0, /* tp_str */
903 PyObject_GenericGetAttr, /* tp_getattro */
904 0, /* tp_setattro */
905 0, /* tp_as_buffer */
906 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
907 0, /* tp_doc */
908 (traverseproc)FutureIter_traverse, /* tp_traverse */
909 0, /* tp_clear */
910 0, /* tp_richcompare */
911 0, /* tp_weaklistoffset */
912 PyObject_SelfIter, /* tp_iter */
913 (iternextfunc)FutureIter_iternext, /* tp_iternext */
914 FutureIter_methods, /* tp_methods */
915 0, /* tp_members */
916};
917
918static PyObject *
919new_future_iter(PyObject *fut)
920{
921 futureiterobject *it;
922
923 if (!PyObject_TypeCheck(fut, &FutureType)) {
924 PyErr_BadInternalCall();
925 return NULL;
926 }
927 it = PyObject_GC_New(futureiterobject, &FutureIterType);
928 if (it == NULL) {
929 return NULL;
930 }
931 Py_INCREF(fut);
932 it->future = (FutureObj*)fut;
INADA Naoki1be427b2016-10-11 02:12:34 +0900933 PyObject_GC_Track(it);
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900934 return (PyObject*)it;
935}
936
937/*********************** Module **************************/
938
INADA Naokic411a7d2016-10-18 11:48:14 +0900939static int
940init_module(void)
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900941{
INADA Naokic411a7d2016-10-18 11:48:14 +0900942 PyObject *module = NULL;
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900943
INADA Naokic411a7d2016-10-18 11:48:14 +0900944 module = PyImport_ImportModule("traceback");
945 if (module == NULL) {
946 return -1;
947 }
948 // new reference
949 traceback_extract_stack = PyObject_GetAttrString(module, "extract_stack");
950 if (traceback_extract_stack == NULL) {
951 goto fail;
952 }
953 Py_DECREF(module);
954
955 module = PyImport_ImportModule("asyncio.events");
956 if (module == NULL) {
957 goto fail;
958 }
959 asyncio_get_event_loop = PyObject_GetAttrString(module, "get_event_loop");
960 if (asyncio_get_event_loop == NULL) {
961 goto fail;
962 }
963 Py_DECREF(module);
964
965 module = PyImport_ImportModule("asyncio.futures");
966 if (module == NULL) {
967 goto fail;
968 }
969 asyncio_repr_info_func = PyObject_GetAttrString(module,
970 "_future_repr_info");
971 if (asyncio_repr_info_func == NULL) {
972 goto fail;
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900973 }
974
INADA Naokic411a7d2016-10-18 11:48:14 +0900975 asyncio_InvalidStateError = PyObject_GetAttrString(module,
976 "InvalidStateError");
977 if (asyncio_InvalidStateError == NULL) {
978 goto fail;
979 }
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900980
INADA Naokic411a7d2016-10-18 11:48:14 +0900981 asyncio_CancelledError = PyObject_GetAttrString(module, "CancelledError");
982 if (asyncio_CancelledError == NULL) {
983 goto fail;
984 }
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900985
INADA Naokic411a7d2016-10-18 11:48:14 +0900986 Py_DECREF(module);
987 return 0;
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900988
INADA Naokic411a7d2016-10-18 11:48:14 +0900989fail:
990 Py_CLEAR(traceback_extract_stack);
991 Py_CLEAR(asyncio_get_event_loop);
992 Py_CLEAR(asyncio_repr_info_func);
993 Py_CLEAR(asyncio_InvalidStateError);
994 Py_CLEAR(asyncio_CancelledError);
995 Py_CLEAR(module);
996 return -1;
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900997}
998
999
INADA Naokic411a7d2016-10-18 11:48:14 +09001000PyDoc_STRVAR(module_doc, "Accelerator module for asyncio");
INADA Naoki9e4e38e2016-10-09 14:44:47 +09001001
INADA Naoki9f2ce252016-10-15 15:39:19 +09001002static struct PyModuleDef _asynciomodule = {
INADA Naoki9e4e38e2016-10-09 14:44:47 +09001003 PyModuleDef_HEAD_INIT, /* m_base */
INADA Naoki9f2ce252016-10-15 15:39:19 +09001004 "_asyncio", /* m_name */
INADA Naoki9e4e38e2016-10-09 14:44:47 +09001005 module_doc, /* m_doc */
1006 -1, /* m_size */
INADA Naokic411a7d2016-10-18 11:48:14 +09001007 NULL, /* m_methods */
INADA Naoki9e4e38e2016-10-09 14:44:47 +09001008 NULL, /* m_slots */
1009 NULL, /* m_traverse */
1010 NULL, /* m_clear */
1011 NULL, /* m_free */
1012};
1013
1014
1015PyMODINIT_FUNC
INADA Naoki9f2ce252016-10-15 15:39:19 +09001016PyInit__asyncio(void)
INADA Naoki9e4e38e2016-10-09 14:44:47 +09001017{
INADA Naokic411a7d2016-10-18 11:48:14 +09001018 if (init_module() < 0) {
1019 return NULL;
1020 }
INADA Naoki9e4e38e2016-10-09 14:44:47 +09001021 if (PyType_Ready(&FutureType) < 0) {
1022 return NULL;
1023 }
1024 if (PyType_Ready(&FutureIterType) < 0) {
1025 return NULL;
1026 }
1027
INADA Naoki9f2ce252016-10-15 15:39:19 +09001028 PyObject *m = PyModule_Create(&_asynciomodule);
INADA Naoki9e4e38e2016-10-09 14:44:47 +09001029 if (m == NULL) {
1030 return NULL;
1031 }
1032
1033 Py_INCREF(&FutureType);
1034 if (PyModule_AddObject(m, "Future", (PyObject *)&FutureType) < 0) {
1035 Py_DECREF(&FutureType);
1036 return NULL;
1037 }
1038
1039 return m;
1040}