blob: b8a88e61d4aba45fac501158e66cc6bb4b6cee32 [file] [log] [blame]
INADA Naoki9e4e38e2016-10-09 14:44:47 +09001#include "Python.h"
2#include "structmember.h"
3
4
Yury Selivanova0c1ba62016-10-28 12:52:37 -04005/*[clinic input]
6module _asyncio
7[clinic start generated code]*/
8/*[clinic end generated code: output=da39a3ee5e6b4b0d input=8fd17862aa989c69]*/
9
10
INADA Naoki9e4e38e2016-10-09 14:44:47 +090011/* identifiers used from some functions */
Yury Selivanova0c1ba62016-10-28 12:52:37 -040012_Py_IDENTIFIER(add_done_callback);
INADA Naoki9e4e38e2016-10-09 14:44:47 +090013_Py_IDENTIFIER(call_soon);
Yury Selivanova0c1ba62016-10-28 12:52:37 -040014_Py_IDENTIFIER(cancel);
15_Py_IDENTIFIER(send);
16_Py_IDENTIFIER(throw);
17_Py_IDENTIFIER(_step);
18_Py_IDENTIFIER(_schedule_callbacks);
19_Py_IDENTIFIER(_wakeup);
INADA Naoki9e4e38e2016-10-09 14:44:47 +090020
21
INADA Naoki9f2ce252016-10-15 15:39:19 +090022/* State of the _asyncio module */
Yury Selivanova0c1ba62016-10-28 12:52:37 -040023static PyObject *all_tasks;
Yury Selivanov684ef2c2016-10-28 19:01:21 -040024static PyObject *current_tasks;
INADA Naoki9e4e38e2016-10-09 14:44:47 +090025static PyObject *traceback_extract_stack;
26static PyObject *asyncio_get_event_loop;
Yury Selivanova0c1ba62016-10-28 12:52:37 -040027static PyObject *asyncio_future_repr_info_func;
28static PyObject *asyncio_task_repr_info_func;
29static PyObject *asyncio_task_get_stack_func;
30static PyObject *asyncio_task_print_stack_func;
INADA Naoki9e4e38e2016-10-09 14:44:47 +090031static PyObject *asyncio_InvalidStateError;
32static PyObject *asyncio_CancelledError;
Yury Selivanova0c1ba62016-10-28 12:52:37 -040033static PyObject *inspect_isgenerator;
INADA Naoki9e4e38e2016-10-09 14:44:47 +090034
35
INADA Naoki9e4e38e2016-10-09 14:44:47 +090036typedef enum {
37 STATE_PENDING,
38 STATE_CANCELLED,
39 STATE_FINISHED
40} fut_state;
41
Yury Selivanova0c1ba62016-10-28 12:52:37 -040042#define FutureObj_HEAD(prefix) \
43 PyObject_HEAD \
44 PyObject *prefix##_loop; \
45 PyObject *prefix##_callbacks; \
46 PyObject *prefix##_exception; \
47 PyObject *prefix##_result; \
48 PyObject *prefix##_source_tb; \
49 fut_state prefix##_state; \
50 int prefix##_log_tb; \
51 int prefix##_blocking; \
52 PyObject *dict; \
53 PyObject *prefix##_weakreflist;
54
55typedef struct {
56 FutureObj_HEAD(fut)
57} FutureObj;
58
59typedef struct {
60 FutureObj_HEAD(task)
61 PyObject *task_fut_waiter;
62 PyObject *task_coro;
63 int task_must_cancel;
64 int task_log_destroy_pending;
65} TaskObj;
INADA Naoki9e4e38e2016-10-09 14:44:47 +090066
67typedef struct {
68 PyObject_HEAD
Yury Selivanova0c1ba62016-10-28 12:52:37 -040069 TaskObj *sw_task;
70 PyObject *sw_arg;
71} TaskSendMethWrapper;
INADA Naoki9e4e38e2016-10-09 14:44:47 +090072
Yury Selivanova0c1ba62016-10-28 12:52:37 -040073typedef struct {
74 PyObject_HEAD
75 TaskObj *ww_task;
76} TaskWakeupMethWrapper;
77
78
79#include "clinic/_asynciomodule.c.h"
80
81
82/*[clinic input]
83class _asyncio.Future "FutureObj *" "&Future_Type"
84[clinic start generated code]*/
85/*[clinic end generated code: output=da39a3ee5e6b4b0d input=00d3e4abca711e0f]*/
86
87/* Get FutureIter from Future */
88static PyObject* future_new_iter(PyObject *);
89static inline int future_call_schedule_callbacks(FutureObj *);
INADA Naoki9e4e38e2016-10-09 14:44:47 +090090
91static int
Yury Selivanova0c1ba62016-10-28 12:52:37 -040092future_schedule_callbacks(FutureObj *fut)
INADA Naoki9e4e38e2016-10-09 14:44:47 +090093{
94 Py_ssize_t len;
95 PyObject* iters;
96 int i;
97
98 if (fut->fut_callbacks == NULL) {
99 PyErr_SetString(PyExc_RuntimeError, "NULL callbacks");
100 return -1;
101 }
102
103 len = PyList_GET_SIZE(fut->fut_callbacks);
104 if (len == 0) {
105 return 0;
106 }
107
108 iters = PyList_GetSlice(fut->fut_callbacks, 0, len);
109 if (iters == NULL) {
110 return -1;
111 }
112 if (PyList_SetSlice(fut->fut_callbacks, 0, len, NULL) < 0) {
113 Py_DECREF(iters);
114 return -1;
115 }
116
117 for (i = 0; i < len; i++) {
118 PyObject *handle = NULL;
119 PyObject *cb = PyList_GET_ITEM(iters, i);
120
Victor Stinnerb6ed57d2016-12-09 14:24:02 +0100121 handle = _PyObject_CallMethodIdObjArgs(fut->fut_loop, &PyId_call_soon,
122 cb, fut, NULL);
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900123
124 if (handle == NULL) {
125 Py_DECREF(iters);
126 return -1;
127 }
128 else {
129 Py_DECREF(handle);
130 }
131 }
132
133 Py_DECREF(iters);
134 return 0;
135}
136
137static int
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400138future_init(FutureObj *fut, PyObject *loop)
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900139{
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900140 PyObject *res = NULL;
141 _Py_IDENTIFIER(get_debug);
142
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900143 if (loop == NULL || loop == Py_None) {
Victor Stinnera5ed5f02016-12-06 18:45:50 +0100144 loop = _PyObject_CallNoArg(asyncio_get_event_loop);
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900145 if (loop == NULL) {
146 return -1;
147 }
148 }
149 else {
150 Py_INCREF(loop);
151 }
152 Py_CLEAR(fut->fut_loop);
153 fut->fut_loop = loop;
154
Victor Stinnerf94d1ee2016-10-29 09:05:39 +0200155 res = _PyObject_CallMethodId(fut->fut_loop, &PyId_get_debug, NULL);
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900156 if (res == NULL) {
157 return -1;
158 }
159 if (PyObject_IsTrue(res)) {
160 Py_CLEAR(res);
Victor Stinnera5ed5f02016-12-06 18:45:50 +0100161 fut->fut_source_tb = _PyObject_CallNoArg(traceback_extract_stack);
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900162 if (fut->fut_source_tb == NULL) {
163 return -1;
164 }
165 }
166 else {
167 Py_CLEAR(res);
168 }
169
170 fut->fut_callbacks = PyList_New(0);
171 if (fut->fut_callbacks == NULL) {
172 return -1;
173 }
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400174
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900175 return 0;
176}
177
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900178static PyObject *
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400179future_set_result(FutureObj *fut, PyObject *res)
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900180{
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900181 if (fut->fut_state != STATE_PENDING) {
182 PyErr_SetString(asyncio_InvalidStateError, "invalid state");
183 return NULL;
184 }
185
186 Py_INCREF(res);
187 fut->fut_result = res;
188 fut->fut_state = STATE_FINISHED;
189
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400190 if (future_call_schedule_callbacks(fut) == -1) {
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900191 return NULL;
192 }
193 Py_RETURN_NONE;
194}
195
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900196static PyObject *
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400197future_set_exception(FutureObj *fut, PyObject *exc)
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900198{
199 PyObject *exc_val = NULL;
200
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900201 if (fut->fut_state != STATE_PENDING) {
202 PyErr_SetString(asyncio_InvalidStateError, "invalid state");
203 return NULL;
204 }
205
206 if (PyExceptionClass_Check(exc)) {
Victor Stinnera5ed5f02016-12-06 18:45:50 +0100207 exc_val = _PyObject_CallNoArg(exc);
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900208 if (exc_val == NULL) {
209 return NULL;
210 }
211 }
212 else {
213 exc_val = exc;
214 Py_INCREF(exc_val);
215 }
216 if (!PyExceptionInstance_Check(exc_val)) {
217 Py_DECREF(exc_val);
218 PyErr_SetString(PyExc_TypeError, "invalid exception object");
219 return NULL;
220 }
221 if ((PyObject*)Py_TYPE(exc_val) == PyExc_StopIteration) {
222 Py_DECREF(exc_val);
223 PyErr_SetString(PyExc_TypeError,
224 "StopIteration interacts badly with generators "
225 "and cannot be raised into a Future");
226 return NULL;
227 }
228
229 fut->fut_exception = exc_val;
230 fut->fut_state = STATE_FINISHED;
231
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400232 if (future_call_schedule_callbacks(fut) == -1) {
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900233 return NULL;
234 }
235
236 fut->fut_log_tb = 1;
237 Py_RETURN_NONE;
238}
239
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400240static int
241future_get_result(FutureObj *fut, PyObject **result)
242{
243 PyObject *exc;
244
245 if (fut->fut_state == STATE_CANCELLED) {
246 exc = _PyObject_CallNoArg(asyncio_CancelledError);
247 if (exc == NULL) {
248 return -1;
249 }
250 *result = exc;
251 return 1;
252 }
253
254 if (fut->fut_state != STATE_FINISHED) {
255 PyObject *msg = PyUnicode_FromString("Result is not ready.");
256 if (msg == NULL) {
257 return -1;
258 }
259
Victor Stinner7bfb42d2016-12-05 17:04:32 +0100260 exc = PyObject_CallFunctionObjArgs(asyncio_InvalidStateError, msg, NULL);
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400261 Py_DECREF(msg);
262 if (exc == NULL) {
263 return -1;
264 }
265
266 *result = exc;
267 return 1;
268 }
269
270 fut->fut_log_tb = 0;
271 if (fut->fut_exception != NULL) {
272 Py_INCREF(fut->fut_exception);
273 *result = fut->fut_exception;
274 return 1;
275 }
276
277 Py_INCREF(fut->fut_result);
278 *result = fut->fut_result;
279 return 0;
280}
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900281
282static PyObject *
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400283future_add_done_callback(FutureObj *fut, PyObject *arg)
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900284{
285 if (fut->fut_state != STATE_PENDING) {
Victor Stinnerb6ed57d2016-12-09 14:24:02 +0100286 PyObject *handle = _PyObject_CallMethodIdObjArgs(fut->fut_loop,
287 &PyId_call_soon,
288 arg, fut, NULL);
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900289
290 if (handle == NULL) {
291 return NULL;
292 }
293 else {
294 Py_DECREF(handle);
295 }
296 }
297 else {
298 int err = PyList_Append(fut->fut_callbacks, arg);
299 if (err != 0) {
300 return NULL;
301 }
302 }
303 Py_RETURN_NONE;
304}
305
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400306static PyObject *
307future_cancel(FutureObj *fut)
308{
Yury Selivanov7ce1c6f2017-06-11 13:49:18 +0000309 fut->fut_log_tb = 0;
310
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400311 if (fut->fut_state != STATE_PENDING) {
312 Py_RETURN_FALSE;
313 }
314 fut->fut_state = STATE_CANCELLED;
315
316 if (future_call_schedule_callbacks(fut) == -1) {
317 return NULL;
318 }
319
320 Py_RETURN_TRUE;
321}
322
323/*[clinic input]
324_asyncio.Future.__init__
325
326 *
327 loop: 'O' = NULL
328
329This class is *almost* compatible with concurrent.futures.Future.
330
331 Differences:
332
333 - result() and exception() do not take a timeout argument and
334 raise an exception when the future isn't done yet.
335
336 - Callbacks registered with add_done_callback() are always called
337 via the event loop's call_soon_threadsafe().
338
339 - This class is not compatible with the wait() and as_completed()
340 methods in the concurrent.futures package.
341[clinic start generated code]*/
342
343static int
344_asyncio_Future___init___impl(FutureObj *self, PyObject *loop)
345/*[clinic end generated code: output=9ed75799eaccb5d6 input=8e1681f23605be2d]*/
346
347{
348 return future_init(self, loop);
349}
350
351static int
352FutureObj_clear(FutureObj *fut)
353{
354 Py_CLEAR(fut->fut_loop);
355 Py_CLEAR(fut->fut_callbacks);
356 Py_CLEAR(fut->fut_result);
357 Py_CLEAR(fut->fut_exception);
358 Py_CLEAR(fut->fut_source_tb);
359 Py_CLEAR(fut->dict);
360 return 0;
361}
362
363static int
364FutureObj_traverse(FutureObj *fut, visitproc visit, void *arg)
365{
366 Py_VISIT(fut->fut_loop);
367 Py_VISIT(fut->fut_callbacks);
368 Py_VISIT(fut->fut_result);
369 Py_VISIT(fut->fut_exception);
370 Py_VISIT(fut->fut_source_tb);
371 Py_VISIT(fut->dict);
372 return 0;
373}
374
375/*[clinic input]
376_asyncio.Future.result
377
378Return the result this future represents.
379
380If the future has been cancelled, raises CancelledError. If the
381future's result isn't yet available, raises InvalidStateError. If
382the future is done and has an exception set, this exception is raised.
383[clinic start generated code]*/
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900384
385static PyObject *
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400386_asyncio_Future_result_impl(FutureObj *self)
387/*[clinic end generated code: output=f35f940936a4b1e5 input=49ecf9cf5ec50dc5]*/
388{
389 PyObject *result;
390 int res = future_get_result(self, &result);
391
392 if (res == -1) {
393 return NULL;
394 }
395
396 if (res == 0) {
397 return result;
398 }
399
400 assert(res == 1);
401
402 PyErr_SetObject(PyExceptionInstance_Class(result), result);
403 Py_DECREF(result);
404 return NULL;
405}
406
407/*[clinic input]
408_asyncio.Future.exception
409
410Return the exception that was set on this future.
411
412The exception (or None if no exception was set) is returned only if
413the future is done. If the future has been cancelled, raises
414CancelledError. If the future isn't done yet, raises
415InvalidStateError.
416[clinic start generated code]*/
417
418static PyObject *
419_asyncio_Future_exception_impl(FutureObj *self)
420/*[clinic end generated code: output=88b20d4f855e0710 input=733547a70c841c68]*/
421{
422 if (self->fut_state == STATE_CANCELLED) {
423 PyErr_SetString(asyncio_CancelledError, "");
424 return NULL;
425 }
426
427 if (self->fut_state != STATE_FINISHED) {
428 PyErr_SetString(asyncio_InvalidStateError, "Result is not ready.");
429 return NULL;
430 }
431
432 if (self->fut_exception != NULL) {
433 self->fut_log_tb = 0;
434 Py_INCREF(self->fut_exception);
435 return self->fut_exception;
436 }
437
438 Py_RETURN_NONE;
439}
440
441/*[clinic input]
442_asyncio.Future.set_result
443
444 res: 'O'
445 /
446
447Mark the future done and set its result.
448
449If the future is already done when this method is called, raises
450InvalidStateError.
451[clinic start generated code]*/
452
453static PyObject *
454_asyncio_Future_set_result(FutureObj *self, PyObject *res)
455/*[clinic end generated code: output=a620abfc2796bfb6 input=8619565e0503357e]*/
456{
457 return future_set_result(self, res);
458}
459
460/*[clinic input]
461_asyncio.Future.set_exception
462
463 exception: 'O'
464 /
465
466Mark the future done and set an exception.
467
468If the future is already done when this method is called, raises
469InvalidStateError.
470[clinic start generated code]*/
471
472static PyObject *
473_asyncio_Future_set_exception(FutureObj *self, PyObject *exception)
474/*[clinic end generated code: output=f1c1b0cd321be360 input=1377dbe15e6ea186]*/
475{
476 return future_set_exception(self, exception);
477}
478
479/*[clinic input]
480_asyncio.Future.add_done_callback
481
482 fn: 'O'
483 /
484
485Add a callback to be run when the future becomes done.
486
487The callback is called with a single argument - the future object. If
488the future is already done when this is called, the callback is
489scheduled with call_soon.
490[clinic start generated code]*/
491
492static PyObject *
493_asyncio_Future_add_done_callback(FutureObj *self, PyObject *fn)
494/*[clinic end generated code: output=819e09629b2ec2b5 input=8cce187e32cec6a8]*/
495{
496 return future_add_done_callback(self, fn);
497}
498
499/*[clinic input]
500_asyncio.Future.remove_done_callback
501
502 fn: 'O'
503 /
504
505Remove all instances of a callback from the "call when done" list.
506
507Returns the number of callbacks removed.
508[clinic start generated code]*/
509
510static PyObject *
511_asyncio_Future_remove_done_callback(FutureObj *self, PyObject *fn)
512/*[clinic end generated code: output=5ab1fb52b24ef31f input=3fedb73e1409c31c]*/
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900513{
514 PyObject *newlist;
515 Py_ssize_t len, i, j=0;
516
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400517 len = PyList_GET_SIZE(self->fut_callbacks);
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900518 if (len == 0) {
519 return PyLong_FromSsize_t(0);
520 }
521
522 newlist = PyList_New(len);
523 if (newlist == NULL) {
524 return NULL;
525 }
526
Yury Selivanov84af9032017-03-02 23:46:56 -0500527 for (i = 0; i < PyList_GET_SIZE(self->fut_callbacks); i++) {
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900528 int ret;
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400529 PyObject *item = PyList_GET_ITEM(self->fut_callbacks, i);
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900530
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400531 if ((ret = PyObject_RichCompareBool(fn, item, Py_EQ)) < 0) {
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900532 goto fail;
533 }
534 if (ret == 0) {
535 Py_INCREF(item);
536 PyList_SET_ITEM(newlist, j, item);
537 j++;
538 }
539 }
540
541 if (PyList_SetSlice(newlist, j, len, NULL) < 0) {
542 goto fail;
543 }
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400544 if (PyList_SetSlice(self->fut_callbacks, 0, len, newlist) < 0) {
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900545 goto fail;
546 }
547 Py_DECREF(newlist);
548 return PyLong_FromSsize_t(len - j);
549
550fail:
551 Py_DECREF(newlist);
552 return NULL;
553}
554
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400555/*[clinic input]
556_asyncio.Future.cancel
557
558Cancel the future and schedule callbacks.
559
560If the future is already done or cancelled, return False. Otherwise,
561change the future's state to cancelled, schedule the callbacks and
562return True.
563[clinic start generated code]*/
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900564
565static PyObject *
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400566_asyncio_Future_cancel_impl(FutureObj *self)
567/*[clinic end generated code: output=e45b932ba8bd68a1 input=515709a127995109]*/
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900568{
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400569 return future_cancel(self);
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900570}
571
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400572/*[clinic input]
573_asyncio.Future.cancelled
574
575Return True if the future was cancelled.
576[clinic start generated code]*/
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900577
578static PyObject *
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400579_asyncio_Future_cancelled_impl(FutureObj *self)
580/*[clinic end generated code: output=145197ced586357d input=943ab8b7b7b17e45]*/
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900581{
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400582 if (self->fut_state == STATE_CANCELLED) {
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900583 Py_RETURN_TRUE;
584 }
585 else {
586 Py_RETURN_FALSE;
587 }
588}
589
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400590/*[clinic input]
591_asyncio.Future.done
592
593Return True if the future is done.
594
595Done means either that a result / exception are available, or that the
596future was cancelled.
597[clinic start generated code]*/
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900598
599static PyObject *
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400600_asyncio_Future_done_impl(FutureObj *self)
601/*[clinic end generated code: output=244c5ac351145096 input=28d7b23fdb65d2ac]*/
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900602{
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400603 if (self->fut_state == STATE_PENDING) {
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900604 Py_RETURN_FALSE;
605 }
606 else {
607 Py_RETURN_TRUE;
608 }
609}
610
611static PyObject *
612FutureObj_get_blocking(FutureObj *fut)
613{
614 if (fut->fut_blocking) {
615 Py_RETURN_TRUE;
616 }
617 else {
618 Py_RETURN_FALSE;
619 }
620}
621
622static int
623FutureObj_set_blocking(FutureObj *fut, PyObject *val)
624{
625 int is_true = PyObject_IsTrue(val);
626 if (is_true < 0) {
627 return -1;
628 }
629 fut->fut_blocking = is_true;
630 return 0;
631}
632
633static PyObject *
634FutureObj_get_log_traceback(FutureObj *fut)
635{
636 if (fut->fut_log_tb) {
637 Py_RETURN_TRUE;
638 }
639 else {
640 Py_RETURN_FALSE;
641 }
642}
643
Yury Selivanov7ce1c6f2017-06-11 13:49:18 +0000644static int
645FutureObj_set_log_traceback(FutureObj *fut, PyObject *val)
646{
647 int is_true = PyObject_IsTrue(val);
648 if (is_true < 0) {
649 return -1;
650 }
651 fut->fut_log_tb = is_true;
652 return 0;
653}
654
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900655static PyObject *
656FutureObj_get_loop(FutureObj *fut)
657{
658 if (fut->fut_loop == NULL) {
659 Py_RETURN_NONE;
660 }
661 Py_INCREF(fut->fut_loop);
662 return fut->fut_loop;
663}
664
665static PyObject *
666FutureObj_get_callbacks(FutureObj *fut)
667{
668 if (fut->fut_callbacks == NULL) {
669 Py_RETURN_NONE;
670 }
671 Py_INCREF(fut->fut_callbacks);
672 return fut->fut_callbacks;
673}
674
675static PyObject *
676FutureObj_get_result(FutureObj *fut)
677{
678 if (fut->fut_result == NULL) {
679 Py_RETURN_NONE;
680 }
681 Py_INCREF(fut->fut_result);
682 return fut->fut_result;
683}
684
685static PyObject *
686FutureObj_get_exception(FutureObj *fut)
687{
688 if (fut->fut_exception == NULL) {
689 Py_RETURN_NONE;
690 }
691 Py_INCREF(fut->fut_exception);
692 return fut->fut_exception;
693}
694
695static PyObject *
696FutureObj_get_source_traceback(FutureObj *fut)
697{
698 if (fut->fut_source_tb == NULL) {
699 Py_RETURN_NONE;
700 }
701 Py_INCREF(fut->fut_source_tb);
702 return fut->fut_source_tb;
703}
704
705static PyObject *
706FutureObj_get_state(FutureObj *fut)
707{
708 _Py_IDENTIFIER(PENDING);
709 _Py_IDENTIFIER(CANCELLED);
710 _Py_IDENTIFIER(FINISHED);
711 PyObject *ret = NULL;
712
713 switch (fut->fut_state) {
714 case STATE_PENDING:
715 ret = _PyUnicode_FromId(&PyId_PENDING);
716 break;
717 case STATE_CANCELLED:
718 ret = _PyUnicode_FromId(&PyId_CANCELLED);
719 break;
720 case STATE_FINISHED:
721 ret = _PyUnicode_FromId(&PyId_FINISHED);
722 break;
723 default:
724 assert (0);
725 }
726 Py_INCREF(ret);
727 return ret;
728}
729
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400730/*[clinic input]
731_asyncio.Future._repr_info
732[clinic start generated code]*/
733
734static PyObject *
735_asyncio_Future__repr_info_impl(FutureObj *self)
736/*[clinic end generated code: output=fa69e901bd176cfb input=f21504d8e2ae1ca2]*/
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900737{
Victor Stinnerde4ae3d2016-12-04 22:59:09 +0100738 return PyObject_CallFunctionObjArgs(
739 asyncio_future_repr_info_func, self, NULL);
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400740}
741
742/*[clinic input]
743_asyncio.Future._schedule_callbacks
744[clinic start generated code]*/
745
746static PyObject *
747_asyncio_Future__schedule_callbacks_impl(FutureObj *self)
748/*[clinic end generated code: output=5e8958d89ea1c5dc input=4f5f295f263f4a88]*/
749{
750 int ret = future_schedule_callbacks(self);
751 if (ret == -1) {
752 return NULL;
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900753 }
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400754 Py_RETURN_NONE;
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900755}
756
757static PyObject *
758FutureObj_repr(FutureObj *fut)
759{
760 _Py_IDENTIFIER(_repr_info);
761
762 PyObject *_repr_info = _PyUnicode_FromId(&PyId__repr_info); // borrowed
763 if (_repr_info == NULL) {
764 return NULL;
765 }
766
767 PyObject *rinfo = PyObject_CallMethodObjArgs((PyObject*)fut, _repr_info,
768 NULL);
769 if (rinfo == NULL) {
770 return NULL;
771 }
772
773 PyObject *sp = PyUnicode_FromString(" ");
774 if (sp == NULL) {
775 Py_DECREF(rinfo);
776 return NULL;
777 }
778
779 PyObject *rinfo_s = PyUnicode_Join(sp, rinfo);
780 Py_DECREF(sp);
781 Py_DECREF(rinfo);
782 if (rinfo_s == NULL) {
783 return NULL;
784 }
785
786 PyObject *rstr = NULL;
787 PyObject *type_name = PyObject_GetAttrString((PyObject*)Py_TYPE(fut),
788 "__name__");
789 if (type_name != NULL) {
790 rstr = PyUnicode_FromFormat("<%S %S>", type_name, rinfo_s);
791 Py_DECREF(type_name);
792 }
793 Py_DECREF(rinfo_s);
794 return rstr;
795}
796
797static void
798FutureObj_finalize(FutureObj *fut)
799{
800 _Py_IDENTIFIER(call_exception_handler);
801 _Py_IDENTIFIER(message);
802 _Py_IDENTIFIER(exception);
803 _Py_IDENTIFIER(future);
804 _Py_IDENTIFIER(source_traceback);
805
806 if (!fut->fut_log_tb) {
807 return;
808 }
809 assert(fut->fut_exception != NULL);
810 fut->fut_log_tb = 0;;
811
812 PyObject *error_type, *error_value, *error_traceback;
813 /* Save the current exception, if any. */
814 PyErr_Fetch(&error_type, &error_value, &error_traceback);
815
816 PyObject *context = NULL;
817 PyObject *type_name = NULL;
818 PyObject *message = NULL;
819 PyObject *func = NULL;
820 PyObject *res = NULL;
821
822 context = PyDict_New();
823 if (context == NULL) {
824 goto finally;
825 }
826
827 type_name = PyObject_GetAttrString((PyObject*)Py_TYPE(fut), "__name__");
828 if (type_name == NULL) {
829 goto finally;
830 }
831
832 message = PyUnicode_FromFormat(
833 "%S exception was never retrieved", type_name);
834 if (message == NULL) {
835 goto finally;
836 }
837
838 if (_PyDict_SetItemId(context, &PyId_message, message) < 0 ||
839 _PyDict_SetItemId(context, &PyId_exception, fut->fut_exception) < 0 ||
840 _PyDict_SetItemId(context, &PyId_future, (PyObject*)fut) < 0) {
841 goto finally;
842 }
843 if (fut->fut_source_tb != NULL) {
844 if (_PyDict_SetItemId(context, &PyId_source_traceback,
845 fut->fut_source_tb) < 0) {
846 goto finally;
847 }
848 }
849
850 func = _PyObject_GetAttrId(fut->fut_loop, &PyId_call_exception_handler);
851 if (func != NULL) {
Victor Stinner7bfb42d2016-12-05 17:04:32 +0100852 res = PyObject_CallFunctionObjArgs(func, context, NULL);
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900853 if (res == NULL) {
854 PyErr_WriteUnraisable(func);
855 }
856 }
857
858finally:
859 Py_CLEAR(context);
860 Py_CLEAR(type_name);
861 Py_CLEAR(message);
862 Py_CLEAR(func);
863 Py_CLEAR(res);
864
865 /* Restore the saved exception. */
866 PyErr_Restore(error_type, error_value, error_traceback);
867}
868
869
870static PyAsyncMethods FutureType_as_async = {
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400871 (unaryfunc)future_new_iter, /* am_await */
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900872 0, /* am_aiter */
873 0 /* am_anext */
874};
875
876static PyMethodDef FutureType_methods[] = {
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400877 _ASYNCIO_FUTURE_RESULT_METHODDEF
878 _ASYNCIO_FUTURE_EXCEPTION_METHODDEF
879 _ASYNCIO_FUTURE_SET_RESULT_METHODDEF
880 _ASYNCIO_FUTURE_SET_EXCEPTION_METHODDEF
881 _ASYNCIO_FUTURE_ADD_DONE_CALLBACK_METHODDEF
882 _ASYNCIO_FUTURE_REMOVE_DONE_CALLBACK_METHODDEF
883 _ASYNCIO_FUTURE_CANCEL_METHODDEF
884 _ASYNCIO_FUTURE_CANCELLED_METHODDEF
885 _ASYNCIO_FUTURE_DONE_METHODDEF
886 _ASYNCIO_FUTURE__REPR_INFO_METHODDEF
887 _ASYNCIO_FUTURE__SCHEDULE_CALLBACKS_METHODDEF
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900888 {NULL, NULL} /* Sentinel */
889};
890
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400891#define FUTURE_COMMON_GETSETLIST \
892 {"_state", (getter)FutureObj_get_state, NULL, NULL}, \
893 {"_asyncio_future_blocking", (getter)FutureObj_get_blocking, \
894 (setter)FutureObj_set_blocking, NULL}, \
895 {"_loop", (getter)FutureObj_get_loop, NULL, NULL}, \
896 {"_callbacks", (getter)FutureObj_get_callbacks, NULL, NULL}, \
897 {"_result", (getter)FutureObj_get_result, NULL, NULL}, \
898 {"_exception", (getter)FutureObj_get_exception, NULL, NULL}, \
Yury Selivanov7ce1c6f2017-06-11 13:49:18 +0000899 {"_log_traceback", (getter)FutureObj_get_log_traceback, \
900 (setter)FutureObj_set_log_traceback, NULL}, \
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900901 {"_source_traceback", (getter)FutureObj_get_source_traceback, NULL, NULL},
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400902
903static PyGetSetDef FutureType_getsetlist[] = {
904 FUTURE_COMMON_GETSETLIST
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900905 {NULL} /* Sentinel */
906};
907
908static void FutureObj_dealloc(PyObject *self);
909
910static PyTypeObject FutureType = {
Victor Stinner1aea8fb2016-10-28 19:13:52 +0200911 PyVarObject_HEAD_INIT(NULL, 0)
INADA Naoki9f2ce252016-10-15 15:39:19 +0900912 "_asyncio.Future",
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900913 sizeof(FutureObj), /* tp_basicsize */
914 .tp_dealloc = FutureObj_dealloc,
915 .tp_as_async = &FutureType_as_async,
916 .tp_repr = (reprfunc)FutureObj_repr,
917 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE
918 | Py_TPFLAGS_HAVE_FINALIZE,
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400919 .tp_doc = _asyncio_Future___init____doc__,
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900920 .tp_traverse = (traverseproc)FutureObj_traverse,
921 .tp_clear = (inquiry)FutureObj_clear,
922 .tp_weaklistoffset = offsetof(FutureObj, fut_weakreflist),
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400923 .tp_iter = (getiterfunc)future_new_iter,
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900924 .tp_methods = FutureType_methods,
925 .tp_getset = FutureType_getsetlist,
926 .tp_dictoffset = offsetof(FutureObj, dict),
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400927 .tp_init = (initproc)_asyncio_Future___init__,
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900928 .tp_new = PyType_GenericNew,
929 .tp_finalize = (destructor)FutureObj_finalize,
930};
931
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400932#define Future_CheckExact(obj) (Py_TYPE(obj) == &FutureType)
933
934static inline int
935future_call_schedule_callbacks(FutureObj *fut)
936{
937 if (Future_CheckExact(fut)) {
938 return future_schedule_callbacks(fut);
939 }
940 else {
941 /* `fut` is a subclass of Future */
942 PyObject *ret = _PyObject_CallMethodId(
943 (PyObject*)fut, &PyId__schedule_callbacks, NULL);
944 if (ret == NULL) {
945 return -1;
946 }
947
948 Py_DECREF(ret);
949 return 0;
950 }
951}
952
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900953static void
954FutureObj_dealloc(PyObject *self)
955{
956 FutureObj *fut = (FutureObj *)self;
957
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400958 if (Future_CheckExact(fut)) {
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900959 /* When fut is subclass of Future, finalizer is called from
960 * subtype_dealloc.
961 */
962 if (PyObject_CallFinalizerFromDealloc(self) < 0) {
963 // resurrected.
964 return;
965 }
966 }
967
968 if (fut->fut_weakreflist != NULL) {
969 PyObject_ClearWeakRefs(self);
970 }
971
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400972 (void)FutureObj_clear(fut);
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900973 Py_TYPE(fut)->tp_free(fut);
974}
975
976
977/*********************** Future Iterator **************************/
978
979typedef struct {
980 PyObject_HEAD
981 FutureObj *future;
982} futureiterobject;
983
984static void
985FutureIter_dealloc(futureiterobject *it)
986{
Yury Selivanova0c1ba62016-10-28 12:52:37 -0400987 PyObject_GC_UnTrack(it);
INADA Naoki9e4e38e2016-10-09 14:44:47 +0900988 Py_XDECREF(it->future);
989 PyObject_GC_Del(it);
990}
991
992static PyObject *
993FutureIter_iternext(futureiterobject *it)
994{
995 PyObject *res;
996 FutureObj *fut = it->future;
997
998 if (fut == NULL) {
999 return NULL;
1000 }
1001
1002 if (fut->fut_state == STATE_PENDING) {
1003 if (!fut->fut_blocking) {
1004 fut->fut_blocking = 1;
1005 Py_INCREF(fut);
1006 return (PyObject *)fut;
1007 }
1008 PyErr_Format(PyExc_AssertionError,
1009 "yield from wasn't used with future");
1010 return NULL;
1011 }
1012
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001013 res = _asyncio_Future_result_impl(fut);
INADA Naoki9e4e38e2016-10-09 14:44:47 +09001014 if (res != NULL) {
Serhiy Storchaka60e49aa2016-11-06 18:47:03 +02001015 /* The result of the Future is not an exception. */
1016 if (_PyGen_SetStopIterationValue(res) < 0) {
1017 Py_DECREF(res);
Yury Selivanova4b884f2016-10-20 15:54:20 -04001018 return NULL;
1019 }
Serhiy Storchaka60e49aa2016-11-06 18:47:03 +02001020 Py_DECREF(res);
INADA Naoki9e4e38e2016-10-09 14:44:47 +09001021 }
1022
1023 it->future = NULL;
1024 Py_DECREF(fut);
1025 return NULL;
1026}
1027
1028static PyObject *
INADA Naoki74c17532016-10-25 19:00:45 +09001029FutureIter_send(futureiterobject *self, PyObject *unused)
INADA Naoki9e4e38e2016-10-09 14:44:47 +09001030{
INADA Naoki74c17532016-10-25 19:00:45 +09001031 /* Future.__iter__ doesn't care about values that are pushed to the
1032 * generator, it just returns "self.result().
1033 */
INADA Naoki9e4e38e2016-10-09 14:44:47 +09001034 return FutureIter_iternext(self);
1035}
1036
1037static PyObject *
1038FutureIter_throw(futureiterobject *self, PyObject *args)
1039{
1040 PyObject *type=NULL, *val=NULL, *tb=NULL;
1041 if (!PyArg_ParseTuple(args, "O|OO", &type, &val, &tb))
1042 return NULL;
1043
1044 if (val == Py_None) {
1045 val = NULL;
1046 }
1047 if (tb == Py_None) {
1048 tb = NULL;
Benjamin Peterson996fc1f2016-11-14 00:15:44 -08001049 } else if (tb != NULL && !PyTraceBack_Check(tb)) {
1050 PyErr_SetString(PyExc_TypeError, "throw() third argument must be a traceback");
1051 return NULL;
1052 }
1053
1054 Py_INCREF(type);
1055 Py_XINCREF(val);
1056 Py_XINCREF(tb);
1057
1058 if (PyExceptionClass_Check(type)) {
1059 PyErr_NormalizeException(&type, &val, &tb);
Yury Selivanovedfe8862016-12-01 11:37:47 -05001060 /* No need to call PyException_SetTraceback since we'll be calling
1061 PyErr_Restore for `type`, `val`, and `tb`. */
Benjamin Peterson996fc1f2016-11-14 00:15:44 -08001062 } else if (PyExceptionInstance_Check(type)) {
1063 if (val) {
1064 PyErr_SetString(PyExc_TypeError,
1065 "instance exception may not have a separate value");
1066 goto fail;
1067 }
1068 val = type;
1069 type = PyExceptionInstance_Class(type);
1070 Py_INCREF(type);
1071 if (tb == NULL)
1072 tb = PyException_GetTraceback(val);
1073 } else {
1074 PyErr_SetString(PyExc_TypeError,
1075 "exceptions must be classes deriving BaseException or "
1076 "instances of such a class");
1077 goto fail;
INADA Naoki9e4e38e2016-10-09 14:44:47 +09001078 }
1079
1080 Py_CLEAR(self->future);
1081
Benjamin Peterson996fc1f2016-11-14 00:15:44 -08001082 PyErr_Restore(type, val, tb);
1083
INADA Naoki9e4e38e2016-10-09 14:44:47 +09001084 return FutureIter_iternext(self);
Benjamin Peterson996fc1f2016-11-14 00:15:44 -08001085
1086 fail:
1087 Py_DECREF(type);
1088 Py_XDECREF(val);
1089 Py_XDECREF(tb);
1090 return NULL;
INADA Naoki9e4e38e2016-10-09 14:44:47 +09001091}
1092
1093static PyObject *
1094FutureIter_close(futureiterobject *self, PyObject *arg)
1095{
1096 Py_CLEAR(self->future);
1097 Py_RETURN_NONE;
1098}
1099
1100static int
1101FutureIter_traverse(futureiterobject *it, visitproc visit, void *arg)
1102{
1103 Py_VISIT(it->future);
1104 return 0;
1105}
1106
1107static PyMethodDef FutureIter_methods[] = {
1108 {"send", (PyCFunction)FutureIter_send, METH_O, NULL},
1109 {"throw", (PyCFunction)FutureIter_throw, METH_VARARGS, NULL},
1110 {"close", (PyCFunction)FutureIter_close, METH_NOARGS, NULL},
1111 {NULL, NULL} /* Sentinel */
1112};
1113
1114static PyTypeObject FutureIterType = {
Victor Stinner1aea8fb2016-10-28 19:13:52 +02001115 PyVarObject_HEAD_INIT(NULL, 0)
INADA Naoki9f2ce252016-10-15 15:39:19 +09001116 "_asyncio.FutureIter",
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001117 .tp_basicsize = sizeof(futureiterobject),
1118 .tp_itemsize = 0,
1119 .tp_dealloc = (destructor)FutureIter_dealloc,
1120 .tp_getattro = PyObject_GenericGetAttr,
1121 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
1122 .tp_traverse = (traverseproc)FutureIter_traverse,
1123 .tp_iter = PyObject_SelfIter,
1124 .tp_iternext = (iternextfunc)FutureIter_iternext,
1125 .tp_methods = FutureIter_methods,
INADA Naoki9e4e38e2016-10-09 14:44:47 +09001126};
1127
1128static PyObject *
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001129future_new_iter(PyObject *fut)
INADA Naoki9e4e38e2016-10-09 14:44:47 +09001130{
1131 futureiterobject *it;
1132
1133 if (!PyObject_TypeCheck(fut, &FutureType)) {
1134 PyErr_BadInternalCall();
1135 return NULL;
1136 }
1137 it = PyObject_GC_New(futureiterobject, &FutureIterType);
1138 if (it == NULL) {
1139 return NULL;
1140 }
1141 Py_INCREF(fut);
1142 it->future = (FutureObj*)fut;
INADA Naoki1be427b2016-10-11 02:12:34 +09001143 PyObject_GC_Track(it);
INADA Naoki9e4e38e2016-10-09 14:44:47 +09001144 return (PyObject*)it;
1145}
1146
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001147
1148/*********************** Task **************************/
1149
1150
1151/*[clinic input]
1152class _asyncio.Task "TaskObj *" "&Task_Type"
1153[clinic start generated code]*/
1154/*[clinic end generated code: output=da39a3ee5e6b4b0d input=719dcef0fcc03b37]*/
1155
1156static int task_call_step_soon(TaskObj *, PyObject *);
1157static inline PyObject * task_call_wakeup(TaskObj *, PyObject *);
1158static inline PyObject * task_call_step(TaskObj *, PyObject *);
1159static PyObject * task_wakeup(TaskObj *, PyObject *);
1160static PyObject * task_step(TaskObj *, PyObject *);
1161
1162/* ----- Task._step wrapper */
INADA Naoki9e4e38e2016-10-09 14:44:47 +09001163
INADA Naokic411a7d2016-10-18 11:48:14 +09001164static int
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001165TaskSendMethWrapper_clear(TaskSendMethWrapper *o)
INADA Naoki9e4e38e2016-10-09 14:44:47 +09001166{
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001167 Py_CLEAR(o->sw_task);
1168 Py_CLEAR(o->sw_arg);
1169 return 0;
1170}
INADA Naoki9e4e38e2016-10-09 14:44:47 +09001171
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001172static void
1173TaskSendMethWrapper_dealloc(TaskSendMethWrapper *o)
1174{
1175 PyObject_GC_UnTrack(o);
1176 (void)TaskSendMethWrapper_clear(o);
1177 Py_TYPE(o)->tp_free(o);
1178}
1179
1180static PyObject *
1181TaskSendMethWrapper_call(TaskSendMethWrapper *o,
1182 PyObject *args, PyObject *kwds)
1183{
1184 return task_call_step(o->sw_task, o->sw_arg);
1185}
1186
1187static int
1188TaskSendMethWrapper_traverse(TaskSendMethWrapper *o,
1189 visitproc visit, void *arg)
1190{
1191 Py_VISIT(o->sw_task);
1192 Py_VISIT(o->sw_arg);
1193 return 0;
1194}
1195
1196static PyObject *
1197TaskSendMethWrapper_get___self__(TaskSendMethWrapper *o)
1198{
1199 if (o->sw_task) {
1200 Py_INCREF(o->sw_task);
1201 return (PyObject*)o->sw_task;
1202 }
1203 Py_RETURN_NONE;
1204}
1205
1206static PyGetSetDef TaskSendMethWrapper_getsetlist[] = {
1207 {"__self__", (getter)TaskSendMethWrapper_get___self__, NULL, NULL},
1208 {NULL} /* Sentinel */
1209};
1210
1211PyTypeObject TaskSendMethWrapper_Type = {
Victor Stinner1aea8fb2016-10-28 19:13:52 +02001212 PyVarObject_HEAD_INIT(NULL, 0)
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001213 "TaskSendMethWrapper",
1214 .tp_basicsize = sizeof(TaskSendMethWrapper),
1215 .tp_itemsize = 0,
1216 .tp_getset = TaskSendMethWrapper_getsetlist,
1217 .tp_dealloc = (destructor)TaskSendMethWrapper_dealloc,
1218 .tp_call = (ternaryfunc)TaskSendMethWrapper_call,
1219 .tp_getattro = PyObject_GenericGetAttr,
1220 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
1221 .tp_traverse = (traverseproc)TaskSendMethWrapper_traverse,
1222 .tp_clear = (inquiry)TaskSendMethWrapper_clear,
1223};
1224
1225static PyObject *
1226TaskSendMethWrapper_new(TaskObj *task, PyObject *arg)
1227{
1228 TaskSendMethWrapper *o;
1229 o = PyObject_GC_New(TaskSendMethWrapper, &TaskSendMethWrapper_Type);
1230 if (o == NULL) {
1231 return NULL;
1232 }
1233
1234 Py_INCREF(task);
1235 o->sw_task = task;
1236
1237 Py_XINCREF(arg);
1238 o->sw_arg = arg;
1239
1240 PyObject_GC_Track(o);
1241 return (PyObject*) o;
1242}
1243
1244/* ----- Task._wakeup wrapper */
1245
1246static PyObject *
1247TaskWakeupMethWrapper_call(TaskWakeupMethWrapper *o,
1248 PyObject *args, PyObject *kwds)
1249{
1250 PyObject *fut;
1251
1252 if (!PyArg_ParseTuple(args, "O|", &fut)) {
1253 return NULL;
1254 }
1255
1256 return task_call_wakeup(o->ww_task, fut);
1257}
1258
1259static int
1260TaskWakeupMethWrapper_clear(TaskWakeupMethWrapper *o)
1261{
1262 Py_CLEAR(o->ww_task);
1263 return 0;
1264}
1265
1266static int
1267TaskWakeupMethWrapper_traverse(TaskWakeupMethWrapper *o,
1268 visitproc visit, void *arg)
1269{
1270 Py_VISIT(o->ww_task);
1271 return 0;
1272}
1273
1274static void
1275TaskWakeupMethWrapper_dealloc(TaskWakeupMethWrapper *o)
1276{
1277 PyObject_GC_UnTrack(o);
1278 (void)TaskWakeupMethWrapper_clear(o);
1279 Py_TYPE(o)->tp_free(o);
1280}
1281
1282PyTypeObject TaskWakeupMethWrapper_Type = {
Victor Stinner1aea8fb2016-10-28 19:13:52 +02001283 PyVarObject_HEAD_INIT(NULL, 0)
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001284 "TaskWakeupMethWrapper",
1285 .tp_basicsize = sizeof(TaskWakeupMethWrapper),
1286 .tp_itemsize = 0,
1287 .tp_dealloc = (destructor)TaskWakeupMethWrapper_dealloc,
1288 .tp_call = (ternaryfunc)TaskWakeupMethWrapper_call,
1289 .tp_getattro = PyObject_GenericGetAttr,
1290 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
1291 .tp_traverse = (traverseproc)TaskWakeupMethWrapper_traverse,
1292 .tp_clear = (inquiry)TaskWakeupMethWrapper_clear,
1293};
1294
1295static PyObject *
1296TaskWakeupMethWrapper_new(TaskObj *task)
1297{
1298 TaskWakeupMethWrapper *o;
1299 o = PyObject_GC_New(TaskWakeupMethWrapper, &TaskWakeupMethWrapper_Type);
1300 if (o == NULL) {
1301 return NULL;
1302 }
1303
1304 Py_INCREF(task);
1305 o->ww_task = task;
1306
1307 PyObject_GC_Track(o);
1308 return (PyObject*) o;
1309}
1310
1311/* ----- Task */
1312
1313/*[clinic input]
1314_asyncio.Task.__init__
1315
1316 coro: 'O'
1317 *
1318 loop: 'O' = NULL
1319
1320A coroutine wrapped in a Future.
1321[clinic start generated code]*/
1322
1323static int
1324_asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop)
1325/*[clinic end generated code: output=9f24774c2287fc2f input=71d8d28c201a18cd]*/
1326{
1327 PyObject *res;
1328 _Py_IDENTIFIER(add);
1329
1330 if (future_init((FutureObj*)self, loop)) {
INADA Naokic411a7d2016-10-18 11:48:14 +09001331 return -1;
1332 }
INADA Naokic411a7d2016-10-18 11:48:14 +09001333
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001334 self->task_fut_waiter = NULL;
1335 self->task_must_cancel = 0;
1336 self->task_log_destroy_pending = 1;
INADA Naokic411a7d2016-10-18 11:48:14 +09001337
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001338 Py_INCREF(coro);
1339 self->task_coro = coro;
1340
1341 if (task_call_step_soon(self, NULL)) {
1342 return -1;
INADA Naokic411a7d2016-10-18 11:48:14 +09001343 }
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001344
Victor Stinnerb6ed57d2016-12-09 14:24:02 +01001345 res = _PyObject_CallMethodIdObjArgs(all_tasks, &PyId_add, self, NULL);
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001346 if (res == NULL) {
1347 return -1;
1348 }
1349 Py_DECREF(res);
1350
1351 return 0;
1352}
1353
1354static int
1355TaskObj_clear(TaskObj *task)
1356{
1357 (void)FutureObj_clear((FutureObj*) task);
1358 Py_CLEAR(task->task_coro);
1359 Py_CLEAR(task->task_fut_waiter);
1360 return 0;
1361}
1362
1363static int
1364TaskObj_traverse(TaskObj *task, visitproc visit, void *arg)
1365{
1366 Py_VISIT(task->task_coro);
1367 Py_VISIT(task->task_fut_waiter);
1368 (void)FutureObj_traverse((FutureObj*) task, visit, arg);
1369 return 0;
1370}
1371
1372static PyObject *
1373TaskObj_get_log_destroy_pending(TaskObj *task)
1374{
1375 if (task->task_log_destroy_pending) {
1376 Py_RETURN_TRUE;
1377 }
1378 else {
1379 Py_RETURN_FALSE;
1380 }
1381}
1382
1383static int
1384TaskObj_set_log_destroy_pending(TaskObj *task, PyObject *val)
1385{
1386 int is_true = PyObject_IsTrue(val);
1387 if (is_true < 0) {
1388 return -1;
1389 }
1390 task->task_log_destroy_pending = is_true;
1391 return 0;
1392}
1393
1394static PyObject *
1395TaskObj_get_must_cancel(TaskObj *task)
1396{
1397 if (task->task_must_cancel) {
1398 Py_RETURN_TRUE;
1399 }
1400 else {
1401 Py_RETURN_FALSE;
1402 }
1403}
1404
1405static PyObject *
1406TaskObj_get_coro(TaskObj *task)
1407{
1408 if (task->task_coro) {
1409 Py_INCREF(task->task_coro);
1410 return task->task_coro;
1411 }
1412
1413 Py_RETURN_NONE;
1414}
1415
1416static PyObject *
1417TaskObj_get_fut_waiter(TaskObj *task)
1418{
1419 if (task->task_fut_waiter) {
1420 Py_INCREF(task->task_fut_waiter);
1421 return task->task_fut_waiter;
1422 }
1423
1424 Py_RETURN_NONE;
1425}
1426
1427/*[clinic input]
1428@classmethod
1429_asyncio.Task.current_task
1430
Yury Selivanov8d26aa92017-03-02 22:16:33 -05001431 loop: 'O' = None
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001432
1433Return the currently running task in an event loop or None.
1434
1435By default the current task for the current event loop is returned.
1436
1437None is returned when called not in the context of a Task.
1438[clinic start generated code]*/
1439
1440static PyObject *
1441_asyncio_Task_current_task_impl(PyTypeObject *type, PyObject *loop)
Yury Selivanov8d26aa92017-03-02 22:16:33 -05001442/*[clinic end generated code: output=99fbe7332c516e03 input=a0d6cdf2e3b243e1]*/
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001443{
1444 PyObject *res;
1445
Yury Selivanov8d26aa92017-03-02 22:16:33 -05001446 if (loop == Py_None) {
Victor Stinnera5ed5f02016-12-06 18:45:50 +01001447 loop = _PyObject_CallNoArg(asyncio_get_event_loop);
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001448 if (loop == NULL) {
1449 return NULL;
1450 }
1451
Yury Selivanov684ef2c2016-10-28 19:01:21 -04001452 res = PyDict_GetItem(current_tasks, loop);
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001453 Py_DECREF(loop);
1454 }
1455 else {
Yury Selivanov684ef2c2016-10-28 19:01:21 -04001456 res = PyDict_GetItem(current_tasks, loop);
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001457 }
1458
1459 if (res == NULL) {
1460 Py_RETURN_NONE;
1461 }
1462 else {
1463 Py_INCREF(res);
1464 return res;
1465 }
1466}
1467
1468static PyObject *
1469task_all_tasks(PyObject *loop)
1470{
1471 PyObject *task;
1472 PyObject *task_loop;
1473 PyObject *set;
1474 PyObject *iter;
1475
1476 assert(loop != NULL);
1477
1478 set = PySet_New(NULL);
1479 if (set == NULL) {
1480 return NULL;
1481 }
1482
1483 iter = PyObject_GetIter(all_tasks);
1484 if (iter == NULL) {
INADA Naokic411a7d2016-10-18 11:48:14 +09001485 goto fail;
INADA Naoki9e4e38e2016-10-09 14:44:47 +09001486 }
1487
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001488 while ((task = PyIter_Next(iter))) {
1489 task_loop = PyObject_GetAttrString(task, "_loop");
1490 if (task_loop == NULL) {
1491 Py_DECREF(task);
1492 goto fail;
1493 }
1494 if (task_loop == loop) {
1495 if (PySet_Add(set, task) == -1) {
1496 Py_DECREF(task_loop);
1497 Py_DECREF(task);
1498 goto fail;
1499 }
1500 }
1501 Py_DECREF(task_loop);
1502 Py_DECREF(task);
1503 }
1504
1505 Py_DECREF(iter);
1506 return set;
1507
1508fail:
1509 Py_XDECREF(set);
1510 Py_XDECREF(iter);
1511 return NULL;
1512}
1513
1514/*[clinic input]
1515@classmethod
1516_asyncio.Task.all_tasks
1517
Yury Selivanov8d26aa92017-03-02 22:16:33 -05001518 loop: 'O' = None
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001519
1520Return a set of all tasks for an event loop.
1521
1522By default all tasks for the current event loop are returned.
1523[clinic start generated code]*/
1524
1525static PyObject *
1526_asyncio_Task_all_tasks_impl(PyTypeObject *type, PyObject *loop)
Yury Selivanov8d26aa92017-03-02 22:16:33 -05001527/*[clinic end generated code: output=11f9b20749ccca5d input=c6f5b53bd487488f]*/
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001528{
1529 PyObject *res;
1530
Yury Selivanov8d26aa92017-03-02 22:16:33 -05001531 if (loop == Py_None) {
Victor Stinnera5ed5f02016-12-06 18:45:50 +01001532 loop = _PyObject_CallNoArg(asyncio_get_event_loop);
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001533 if (loop == NULL) {
1534 return NULL;
1535 }
1536
1537 res = task_all_tasks(loop);
1538 Py_DECREF(loop);
1539 }
1540 else {
1541 res = task_all_tasks(loop);
1542 }
1543
1544 return res;
1545}
1546
1547/*[clinic input]
1548_asyncio.Task._repr_info
1549[clinic start generated code]*/
1550
1551static PyObject *
1552_asyncio_Task__repr_info_impl(TaskObj *self)
1553/*[clinic end generated code: output=6a490eb66d5ba34b input=3c6d051ed3ddec8b]*/
1554{
Victor Stinnerde4ae3d2016-12-04 22:59:09 +01001555 return PyObject_CallFunctionObjArgs(
1556 asyncio_task_repr_info_func, self, NULL);
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001557}
1558
1559/*[clinic input]
1560_asyncio.Task.cancel
1561
1562Request that this task cancel itself.
1563
1564This arranges for a CancelledError to be thrown into the
1565wrapped coroutine on the next cycle through the event loop.
1566The coroutine then has a chance to clean up or even deny
1567the request using try/except/finally.
1568
1569Unlike Future.cancel, this does not guarantee that the
1570task will be cancelled: the exception might be caught and
1571acted upon, delaying cancellation of the task or preventing
1572cancellation completely. The task may also return a value or
1573raise a different exception.
1574
1575Immediately after this method is called, Task.cancelled() will
1576not return True (unless the task was already cancelled). A
1577task will be marked as cancelled when the wrapped coroutine
1578terminates with a CancelledError exception (even if cancel()
1579was not called).
1580[clinic start generated code]*/
1581
1582static PyObject *
1583_asyncio_Task_cancel_impl(TaskObj *self)
1584/*[clinic end generated code: output=6bfc0479da9d5757 input=13f9bf496695cb52]*/
1585{
Yury Selivanov7ce1c6f2017-06-11 13:49:18 +00001586 self->task_log_tb = 0;
1587
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001588 if (self->task_state != STATE_PENDING) {
1589 Py_RETURN_FALSE;
1590 }
1591
1592 if (self->task_fut_waiter) {
1593 PyObject *res;
1594 int is_true;
1595
1596 res = _PyObject_CallMethodId(
1597 self->task_fut_waiter, &PyId_cancel, NULL);
1598 if (res == NULL) {
1599 return NULL;
1600 }
1601
1602 is_true = PyObject_IsTrue(res);
1603 Py_DECREF(res);
1604 if (is_true < 0) {
1605 return NULL;
1606 }
1607
1608 if (is_true) {
1609 Py_RETURN_TRUE;
1610 }
1611 }
1612
1613 self->task_must_cancel = 1;
1614 Py_RETURN_TRUE;
1615}
1616
1617/*[clinic input]
1618_asyncio.Task.get_stack
1619
1620 *
1621 limit: 'O' = None
1622
1623Return the list of stack frames for this task's coroutine.
1624
1625If the coroutine is not done, this returns the stack where it is
1626suspended. If the coroutine has completed successfully or was
1627cancelled, this returns an empty list. If the coroutine was
1628terminated by an exception, this returns the list of traceback
1629frames.
1630
1631The frames are always ordered from oldest to newest.
1632
1633The optional limit gives the maximum number of frames to
1634return; by default all available frames are returned. Its
1635meaning differs depending on whether a stack or a traceback is
1636returned: the newest frames of a stack are returned, but the
1637oldest frames of a traceback are returned. (This matches the
1638behavior of the traceback module.)
1639
1640For reasons beyond our control, only one stack frame is
1641returned for a suspended coroutine.
1642[clinic start generated code]*/
1643
1644static PyObject *
1645_asyncio_Task_get_stack_impl(TaskObj *self, PyObject *limit)
1646/*[clinic end generated code: output=c9aeeeebd1e18118 input=b1920230a766d17a]*/
1647{
1648 return PyObject_CallFunctionObjArgs(
1649 asyncio_task_get_stack_func, self, limit, NULL);
1650}
1651
1652/*[clinic input]
1653_asyncio.Task.print_stack
1654
1655 *
1656 limit: 'O' = None
1657 file: 'O' = None
1658
1659Print the stack or traceback for this task's coroutine.
1660
1661This produces output similar to that of the traceback module,
1662for the frames retrieved by get_stack(). The limit argument
1663is passed to get_stack(). The file argument is an I/O stream
1664to which the output is written; by default output is written
1665to sys.stderr.
1666[clinic start generated code]*/
1667
1668static PyObject *
1669_asyncio_Task_print_stack_impl(TaskObj *self, PyObject *limit,
1670 PyObject *file)
1671/*[clinic end generated code: output=7339e10314cd3f4d input=19f1e99ab5400bc3]*/
1672{
1673 return PyObject_CallFunctionObjArgs(
1674 asyncio_task_print_stack_func, self, limit, file, NULL);
1675}
1676
1677/*[clinic input]
1678_asyncio.Task._step
1679
1680 exc: 'O' = NULL
1681[clinic start generated code]*/
1682
1683static PyObject *
1684_asyncio_Task__step_impl(TaskObj *self, PyObject *exc)
1685/*[clinic end generated code: output=7ed23f0cefd5ae42 input=ada4b2324e5370af]*/
1686{
1687 return task_step(self, exc == Py_None ? NULL : exc);
1688}
1689
1690/*[clinic input]
1691_asyncio.Task._wakeup
1692
1693 fut: 'O'
1694[clinic start generated code]*/
1695
1696static PyObject *
1697_asyncio_Task__wakeup_impl(TaskObj *self, PyObject *fut)
1698/*[clinic end generated code: output=75cb341c760fd071 input=11ee4918a5bdbf21]*/
1699{
1700 return task_wakeup(self, fut);
1701}
1702
1703static void
1704TaskObj_finalize(TaskObj *task)
1705{
1706 _Py_IDENTIFIER(call_exception_handler);
1707 _Py_IDENTIFIER(task);
1708 _Py_IDENTIFIER(message);
1709 _Py_IDENTIFIER(source_traceback);
1710
1711 PyObject *message = NULL;
1712 PyObject *context = NULL;
1713 PyObject *func = NULL;
1714 PyObject *res = NULL;
1715
1716 PyObject *error_type, *error_value, *error_traceback;
1717
1718 if (task->task_state != STATE_PENDING || !task->task_log_destroy_pending) {
1719 goto done;
1720 }
1721
1722 /* Save the current exception, if any. */
1723 PyErr_Fetch(&error_type, &error_value, &error_traceback);
1724
1725 context = PyDict_New();
1726 if (context == NULL) {
1727 goto finally;
1728 }
1729
1730 message = PyUnicode_FromString("Task was destroyed but it is pending!");
1731 if (message == NULL) {
1732 goto finally;
1733 }
1734
1735 if (_PyDict_SetItemId(context, &PyId_message, message) < 0 ||
1736 _PyDict_SetItemId(context, &PyId_task, (PyObject*)task) < 0)
1737 {
1738 goto finally;
1739 }
1740
1741 if (task->task_source_tb != NULL) {
1742 if (_PyDict_SetItemId(context, &PyId_source_traceback,
1743 task->task_source_tb) < 0)
1744 {
1745 goto finally;
1746 }
1747 }
1748
1749 func = _PyObject_GetAttrId(task->task_loop, &PyId_call_exception_handler);
1750 if (func != NULL) {
Victor Stinner7bfb42d2016-12-05 17:04:32 +01001751 res = PyObject_CallFunctionObjArgs(func, context, NULL);
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001752 if (res == NULL) {
1753 PyErr_WriteUnraisable(func);
1754 }
1755 }
1756
1757finally:
1758 Py_CLEAR(context);
1759 Py_CLEAR(message);
1760 Py_CLEAR(func);
1761 Py_CLEAR(res);
1762
1763 /* Restore the saved exception. */
1764 PyErr_Restore(error_type, error_value, error_traceback);
1765
1766done:
1767 FutureObj_finalize((FutureObj*)task);
1768}
1769
1770static void TaskObj_dealloc(PyObject *); /* Needs Task_CheckExact */
1771
1772static PyMethodDef TaskType_methods[] = {
1773 _ASYNCIO_FUTURE_RESULT_METHODDEF
1774 _ASYNCIO_FUTURE_EXCEPTION_METHODDEF
1775 _ASYNCIO_FUTURE_SET_RESULT_METHODDEF
1776 _ASYNCIO_FUTURE_SET_EXCEPTION_METHODDEF
1777 _ASYNCIO_FUTURE_ADD_DONE_CALLBACK_METHODDEF
1778 _ASYNCIO_FUTURE_REMOVE_DONE_CALLBACK_METHODDEF
1779 _ASYNCIO_FUTURE_CANCELLED_METHODDEF
1780 _ASYNCIO_FUTURE_DONE_METHODDEF
1781 _ASYNCIO_TASK_CURRENT_TASK_METHODDEF
1782 _ASYNCIO_TASK_ALL_TASKS_METHODDEF
1783 _ASYNCIO_TASK_CANCEL_METHODDEF
1784 _ASYNCIO_TASK_GET_STACK_METHODDEF
1785 _ASYNCIO_TASK_PRINT_STACK_METHODDEF
1786 _ASYNCIO_TASK__WAKEUP_METHODDEF
1787 _ASYNCIO_TASK__STEP_METHODDEF
1788 _ASYNCIO_TASK__REPR_INFO_METHODDEF
1789 {NULL, NULL} /* Sentinel */
1790};
1791
1792static PyGetSetDef TaskType_getsetlist[] = {
1793 FUTURE_COMMON_GETSETLIST
1794 {"_log_destroy_pending", (getter)TaskObj_get_log_destroy_pending,
1795 (setter)TaskObj_set_log_destroy_pending, NULL},
1796 {"_must_cancel", (getter)TaskObj_get_must_cancel, NULL, NULL},
1797 {"_coro", (getter)TaskObj_get_coro, NULL, NULL},
1798 {"_fut_waiter", (getter)TaskObj_get_fut_waiter, NULL, NULL},
1799 {NULL} /* Sentinel */
1800};
1801
1802static PyTypeObject TaskType = {
Victor Stinner1aea8fb2016-10-28 19:13:52 +02001803 PyVarObject_HEAD_INIT(NULL, 0)
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001804 "_asyncio.Task",
1805 sizeof(TaskObj), /* tp_basicsize */
1806 .tp_base = &FutureType,
1807 .tp_dealloc = TaskObj_dealloc,
1808 .tp_as_async = &FutureType_as_async,
1809 .tp_repr = (reprfunc)FutureObj_repr,
1810 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE
1811 | Py_TPFLAGS_HAVE_FINALIZE,
1812 .tp_doc = _asyncio_Task___init____doc__,
1813 .tp_traverse = (traverseproc)TaskObj_traverse,
1814 .tp_clear = (inquiry)TaskObj_clear,
1815 .tp_weaklistoffset = offsetof(TaskObj, task_weakreflist),
1816 .tp_iter = (getiterfunc)future_new_iter,
1817 .tp_methods = TaskType_methods,
1818 .tp_getset = TaskType_getsetlist,
1819 .tp_dictoffset = offsetof(TaskObj, dict),
1820 .tp_init = (initproc)_asyncio_Task___init__,
1821 .tp_new = PyType_GenericNew,
1822 .tp_finalize = (destructor)TaskObj_finalize,
1823};
1824
1825#define Task_CheckExact(obj) (Py_TYPE(obj) == &TaskType)
1826
1827static void
1828TaskObj_dealloc(PyObject *self)
1829{
1830 TaskObj *task = (TaskObj *)self;
1831
1832 if (Task_CheckExact(self)) {
1833 /* When fut is subclass of Task, finalizer is called from
1834 * subtype_dealloc.
1835 */
1836 if (PyObject_CallFinalizerFromDealloc(self) < 0) {
1837 // resurrected.
1838 return;
1839 }
1840 }
1841
1842 if (task->task_weakreflist != NULL) {
1843 PyObject_ClearWeakRefs(self);
1844 }
1845
1846 (void)TaskObj_clear(task);
1847 Py_TYPE(task)->tp_free(task);
1848}
1849
1850static inline PyObject *
1851task_call_wakeup(TaskObj *task, PyObject *fut)
1852{
1853 if (Task_CheckExact(task)) {
1854 return task_wakeup(task, fut);
1855 }
1856 else {
1857 /* `task` is a subclass of Task */
Victor Stinnerb6ed57d2016-12-09 14:24:02 +01001858 return _PyObject_CallMethodIdObjArgs((PyObject*)task, &PyId__wakeup,
1859 fut, NULL);
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001860 }
1861}
1862
1863static inline PyObject *
1864task_call_step(TaskObj *task, PyObject *arg)
1865{
1866 if (Task_CheckExact(task)) {
1867 return task_step(task, arg);
1868 }
1869 else {
1870 /* `task` is a subclass of Task */
1871 if (arg == NULL) {
1872 arg = Py_None;
1873 }
Victor Stinnerb6ed57d2016-12-09 14:24:02 +01001874 return _PyObject_CallMethodIdObjArgs((PyObject*)task, &PyId__step,
1875 arg, NULL);
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001876 }
1877}
1878
1879static int
1880task_call_step_soon(TaskObj *task, PyObject *arg)
1881{
1882 PyObject *handle;
1883
1884 PyObject *cb = TaskSendMethWrapper_new(task, arg);
1885 if (cb == NULL) {
1886 return -1;
1887 }
1888
Victor Stinnerb6ed57d2016-12-09 14:24:02 +01001889 handle = _PyObject_CallMethodIdObjArgs(task->task_loop, &PyId_call_soon,
1890 cb, NULL);
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001891 Py_DECREF(cb);
1892 if (handle == NULL) {
1893 return -1;
1894 }
1895
1896 Py_DECREF(handle);
1897 return 0;
1898}
1899
1900static PyObject *
1901task_set_error_soon(TaskObj *task, PyObject *et, const char *format, ...)
1902{
1903 PyObject* msg;
1904
1905 va_list vargs;
1906#ifdef HAVE_STDARG_PROTOTYPES
1907 va_start(vargs, format);
1908#else
1909 va_start(vargs);
1910#endif
1911 msg = PyUnicode_FromFormatV(format, vargs);
1912 va_end(vargs);
1913
1914 if (msg == NULL) {
1915 return NULL;
1916 }
1917
Victor Stinnerde4ae3d2016-12-04 22:59:09 +01001918 PyObject *e = PyObject_CallFunctionObjArgs(et, msg, NULL);
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001919 Py_DECREF(msg);
1920 if (e == NULL) {
1921 return NULL;
1922 }
1923
1924 if (task_call_step_soon(task, e) == -1) {
1925 Py_DECREF(e);
1926 return NULL;
1927 }
1928
1929 Py_DECREF(e);
1930 Py_RETURN_NONE;
1931}
1932
1933static PyObject *
1934task_step_impl(TaskObj *task, PyObject *exc)
1935{
1936 int res;
1937 int clear_exc = 0;
1938 PyObject *result = NULL;
1939 PyObject *coro = task->task_coro;
1940 PyObject *o;
1941
1942 if (task->task_state != STATE_PENDING) {
1943 PyErr_Format(PyExc_AssertionError,
1944 "_step(): already done: %R %R",
1945 task,
1946 exc ? exc : Py_None);
INADA Naokic411a7d2016-10-18 11:48:14 +09001947 goto fail;
1948 }
INADA Naoki9e4e38e2016-10-09 14:44:47 +09001949
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001950 if (task->task_must_cancel) {
1951 assert(exc != Py_None);
1952
1953 if (exc) {
1954 /* Check if exc is a CancelledError */
1955 res = PyObject_IsInstance(exc, asyncio_CancelledError);
1956 if (res == -1) {
1957 /* An error occurred, abort */
1958 goto fail;
1959 }
1960 if (res == 0) {
1961 /* exc is not CancelledError; reset it to NULL */
1962 exc = NULL;
1963 }
1964 }
1965
1966 if (!exc) {
1967 /* exc was not a CancelledError */
Victor Stinnerf17c3de2016-12-06 18:46:19 +01001968 exc = _PyObject_CallNoArg(asyncio_CancelledError);
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001969 if (!exc) {
1970 goto fail;
1971 }
1972 clear_exc = 1;
1973 }
1974
1975 task->task_must_cancel = 0;
1976 }
1977
1978 Py_CLEAR(task->task_fut_waiter);
1979
1980 if (exc == NULL) {
1981 if (PyGen_CheckExact(coro) || PyCoro_CheckExact(coro)) {
1982 result = _PyGen_Send((PyGenObject*)coro, Py_None);
1983 }
1984 else {
Victor Stinnerb6ed57d2016-12-09 14:24:02 +01001985 result = _PyObject_CallMethodIdObjArgs(coro, &PyId_send,
1986 Py_None, NULL);
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001987 }
1988 }
1989 else {
Victor Stinnerb6ed57d2016-12-09 14:24:02 +01001990 result = _PyObject_CallMethodIdObjArgs(coro, &PyId_throw,
1991 exc, NULL);
Yury Selivanova0c1ba62016-10-28 12:52:37 -04001992 if (clear_exc) {
1993 /* We created 'exc' during this call */
1994 Py_CLEAR(exc);
1995 }
1996 }
1997
1998 if (result == NULL) {
1999 PyObject *et, *ev, *tb;
2000
2001 if (_PyGen_FetchStopIterationValue(&o) == 0) {
2002 /* The error is StopIteration and that means that
2003 the underlying coroutine has resolved */
INADA Naoki991adca2017-05-11 21:18:38 +09002004 if (task->task_must_cancel) {
2005 // Task is cancelled right before coro stops.
2006 Py_DECREF(o);
2007 task->task_must_cancel = 0;
2008 et = asyncio_CancelledError;
2009 Py_INCREF(et);
2010 ev = NULL;
2011 tb = NULL;
2012 goto set_exception;
2013 }
Yury Selivanova0c1ba62016-10-28 12:52:37 -04002014 PyObject *res = future_set_result((FutureObj*)task, o);
2015 Py_DECREF(o);
2016 if (res == NULL) {
2017 return NULL;
2018 }
2019 Py_DECREF(res);
2020 Py_RETURN_NONE;
2021 }
2022
2023 if (PyErr_ExceptionMatches(asyncio_CancelledError)) {
2024 /* CancelledError */
2025 PyErr_Clear();
2026 return future_cancel((FutureObj*)task);
2027 }
2028
2029 /* Some other exception; pop it and call Task.set_exception() */
2030 PyErr_Fetch(&et, &ev, &tb);
INADA Naoki991adca2017-05-11 21:18:38 +09002031
2032set_exception:
Yury Selivanova0c1ba62016-10-28 12:52:37 -04002033 assert(et);
2034 if (!ev || !PyObject_TypeCheck(ev, (PyTypeObject *) et)) {
2035 PyErr_NormalizeException(&et, &ev, &tb);
2036 }
Yury Selivanovedfe8862016-12-01 11:37:47 -05002037 if (tb != NULL) {
2038 PyException_SetTraceback(ev, tb);
2039 }
Yury Selivanova0c1ba62016-10-28 12:52:37 -04002040 o = future_set_exception((FutureObj*)task, ev);
2041 if (!o) {
2042 /* An exception in Task.set_exception() */
2043 Py_XDECREF(et);
2044 Py_XDECREF(tb);
2045 Py_XDECREF(ev);
2046 goto fail;
2047 }
2048 assert(o == Py_None);
2049 Py_CLEAR(o);
2050
2051 if (!PyErr_GivenExceptionMatches(et, PyExc_Exception)) {
2052 /* We've got a BaseException; re-raise it */
2053 PyErr_Restore(et, ev, tb);
2054 goto fail;
2055 }
2056
2057 Py_XDECREF(et);
2058 Py_XDECREF(tb);
2059 Py_XDECREF(ev);
2060
2061 Py_RETURN_NONE;
2062 }
2063
2064 if (result == (PyObject*)task) {
2065 /* We have a task that wants to await on itself */
2066 goto self_await;
2067 }
2068
2069 /* Check if `result` is FutureObj or TaskObj (and not a subclass) */
2070 if (Future_CheckExact(result) || Task_CheckExact(result)) {
2071 PyObject *wrapper;
2072 PyObject *res;
2073 FutureObj *fut = (FutureObj*)result;
2074
2075 /* Check if `result` future is attached to a different loop */
2076 if (fut->fut_loop != task->task_loop) {
2077 goto different_loop;
2078 }
2079
2080 if (fut->fut_blocking) {
2081 fut->fut_blocking = 0;
2082
2083 /* result.add_done_callback(task._wakeup) */
2084 wrapper = TaskWakeupMethWrapper_new(task);
2085 if (wrapper == NULL) {
2086 goto fail;
2087 }
2088 res = future_add_done_callback((FutureObj*)result, wrapper);
2089 Py_DECREF(wrapper);
2090 if (res == NULL) {
2091 goto fail;
2092 }
2093 Py_DECREF(res);
2094
2095 /* task._fut_waiter = result */
2096 task->task_fut_waiter = result; /* no incref is necessary */
2097
2098 if (task->task_must_cancel) {
2099 PyObject *r;
2100 r = future_cancel(fut);
2101 if (r == NULL) {
2102 return NULL;
2103 }
2104 if (r == Py_True) {
2105 task->task_must_cancel = 0;
2106 }
2107 Py_DECREF(r);
2108 }
2109
2110 Py_RETURN_NONE;
2111 }
2112 else {
2113 goto yield_insteadof_yf;
2114 }
2115 }
2116
2117 /* Check if `result` is a Future-compatible object */
2118 o = PyObject_GetAttrString(result, "_asyncio_future_blocking");
2119 if (o == NULL) {
2120 if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
2121 PyErr_Clear();
2122 }
2123 else {
2124 goto fail;
2125 }
2126 }
2127 else {
2128 if (o == Py_None) {
2129 Py_CLEAR(o);
2130 }
2131 else {
2132 /* `result` is a Future-compatible object */
2133 PyObject *wrapper;
2134 PyObject *res;
2135
2136 int blocking = PyObject_IsTrue(o);
2137 Py_CLEAR(o);
2138 if (blocking < 0) {
2139 goto fail;
2140 }
2141
2142 /* Check if `result` future is attached to a different loop */
2143 PyObject *oloop = PyObject_GetAttrString(result, "_loop");
2144 if (oloop == NULL) {
2145 goto fail;
2146 }
2147 if (oloop != task->task_loop) {
2148 Py_DECREF(oloop);
2149 goto different_loop;
2150 }
2151 else {
2152 Py_DECREF(oloop);
2153 }
2154
2155 if (blocking) {
2156 /* result._asyncio_future_blocking = False */
2157 if (PyObject_SetAttrString(
2158 result, "_asyncio_future_blocking", Py_False) == -1) {
2159 goto fail;
2160 }
2161
2162 /* result.add_done_callback(task._wakeup) */
2163 wrapper = TaskWakeupMethWrapper_new(task);
2164 if (wrapper == NULL) {
2165 goto fail;
2166 }
Victor Stinnerb6ed57d2016-12-09 14:24:02 +01002167 res = _PyObject_CallMethodIdObjArgs(result,
2168 &PyId_add_done_callback,
2169 wrapper, NULL);
Yury Selivanova0c1ba62016-10-28 12:52:37 -04002170 Py_DECREF(wrapper);
2171 if (res == NULL) {
2172 goto fail;
2173 }
2174 Py_DECREF(res);
2175
2176 /* task._fut_waiter = result */
2177 task->task_fut_waiter = result; /* no incref is necessary */
2178
2179 if (task->task_must_cancel) {
2180 PyObject *r;
2181 int is_true;
2182 r = _PyObject_CallMethodId(result, &PyId_cancel, NULL);
2183 if (r == NULL) {
2184 return NULL;
2185 }
2186 is_true = PyObject_IsTrue(r);
2187 Py_DECREF(r);
2188 if (is_true < 0) {
2189 return NULL;
2190 }
2191 else if (is_true) {
2192 task->task_must_cancel = 0;
2193 }
2194 }
2195
2196 Py_RETURN_NONE;
2197 }
2198 else {
2199 goto yield_insteadof_yf;
2200 }
2201 }
2202 }
2203
2204 /* Check if `result` is None */
2205 if (result == Py_None) {
2206 /* Bare yield relinquishes control for one event loop iteration. */
2207 if (task_call_step_soon(task, NULL)) {
2208 goto fail;
2209 }
2210 return result;
2211 }
2212
2213 /* Check if `result` is a generator */
Victor Stinnerde4ae3d2016-12-04 22:59:09 +01002214 o = PyObject_CallFunctionObjArgs(inspect_isgenerator, result, NULL);
Yury Selivanova0c1ba62016-10-28 12:52:37 -04002215 if (o == NULL) {
2216 /* An exception in inspect.isgenerator */
2217 goto fail;
2218 }
2219 res = PyObject_IsTrue(o);
2220 Py_CLEAR(o);
2221 if (res == -1) {
2222 /* An exception while checking if 'val' is True */
2223 goto fail;
2224 }
2225 if (res == 1) {
2226 /* `result` is a generator */
2227 PyObject *ret;
2228 ret = task_set_error_soon(
2229 task, PyExc_RuntimeError,
2230 "yield was used instead of yield from for "
2231 "generator in task %R with %S", task, result);
2232 Py_DECREF(result);
2233 return ret;
2234 }
2235
2236 /* The `result` is none of the above */
2237 Py_DECREF(result);
2238 return task_set_error_soon(
2239 task, PyExc_RuntimeError, "Task got bad yield: %R", result);
2240
2241self_await:
2242 o = task_set_error_soon(
2243 task, PyExc_RuntimeError,
2244 "Task cannot await on itself: %R", task);
2245 Py_DECREF(result);
2246 return o;
2247
2248yield_insteadof_yf:
2249 o = task_set_error_soon(
2250 task, PyExc_RuntimeError,
2251 "yield was used instead of yield from "
2252 "in task %R with %R",
2253 task, result);
2254 Py_DECREF(result);
2255 return o;
2256
2257different_loop:
2258 o = task_set_error_soon(
2259 task, PyExc_RuntimeError,
2260 "Task %R got Future %R attached to a different loop",
2261 task, result);
2262 Py_DECREF(result);
2263 return o;
2264
2265fail:
2266 Py_XDECREF(result);
2267 return NULL;
2268}
2269
2270static PyObject *
2271task_step(TaskObj *task, PyObject *exc)
2272{
2273 PyObject *res;
2274 PyObject *ot;
2275
Yury Selivanov684ef2c2016-10-28 19:01:21 -04002276 if (PyDict_SetItem(current_tasks,
Yury Selivanova0c1ba62016-10-28 12:52:37 -04002277 task->task_loop, (PyObject*)task) == -1)
2278 {
2279 return NULL;
2280 }
2281
2282 res = task_step_impl(task, exc);
2283
2284 if (res == NULL) {
2285 PyObject *et, *ev, *tb;
2286 PyErr_Fetch(&et, &ev, &tb);
2287 ot = _PyDict_Pop(current_tasks, task->task_loop, NULL);
2288 if (ot == NULL) {
2289 Py_XDECREF(et);
2290 Py_XDECREF(tb);
2291 Py_XDECREF(ev);
2292 return NULL;
2293 }
2294 Py_DECREF(ot);
2295 PyErr_Restore(et, ev, tb);
2296 return NULL;
2297 }
2298 else {
2299 ot = _PyDict_Pop(current_tasks, task->task_loop, NULL);
2300 if (ot == NULL) {
2301 Py_DECREF(res);
2302 return NULL;
2303 }
2304 else {
2305 Py_DECREF(ot);
2306 return res;
2307 }
2308 }
2309}
2310
2311static PyObject *
2312task_wakeup(TaskObj *task, PyObject *o)
2313{
2314 assert(o);
2315
2316 if (Future_CheckExact(o) || Task_CheckExact(o)) {
2317 PyObject *fut_result = NULL;
2318 int res = future_get_result((FutureObj*)o, &fut_result);
2319 PyObject *result;
2320
2321 switch(res) {
2322 case -1:
2323 assert(fut_result == NULL);
2324 return NULL;
2325 case 0:
2326 Py_DECREF(fut_result);
2327 return task_call_step(task, NULL);
2328 default:
2329 assert(res == 1);
2330 result = task_call_step(task, fut_result);
2331 Py_DECREF(fut_result);
2332 return result;
2333 }
2334 }
2335
2336 PyObject *fut_result = PyObject_CallMethod(o, "result", NULL);
2337 if (fut_result == NULL) {
2338 PyObject *et, *ev, *tb;
2339 PyObject *res;
2340
2341 PyErr_Fetch(&et, &ev, &tb);
2342 if (!ev || !PyObject_TypeCheck(ev, (PyTypeObject *) et)) {
2343 PyErr_NormalizeException(&et, &ev, &tb);
2344 }
2345
2346 res = task_call_step(task, ev);
2347
2348 Py_XDECREF(et);
2349 Py_XDECREF(tb);
2350 Py_XDECREF(ev);
2351
2352 return res;
2353 }
2354 else {
2355 Py_DECREF(fut_result);
2356 return task_call_step(task, NULL);
2357 }
2358}
2359
2360
2361/*********************** Module **************************/
2362
2363
2364static void
2365module_free(void *m)
2366{
2367 Py_CLEAR(current_tasks);
2368 Py_CLEAR(all_tasks);
2369 Py_CLEAR(traceback_extract_stack);
2370 Py_CLEAR(asyncio_get_event_loop);
2371 Py_CLEAR(asyncio_future_repr_info_func);
2372 Py_CLEAR(asyncio_task_repr_info_func);
2373 Py_CLEAR(asyncio_task_get_stack_func);
2374 Py_CLEAR(asyncio_task_print_stack_func);
2375 Py_CLEAR(asyncio_InvalidStateError);
2376 Py_CLEAR(asyncio_CancelledError);
2377 Py_CLEAR(inspect_isgenerator);
2378}
2379
2380static int
2381module_init(void)
2382{
2383 PyObject *module = NULL;
2384 PyObject *cls;
2385
2386#define WITH_MOD(NAME) \
2387 Py_CLEAR(module); \
2388 module = PyImport_ImportModule(NAME); \
2389 if (module == NULL) { \
2390 return -1; \
2391 }
2392
2393#define GET_MOD_ATTR(VAR, NAME) \
2394 VAR = PyObject_GetAttrString(module, NAME); \
2395 if (VAR == NULL) { \
2396 goto fail; \
2397 }
2398
2399 WITH_MOD("asyncio.events")
2400 GET_MOD_ATTR(asyncio_get_event_loop, "get_event_loop")
2401
2402 WITH_MOD("asyncio.base_futures")
2403 GET_MOD_ATTR(asyncio_future_repr_info_func, "_future_repr_info")
2404 GET_MOD_ATTR(asyncio_InvalidStateError, "InvalidStateError")
2405 GET_MOD_ATTR(asyncio_CancelledError, "CancelledError")
2406
2407 WITH_MOD("asyncio.base_tasks")
2408 GET_MOD_ATTR(asyncio_task_repr_info_func, "_task_repr_info")
2409 GET_MOD_ATTR(asyncio_task_get_stack_func, "_task_get_stack")
2410 GET_MOD_ATTR(asyncio_task_print_stack_func, "_task_print_stack")
2411
2412 WITH_MOD("inspect")
2413 GET_MOD_ATTR(inspect_isgenerator, "isgenerator")
2414
2415 WITH_MOD("traceback")
2416 GET_MOD_ATTR(traceback_extract_stack, "extract_stack")
2417
2418 WITH_MOD("weakref")
2419 GET_MOD_ATTR(cls, "WeakSet")
Victor Stinnera5ed5f02016-12-06 18:45:50 +01002420 all_tasks = _PyObject_CallNoArg(cls);
Yury Selivanova0c1ba62016-10-28 12:52:37 -04002421 Py_CLEAR(cls);
2422 if (all_tasks == NULL) {
INADA Naokic411a7d2016-10-18 11:48:14 +09002423 goto fail;
2424 }
INADA Naoki9e4e38e2016-10-09 14:44:47 +09002425
Yury Selivanov684ef2c2016-10-28 19:01:21 -04002426 current_tasks = PyDict_New();
Yury Selivanova0c1ba62016-10-28 12:52:37 -04002427 if (current_tasks == NULL) {
2428 goto fail;
2429 }
2430
2431 Py_CLEAR(module);
INADA Naokic411a7d2016-10-18 11:48:14 +09002432 return 0;
INADA Naoki9e4e38e2016-10-09 14:44:47 +09002433
INADA Naokic411a7d2016-10-18 11:48:14 +09002434fail:
INADA Naokic411a7d2016-10-18 11:48:14 +09002435 Py_CLEAR(module);
Yury Selivanova0c1ba62016-10-28 12:52:37 -04002436 module_free(NULL);
INADA Naokic411a7d2016-10-18 11:48:14 +09002437 return -1;
INADA Naoki9e4e38e2016-10-09 14:44:47 +09002438
Yury Selivanova0c1ba62016-10-28 12:52:37 -04002439#undef WITH_MOD
2440#undef GET_MOD_ATTR
2441}
INADA Naoki9e4e38e2016-10-09 14:44:47 +09002442
INADA Naokic411a7d2016-10-18 11:48:14 +09002443PyDoc_STRVAR(module_doc, "Accelerator module for asyncio");
INADA Naoki9e4e38e2016-10-09 14:44:47 +09002444
INADA Naoki9f2ce252016-10-15 15:39:19 +09002445static struct PyModuleDef _asynciomodule = {
INADA Naoki9e4e38e2016-10-09 14:44:47 +09002446 PyModuleDef_HEAD_INIT, /* m_base */
INADA Naoki9f2ce252016-10-15 15:39:19 +09002447 "_asyncio", /* m_name */
INADA Naoki9e4e38e2016-10-09 14:44:47 +09002448 module_doc, /* m_doc */
2449 -1, /* m_size */
INADA Naokic411a7d2016-10-18 11:48:14 +09002450 NULL, /* m_methods */
INADA Naoki9e4e38e2016-10-09 14:44:47 +09002451 NULL, /* m_slots */
2452 NULL, /* m_traverse */
2453 NULL, /* m_clear */
Yury Selivanova0c1ba62016-10-28 12:52:37 -04002454 (freefunc)module_free /* m_free */
INADA Naoki9e4e38e2016-10-09 14:44:47 +09002455};
2456
2457
2458PyMODINIT_FUNC
INADA Naoki9f2ce252016-10-15 15:39:19 +09002459PyInit__asyncio(void)
INADA Naoki9e4e38e2016-10-09 14:44:47 +09002460{
Yury Selivanova0c1ba62016-10-28 12:52:37 -04002461 if (module_init() < 0) {
INADA Naokic411a7d2016-10-18 11:48:14 +09002462 return NULL;
2463 }
INADA Naoki9e4e38e2016-10-09 14:44:47 +09002464 if (PyType_Ready(&FutureType) < 0) {
2465 return NULL;
2466 }
2467 if (PyType_Ready(&FutureIterType) < 0) {
2468 return NULL;
2469 }
Yury Selivanova0c1ba62016-10-28 12:52:37 -04002470 if (PyType_Ready(&TaskSendMethWrapper_Type) < 0) {
2471 return NULL;
2472 }
2473 if(PyType_Ready(&TaskWakeupMethWrapper_Type) < 0) {
2474 return NULL;
2475 }
2476 if (PyType_Ready(&TaskType) < 0) {
2477 return NULL;
2478 }
INADA Naoki9e4e38e2016-10-09 14:44:47 +09002479
INADA Naoki9f2ce252016-10-15 15:39:19 +09002480 PyObject *m = PyModule_Create(&_asynciomodule);
INADA Naoki9e4e38e2016-10-09 14:44:47 +09002481 if (m == NULL) {
2482 return NULL;
2483 }
2484
2485 Py_INCREF(&FutureType);
2486 if (PyModule_AddObject(m, "Future", (PyObject *)&FutureType) < 0) {
2487 Py_DECREF(&FutureType);
2488 return NULL;
2489 }
2490
Yury Selivanova0c1ba62016-10-28 12:52:37 -04002491 Py_INCREF(&TaskType);
2492 if (PyModule_AddObject(m, "Task", (PyObject *)&TaskType) < 0) {
2493 Py_DECREF(&TaskType);
2494 return NULL;
2495 }
2496
INADA Naoki9e4e38e2016-10-09 14:44:47 +09002497 return m;
2498}