From bca4939d806170c3ca5d05f23710d11a8f1669cf Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 3 Sep 2017 08:10:14 +0300 Subject: bpo-31185: Fixed miscellaneous errors in asyncio speedup module. (#3076) --- Lib/test/test_asyncio/test_futures.py | 45 ++- .../2017-08-11-19-30-00.bpo-31185.i6TPgL.rst | 1 + Modules/_asynciomodule.c | 413 ++++++++++----------- Modules/clinic/_asynciomodule.c.h | 8 +- 4 files changed, 248 insertions(+), 219 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2017-08-11-19-30-00.bpo-31185.i6TPgL.rst diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py index f8f614f..4320a90 100644 --- a/Lib/test/test_asyncio/test_futures.py +++ b/Lib/test/test_asyncio/test_futures.py @@ -100,8 +100,8 @@ class DuckTests(test_utils.TestCase): class BaseFutureTests: - def _new_future(self, loop=None): - raise NotImplementedError + def _new_future(self, *args, **kwargs): + return self.cls(*args, **kwargs) def setUp(self): super().setUp() @@ -147,6 +147,39 @@ class BaseFutureTests: # Make sure Future doesn't accept a positional argument self.assertRaises(TypeError, self._new_future, 42) + def test_uninitialized(self): + fut = self.cls.__new__(self.cls, loop=self.loop) + self.assertRaises(asyncio.InvalidStateError, fut.result) + fut = self.cls.__new__(self.cls, loop=self.loop) + self.assertRaises(asyncio.InvalidStateError, fut.exception) + fut = self.cls.__new__(self.cls, loop=self.loop) + with self.assertRaises((RuntimeError, AttributeError)): + fut.set_result(None) + fut = self.cls.__new__(self.cls, loop=self.loop) + with self.assertRaises((RuntimeError, AttributeError)): + fut.set_exception(Exception) + fut = self.cls.__new__(self.cls, loop=self.loop) + with self.assertRaises((RuntimeError, AttributeError)): + fut.cancel() + fut = self.cls.__new__(self.cls, loop=self.loop) + with self.assertRaises((RuntimeError, AttributeError)): + fut.add_done_callback(lambda f: None) + fut = self.cls.__new__(self.cls, loop=self.loop) + with self.assertRaises((RuntimeError, AttributeError)): + fut.remove_done_callback(lambda f: None) + fut = self.cls.__new__(self.cls, loop=self.loop) + with self.assertRaises((RuntimeError, AttributeError)): + fut._schedule_callbacks() + fut = self.cls.__new__(self.cls, loop=self.loop) + try: + repr(fut) + except AttributeError: + pass + fut = self.cls.__new__(self.cls, loop=self.loop) + fut.cancelled() + fut.done() + iter(fut) + def test_cancel(self): f = self._new_future(loop=self.loop) self.assertTrue(f.cancel()) @@ -501,15 +534,11 @@ class BaseFutureTests: @unittest.skipUnless(hasattr(futures, '_CFuture'), 'requires the C _asyncio module') class CFutureTests(BaseFutureTests, test_utils.TestCase): - - def _new_future(self, *args, **kwargs): - return futures._CFuture(*args, **kwargs) + cls = getattr(futures, '_CFuture') class PyFutureTests(BaseFutureTests, test_utils.TestCase): - - def _new_future(self, *args, **kwargs): - return futures._PyFuture(*args, **kwargs) + cls = futures._PyFuture class BaseFutureDoneCallbackTests(): diff --git a/Misc/NEWS.d/next/Library/2017-08-11-19-30-00.bpo-31185.i6TPgL.rst b/Misc/NEWS.d/next/Library/2017-08-11-19-30-00.bpo-31185.i6TPgL.rst new file mode 100644 index 0000000..bdaa4ea --- /dev/null +++ b/Misc/NEWS.d/next/Library/2017-08-11-19-30-00.bpo-31185.i6TPgL.rst @@ -0,0 +1 @@ +Fixed miscellaneous errors in asyncio speedup module. diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index d4b3134..2c64c55 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -68,7 +68,7 @@ typedef struct { PyObject_HEAD TaskObj *sw_task; PyObject *sw_arg; -} TaskSendMethWrapper; +} TaskStepMethWrapper; typedef struct { PyObject_HEAD @@ -92,11 +92,11 @@ static int future_schedule_callbacks(FutureObj *fut) { Py_ssize_t len; - PyObject* iters; + PyObject *callbacks; int i; if (fut->fut_callbacks == NULL) { - PyErr_SetString(PyExc_RuntimeError, "NULL callbacks"); + PyErr_SetString(PyExc_RuntimeError, "uninitialized Future object"); return -1; } @@ -105,42 +105,41 @@ future_schedule_callbacks(FutureObj *fut) return 0; } - iters = PyList_GetSlice(fut->fut_callbacks, 0, len); - if (iters == NULL) { + callbacks = PyList_GetSlice(fut->fut_callbacks, 0, len); + if (callbacks == NULL) { return -1; } if (PyList_SetSlice(fut->fut_callbacks, 0, len, NULL) < 0) { - Py_DECREF(iters); + Py_DECREF(callbacks); return -1; } for (i = 0; i < len; i++) { - PyObject *handle = NULL; - PyObject *cb = PyList_GET_ITEM(iters, i); + PyObject *handle; + PyObject *cb = PyList_GET_ITEM(callbacks, i); handle = _PyObject_CallMethodIdObjArgs(fut->fut_loop, &PyId_call_soon, cb, fut, NULL); if (handle == NULL) { - Py_DECREF(iters); + Py_DECREF(callbacks); return -1; } - else { - Py_DECREF(handle); - } + Py_DECREF(handle); } - Py_DECREF(iters); + Py_DECREF(callbacks); return 0; } static int future_init(FutureObj *fut, PyObject *loop) { - PyObject *res = NULL; + PyObject *res; + int is_true; _Py_IDENTIFIER(get_debug); - if (loop == NULL || loop == Py_None) { + if (loop == Py_None) { loop = _PyObject_CallNoArg(asyncio_get_event_loop); if (loop == NULL) { return -1; @@ -149,25 +148,25 @@ future_init(FutureObj *fut, PyObject *loop) else { Py_INCREF(loop); } - Py_CLEAR(fut->fut_loop); - fut->fut_loop = loop; + Py_XSETREF(fut->fut_loop, loop); res = _PyObject_CallMethodId(fut->fut_loop, &PyId_get_debug, NULL); if (res == NULL) { return -1; } - if (PyObject_IsTrue(res)) { - Py_CLEAR(res); - fut->fut_source_tb = _PyObject_CallNoArg(traceback_extract_stack); + is_true = PyObject_IsTrue(res); + Py_DECREF(res); + if (is_true < 0) { + return -1; + } + if (is_true) { + Py_XSETREF(fut->fut_source_tb, _PyObject_CallNoArg(traceback_extract_stack)); if (fut->fut_source_tb == NULL) { return -1; } } - else { - Py_CLEAR(res); - } - fut->fut_callbacks = PyList_New(0); + Py_XSETREF(fut->fut_callbacks, PyList_New(0)); if (fut->fut_callbacks == NULL) { return -1; } @@ -183,6 +182,7 @@ future_set_result(FutureObj *fut, PyObject *res) return NULL; } + assert(!fut->fut_result); Py_INCREF(res); fut->fut_result = res; fut->fut_state = STATE_FINISHED; @@ -208,6 +208,11 @@ future_set_exception(FutureObj *fut, PyObject *exc) if (exc_val == NULL) { return NULL; } + if (fut->fut_state != STATE_PENDING) { + Py_DECREF(exc_val); + PyErr_SetString(asyncio_InvalidStateError, "invalid state"); + return NULL; + } } else { exc_val = exc; @@ -226,6 +231,7 @@ future_set_exception(FutureObj *fut, PyObject *exc) return NULL; } + assert(!fut->fut_exception); fut->fut_exception = exc_val; fut->fut_state = STATE_FINISHED; @@ -240,31 +246,14 @@ future_set_exception(FutureObj *fut, PyObject *exc) static int future_get_result(FutureObj *fut, PyObject **result) { - PyObject *exc; - if (fut->fut_state == STATE_CANCELLED) { - exc = _PyObject_CallNoArg(asyncio_CancelledError); - if (exc == NULL) { - return -1; - } - *result = exc; - return 1; + PyErr_SetNone(asyncio_CancelledError); + return -1; } if (fut->fut_state != STATE_FINISHED) { - PyObject *msg = PyUnicode_FromString("Result is not ready."); - if (msg == NULL) { - return -1; - } - - exc = PyObject_CallFunctionObjArgs(asyncio_InvalidStateError, msg, NULL); - Py_DECREF(msg); - if (exc == NULL) { - return -1; - } - - *result = exc; - return 1; + PyErr_SetString(asyncio_InvalidStateError, "Result is not set."); + return -1; } fut->fut_log_tb = 0; @@ -286,15 +275,16 @@ future_add_done_callback(FutureObj *fut, PyObject *arg) PyObject *handle = _PyObject_CallMethodIdObjArgs(fut->fut_loop, &PyId_call_soon, arg, fut, NULL); - if (handle == NULL) { return NULL; } - else { - Py_DECREF(handle); - } + Py_DECREF(handle); } else { + if (fut->fut_callbacks == NULL) { + PyErr_SetString(PyExc_RuntimeError, "uninitialized Future object"); + return NULL; + } int err = PyList_Append(fut->fut_callbacks, arg); if (err != 0) { return NULL; @@ -324,7 +314,7 @@ future_cancel(FutureObj *fut) _asyncio.Future.__init__ * - loop: 'O' = NULL + loop: object = None This class is *almost* compatible with concurrent.futures.Future. @@ -342,7 +332,7 @@ This class is *almost* compatible with concurrent.futures.Future. static int _asyncio_Future___init___impl(FutureObj *self, PyObject *loop) -/*[clinic end generated code: output=9ed75799eaccb5d6 input=8e1681f23605be2d]*/ +/*[clinic end generated code: output=9ed75799eaccb5d6 input=89af317082bc0bf8]*/ { return future_init(self, loop); @@ -420,12 +410,12 @@ _asyncio_Future_exception_impl(FutureObj *self) /*[clinic end generated code: output=88b20d4f855e0710 input=733547a70c841c68]*/ { if (self->fut_state == STATE_CANCELLED) { - PyErr_SetString(asyncio_CancelledError, ""); + PyErr_SetNone(asyncio_CancelledError); return NULL; } if (self->fut_state != STATE_FINISHED) { - PyErr_SetString(asyncio_InvalidStateError, "Result is not ready."); + PyErr_SetString(asyncio_InvalidStateError, "Exception is not set."); return NULL; } @@ -441,7 +431,7 @@ _asyncio_Future_exception_impl(FutureObj *self) /*[clinic input] _asyncio.Future.set_result - res: 'O' + res: object / Mark the future done and set its result. @@ -452,7 +442,7 @@ InvalidStateError. static PyObject * _asyncio_Future_set_result(FutureObj *self, PyObject *res) -/*[clinic end generated code: output=a620abfc2796bfb6 input=8619565e0503357e]*/ +/*[clinic end generated code: output=a620abfc2796bfb6 input=5b9dc180f1baa56d]*/ { return future_set_result(self, res); } @@ -460,7 +450,7 @@ _asyncio_Future_set_result(FutureObj *self, PyObject *res) /*[clinic input] _asyncio.Future.set_exception - exception: 'O' + exception: object / Mark the future done and set an exception. @@ -471,7 +461,7 @@ InvalidStateError. static PyObject * _asyncio_Future_set_exception(FutureObj *self, PyObject *exception) -/*[clinic end generated code: output=f1c1b0cd321be360 input=1377dbe15e6ea186]*/ +/*[clinic end generated code: output=f1c1b0cd321be360 input=e45b7d7aa71cc66d]*/ { return future_set_exception(self, exception); } @@ -479,7 +469,7 @@ _asyncio_Future_set_exception(FutureObj *self, PyObject *exception) /*[clinic input] _asyncio.Future.add_done_callback - fn: 'O' + fn: object / Add a callback to be run when the future becomes done. @@ -491,7 +481,7 @@ scheduled with call_soon. static PyObject * _asyncio_Future_add_done_callback(FutureObj *self, PyObject *fn) -/*[clinic end generated code: output=819e09629b2ec2b5 input=8cce187e32cec6a8]*/ +/*[clinic end generated code: output=819e09629b2ec2b5 input=8f818b39990b027d]*/ { return future_add_done_callback(self, fn); } @@ -499,7 +489,7 @@ _asyncio_Future_add_done_callback(FutureObj *self, PyObject *fn) /*[clinic input] _asyncio.Future.remove_done_callback - fn: 'O' + fn: object / Remove all instances of a callback from the "call when done" list. @@ -509,11 +499,16 @@ Returns the number of callbacks removed. static PyObject * _asyncio_Future_remove_done_callback(FutureObj *self, PyObject *fn) -/*[clinic end generated code: output=5ab1fb52b24ef31f input=3fedb73e1409c31c]*/ +/*[clinic end generated code: output=5ab1fb52b24ef31f input=0a43280a149d505b]*/ { PyObject *newlist; Py_ssize_t len, i, j=0; + if (self->fut_callbacks == NULL) { + PyErr_SetString(PyExc_RuntimeError, "uninitialized Future object"); + return NULL; + } + len = PyList_GET_SIZE(self->fut_callbacks); if (len == 0) { return PyLong_FromSsize_t(0); @@ -527,29 +522,31 @@ _asyncio_Future_remove_done_callback(FutureObj *self, PyObject *fn) for (i = 0; i < PyList_GET_SIZE(self->fut_callbacks); i++) { int ret; PyObject *item = PyList_GET_ITEM(self->fut_callbacks, i); - - if ((ret = PyObject_RichCompareBool(fn, item, Py_EQ)) < 0) { - goto fail; - } + Py_INCREF(item); + ret = PyObject_RichCompareBool(fn, item, Py_EQ); if (ret == 0) { if (j < len) { - Py_INCREF(item); PyList_SET_ITEM(newlist, j, item); j++; + continue; } - else { - if (PyList_Append(newlist, item)) { - goto fail; - } - } + ret = PyList_Append(newlist, item); + } + Py_DECREF(item); + if (ret < 0) { + goto fail; } } - if (PyList_SetSlice(newlist, j, len, NULL) < 0) { - goto fail; + if (j < len) { + Py_SIZE(newlist) = j; } - if (PyList_SetSlice(self->fut_callbacks, 0, len, newlist) < 0) { - goto fail; + j = PyList_GET_SIZE(newlist); + len = PyList_GET_SIZE(self->fut_callbacks); + if (j != len) { + if (PyList_SetSlice(self->fut_callbacks, 0, len, newlist) < 0) { + goto fail; + } } Py_DECREF(newlist); return PyLong_FromSsize_t(len - j); @@ -730,7 +727,7 @@ FutureObj_get_state(FutureObj *fut) default: assert (0); } - Py_INCREF(ret); + Py_XINCREF(ret); return ret; } @@ -766,25 +763,14 @@ FutureObj_repr(FutureObj *fut) { _Py_IDENTIFIER(_repr_info); - PyObject *_repr_info = _PyUnicode_FromId(&PyId__repr_info); // borrowed - if (_repr_info == NULL) { - return NULL; - } - - PyObject *rinfo = PyObject_CallMethodObjArgs((PyObject*)fut, _repr_info, - NULL); + PyObject *rinfo = _PyObject_CallMethodIdObjArgs((PyObject*)fut, + &PyId__repr_info, + NULL); if (rinfo == NULL) { return NULL; } - PyObject *sp = PyUnicode_FromString(" "); - if (sp == NULL) { - Py_DECREF(rinfo); - return NULL; - } - - PyObject *rinfo_s = PyUnicode_Join(sp, rinfo); - Py_DECREF(sp); + PyObject *rinfo_s = PyUnicode_Join(NULL, rinfo); Py_DECREF(rinfo); if (rinfo_s == NULL) { return NULL; @@ -794,7 +780,7 @@ FutureObj_repr(FutureObj *fut) PyObject *type_name = PyObject_GetAttrString((PyObject*)Py_TYPE(fut), "__name__"); if (type_name != NULL) { - rstr = PyUnicode_FromFormat("<%S %S>", type_name, rinfo_s); + rstr = PyUnicode_FromFormat("<%S %U>", type_name, rinfo_s); Py_DECREF(type_name); } Py_DECREF(rinfo_s); @@ -810,22 +796,21 @@ FutureObj_finalize(FutureObj *fut) _Py_IDENTIFIER(future); _Py_IDENTIFIER(source_traceback); + PyObject *error_type, *error_value, *error_traceback; + PyObject *context; + PyObject *type_name; + PyObject *message = NULL; + PyObject *func; + if (!fut->fut_log_tb) { return; } assert(fut->fut_exception != NULL); - fut->fut_log_tb = 0;; + fut->fut_log_tb = 0; - PyObject *error_type, *error_value, *error_traceback; /* Save the current exception, if any. */ PyErr_Fetch(&error_type, &error_value, &error_traceback); - PyObject *context = NULL; - PyObject *type_name = NULL; - PyObject *message = NULL; - PyObject *func = NULL; - PyObject *res = NULL; - context = PyDict_New(); if (context == NULL) { goto finally; @@ -838,6 +823,7 @@ FutureObj_finalize(FutureObj *fut) message = PyUnicode_FromFormat( "%S exception was never retrieved", type_name); + Py_DECREF(type_name); if (message == NULL) { goto finally; } @@ -856,18 +842,19 @@ FutureObj_finalize(FutureObj *fut) func = _PyObject_GetAttrId(fut->fut_loop, &PyId_call_exception_handler); if (func != NULL) { - res = PyObject_CallFunctionObjArgs(func, context, NULL); + PyObject *res = PyObject_CallFunctionObjArgs(func, context, NULL); if (res == NULL) { PyErr_WriteUnraisable(func); } + else { + Py_DECREF(res); + } + Py_DECREF(func); } finally: - Py_CLEAR(context); - Py_CLEAR(type_name); - Py_CLEAR(message); - Py_CLEAR(func); - Py_CLEAR(res); + Py_XDECREF(context); + Py_XDECREF(message); /* Restore the saved exception. */ PyErr_Restore(error_type, error_value, error_traceback); @@ -1014,22 +1001,19 @@ FutureIter_iternext(futureiterobject *it) Py_INCREF(fut); return (PyObject *)fut; } - PyErr_Format(PyExc_AssertionError, - "yield from wasn't used with future"); + PyErr_SetString(PyExc_AssertionError, + "yield from wasn't used with future"); return NULL; } + it->future = NULL; res = _asyncio_Future_result_impl(fut); if (res != NULL) { /* The result of the Future is not an exception. */ - if (_PyGen_SetStopIterationValue(res) < 0) { - Py_DECREF(res); - return NULL; - } + (void)_PyGen_SetStopIterationValue(res); Py_DECREF(res); } - it->future = NULL; Py_DECREF(fut); return NULL; } @@ -1046,7 +1030,7 @@ FutureIter_send(futureiterobject *self, PyObject *unused) static PyObject * FutureIter_throw(futureiterobject *self, PyObject *args) { - PyObject *type=NULL, *val=NULL, *tb=NULL; + PyObject *type, *val = NULL, *tb = NULL; if (!PyArg_ParseTuple(args, "O|OO", &type, &val, &tb)) return NULL; @@ -1090,7 +1074,7 @@ FutureIter_throw(futureiterobject *self, PyObject *args) PyErr_Restore(type, val, tb); - return FutureIter_iternext(self); + return NULL; fail: Py_DECREF(type); @@ -1171,7 +1155,7 @@ static PyObject * task_step(TaskObj *, PyObject *); /* ----- Task._step wrapper */ static int -TaskSendMethWrapper_clear(TaskSendMethWrapper *o) +TaskStepMethWrapper_clear(TaskStepMethWrapper *o) { Py_CLEAR(o->sw_task); Py_CLEAR(o->sw_arg); @@ -1179,22 +1163,30 @@ TaskSendMethWrapper_clear(TaskSendMethWrapper *o) } static void -TaskSendMethWrapper_dealloc(TaskSendMethWrapper *o) +TaskStepMethWrapper_dealloc(TaskStepMethWrapper *o) { PyObject_GC_UnTrack(o); - (void)TaskSendMethWrapper_clear(o); + (void)TaskStepMethWrapper_clear(o); Py_TYPE(o)->tp_free(o); } static PyObject * -TaskSendMethWrapper_call(TaskSendMethWrapper *o, +TaskStepMethWrapper_call(TaskStepMethWrapper *o, PyObject *args, PyObject *kwds) { + if (kwds != NULL && PyDict_GET_SIZE(kwds) != 0) { + PyErr_SetString(PyExc_TypeError, "function takes no keyword arguments"); + return NULL; + } + if (args != NULL && PyTuple_GET_SIZE(args) != 0) { + PyErr_SetString(PyExc_TypeError, "function takes no positional arguments"); + return NULL; + } return task_call_step(o->sw_task, o->sw_arg); } static int -TaskSendMethWrapper_traverse(TaskSendMethWrapper *o, +TaskStepMethWrapper_traverse(TaskStepMethWrapper *o, visitproc visit, void *arg) { Py_VISIT(o->sw_task); @@ -1203,7 +1195,7 @@ TaskSendMethWrapper_traverse(TaskSendMethWrapper *o, } static PyObject * -TaskSendMethWrapper_get___self__(TaskSendMethWrapper *o) +TaskStepMethWrapper_get___self__(TaskStepMethWrapper *o) { if (o->sw_task) { Py_INCREF(o->sw_task); @@ -1212,30 +1204,30 @@ TaskSendMethWrapper_get___self__(TaskSendMethWrapper *o) Py_RETURN_NONE; } -static PyGetSetDef TaskSendMethWrapper_getsetlist[] = { - {"__self__", (getter)TaskSendMethWrapper_get___self__, NULL, NULL}, +static PyGetSetDef TaskStepMethWrapper_getsetlist[] = { + {"__self__", (getter)TaskStepMethWrapper_get___self__, NULL, NULL}, {NULL} /* Sentinel */ }; -PyTypeObject TaskSendMethWrapper_Type = { +PyTypeObject TaskStepMethWrapper_Type = { PyVarObject_HEAD_INIT(NULL, 0) - "TaskSendMethWrapper", - .tp_basicsize = sizeof(TaskSendMethWrapper), + "TaskStepMethWrapper", + .tp_basicsize = sizeof(TaskStepMethWrapper), .tp_itemsize = 0, - .tp_getset = TaskSendMethWrapper_getsetlist, - .tp_dealloc = (destructor)TaskSendMethWrapper_dealloc, - .tp_call = (ternaryfunc)TaskSendMethWrapper_call, + .tp_getset = TaskStepMethWrapper_getsetlist, + .tp_dealloc = (destructor)TaskStepMethWrapper_dealloc, + .tp_call = (ternaryfunc)TaskStepMethWrapper_call, .tp_getattro = PyObject_GenericGetAttr, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, - .tp_traverse = (traverseproc)TaskSendMethWrapper_traverse, - .tp_clear = (inquiry)TaskSendMethWrapper_clear, + .tp_traverse = (traverseproc)TaskStepMethWrapper_traverse, + .tp_clear = (inquiry)TaskStepMethWrapper_clear, }; static PyObject * -TaskSendMethWrapper_new(TaskObj *task, PyObject *arg) +TaskStepMethWrapper_new(TaskObj *task, PyObject *arg) { - TaskSendMethWrapper *o; - o = PyObject_GC_New(TaskSendMethWrapper, &TaskSendMethWrapper_Type); + TaskStepMethWrapper *o; + o = PyObject_GC_New(TaskStepMethWrapper, &TaskStepMethWrapper_Type); if (o == NULL) { return NULL; } @@ -1258,7 +1250,11 @@ TaskWakeupMethWrapper_call(TaskWakeupMethWrapper *o, { PyObject *fut; - if (!PyArg_ParseTuple(args, "O|", &fut)) { + if (kwds != NULL && PyDict_GET_SIZE(kwds) != 0) { + PyErr_SetString(PyExc_TypeError, "function takes no keyword arguments"); + return NULL; + } + if (!PyArg_ParseTuple(args, "O", &fut)) { return NULL; } @@ -1322,16 +1318,16 @@ TaskWakeupMethWrapper_new(TaskObj *task) /*[clinic input] _asyncio.Task.__init__ - coro: 'O' + coro: object * - loop: 'O' = NULL + loop: object = None A coroutine wrapped in a Future. [clinic start generated code]*/ static int _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop) -/*[clinic end generated code: output=9f24774c2287fc2f input=71d8d28c201a18cd]*/ +/*[clinic end generated code: output=9f24774c2287fc2f input=8d132974b049593e]*/ { PyObject *res; _Py_IDENTIFIER(add); @@ -1437,7 +1433,7 @@ TaskObj_get_fut_waiter(TaskObj *task) @classmethod _asyncio.Task.current_task - loop: 'O' = None + loop: object = None Return the currently running task in an event loop or None. @@ -1448,7 +1444,7 @@ None is returned when called not in the context of a Task. static PyObject * _asyncio_Task_current_task_impl(PyTypeObject *type, PyObject *loop) -/*[clinic end generated code: output=99fbe7332c516e03 input=a0d6cdf2e3b243e1]*/ +/*[clinic end generated code: output=99fbe7332c516e03 input=cd14770c5b79c7eb]*/ { PyObject *res; @@ -1510,12 +1506,14 @@ task_all_tasks(PyObject *loop) Py_DECREF(task_loop); Py_DECREF(task); } - + if (PyErr_Occurred()) { + goto fail; + } Py_DECREF(iter); return set; fail: - Py_XDECREF(set); + Py_DECREF(set); Py_XDECREF(iter); return NULL; } @@ -1524,7 +1522,7 @@ fail: @classmethod _asyncio.Task.all_tasks - loop: 'O' = None + loop: object = None Return a set of all tasks for an event loop. @@ -1533,7 +1531,7 @@ By default all tasks for the current event loop are returned. static PyObject * _asyncio_Task_all_tasks_impl(PyTypeObject *type, PyObject *loop) -/*[clinic end generated code: output=11f9b20749ccca5d input=c6f5b53bd487488f]*/ +/*[clinic end generated code: output=11f9b20749ccca5d input=497f80bc9ce726b5]*/ { PyObject *res; @@ -1627,7 +1625,7 @@ _asyncio_Task_cancel_impl(TaskObj *self) _asyncio.Task.get_stack * - limit: 'O' = None + limit: object = None Return the list of stack frames for this task's coroutine. @@ -1652,7 +1650,7 @@ returned for a suspended coroutine. static PyObject * _asyncio_Task_get_stack_impl(TaskObj *self, PyObject *limit) -/*[clinic end generated code: output=c9aeeeebd1e18118 input=b1920230a766d17a]*/ +/*[clinic end generated code: output=c9aeeeebd1e18118 input=05b323d42b809b90]*/ { return PyObject_CallFunctionObjArgs( asyncio_task_get_stack_func, self, limit, NULL); @@ -1662,8 +1660,8 @@ _asyncio_Task_get_stack_impl(TaskObj *self, PyObject *limit) _asyncio.Task.print_stack * - limit: 'O' = None - file: 'O' = None + limit: object = None + file: object = None Print the stack or traceback for this task's coroutine. @@ -1677,7 +1675,7 @@ to sys.stderr. static PyObject * _asyncio_Task_print_stack_impl(TaskObj *self, PyObject *limit, PyObject *file) -/*[clinic end generated code: output=7339e10314cd3f4d input=19f1e99ab5400bc3]*/ +/*[clinic end generated code: output=7339e10314cd3f4d input=1a0352913b7fcd92]*/ { return PyObject_CallFunctionObjArgs( asyncio_task_print_stack_func, self, limit, file, NULL); @@ -1686,12 +1684,12 @@ _asyncio_Task_print_stack_impl(TaskObj *self, PyObject *limit, /*[clinic input] _asyncio.Task._step - exc: 'O' = NULL + exc: object = None [clinic start generated code]*/ static PyObject * _asyncio_Task__step_impl(TaskObj *self, PyObject *exc) -/*[clinic end generated code: output=7ed23f0cefd5ae42 input=ada4b2324e5370af]*/ +/*[clinic end generated code: output=7ed23f0cefd5ae42 input=1e19a985ace87ca4]*/ { return task_step(self, exc == Py_None ? NULL : exc); } @@ -1699,12 +1697,12 @@ _asyncio_Task__step_impl(TaskObj *self, PyObject *exc) /*[clinic input] _asyncio.Task._wakeup - fut: 'O' + fut: object [clinic start generated code]*/ static PyObject * _asyncio_Task__wakeup_impl(TaskObj *self, PyObject *fut) -/*[clinic end generated code: output=75cb341c760fd071 input=11ee4918a5bdbf21]*/ +/*[clinic end generated code: output=75cb341c760fd071 input=6a0616406f829a7b]*/ { return task_wakeup(self, fut); } @@ -1717,11 +1715,9 @@ TaskObj_finalize(TaskObj *task) _Py_IDENTIFIER(message); _Py_IDENTIFIER(source_traceback); + PyObject *context; PyObject *message = NULL; - PyObject *context = NULL; - PyObject *func = NULL; - PyObject *res = NULL; - + PyObject *func; PyObject *error_type, *error_value, *error_traceback; if (task->task_state != STATE_PENDING || !task->task_log_destroy_pending) { @@ -1757,17 +1753,19 @@ TaskObj_finalize(TaskObj *task) func = _PyObject_GetAttrId(task->task_loop, &PyId_call_exception_handler); if (func != NULL) { - res = PyObject_CallFunctionObjArgs(func, context, NULL); + PyObject *res = PyObject_CallFunctionObjArgs(func, context, NULL); if (res == NULL) { PyErr_WriteUnraisable(func); } + else { + Py_DECREF(res); + } + Py_DECREF(func); } finally: - Py_CLEAR(context); - Py_CLEAR(message); - Py_CLEAR(func); - Py_CLEAR(res); + Py_XDECREF(context); + Py_XDECREF(message); /* Restore the saved exception. */ PyErr_Restore(error_type, error_value, error_traceback); @@ -1879,9 +1877,6 @@ task_call_step(TaskObj *task, PyObject *arg) } else { /* `task` is a subclass of Task */ - if (arg == NULL) { - arg = Py_None; - } return _PyObject_CallMethodIdObjArgs((PyObject*)task, &PyId__step, arg, NULL); } @@ -1892,7 +1887,7 @@ task_call_step_soon(TaskObj *task, PyObject *arg) { PyObject *handle; - PyObject *cb = TaskSendMethWrapper_new(task, arg); + PyObject *cb = TaskStepMethWrapper_new(task, arg); if (cb == NULL) { return -1; } @@ -1947,7 +1942,7 @@ task_step_impl(TaskObj *task, PyObject *exc) int res; int clear_exc = 0; PyObject *result = NULL; - PyObject *coro = task->task_coro; + PyObject *coro; PyObject *o; if (task->task_state != STATE_PENDING) { @@ -1988,6 +1983,12 @@ task_step_impl(TaskObj *task, PyObject *exc) Py_CLEAR(task->task_fut_waiter); + coro = task->task_coro; + if (coro == NULL) { + PyErr_SetString(PyExc_RuntimeError, "uninitialized Task object"); + return NULL; + } + if (exc == NULL) { if (PyGen_CheckExact(coro) || PyCoro_CheckExact(coro)) { result = _PyGen_Send((PyGenObject*)coro, Py_None); @@ -2002,7 +2003,7 @@ task_step_impl(TaskObj *task, PyObject *exc) exc, NULL); if (clear_exc) { /* We created 'exc' during this call */ - Py_CLEAR(exc); + Py_DECREF(exc); } } @@ -2051,13 +2052,13 @@ set_exception: o = future_set_exception((FutureObj*)task, ev); if (!o) { /* An exception in Task.set_exception() */ - Py_XDECREF(et); + Py_DECREF(et); Py_XDECREF(tb); Py_XDECREF(ev); goto fail; } assert(o == Py_None); - Py_CLEAR(o); + Py_DECREF(o); if (!PyErr_GivenExceptionMatches(et, PyExc_Exception)) { /* We've got a BaseException; re-raise it */ @@ -2065,7 +2066,7 @@ set_exception: goto fail; } - Py_XDECREF(et); + Py_DECREF(et); Py_XDECREF(tb); Py_XDECREF(ev); @@ -2137,7 +2138,7 @@ set_exception: } else { if (o == Py_None) { - Py_CLEAR(o); + Py_DECREF(o); } else { /* `result` is a Future-compatible object */ @@ -2145,7 +2146,7 @@ set_exception: PyObject *res; int blocking = PyObject_IsTrue(o); - Py_CLEAR(o); + Py_DECREF(o); if (blocking < 0) { goto fail; } @@ -2228,7 +2229,7 @@ set_exception: goto fail; } res = PyObject_IsTrue(o); - Py_CLEAR(o); + Py_DECREF(o); if (res == -1) { /* An exception while checking if 'val' is True */ goto fail; @@ -2296,14 +2297,8 @@ task_step(TaskObj *task, PyObject *exc) PyObject *et, *ev, *tb; PyErr_Fetch(&et, &ev, &tb); ot = _PyDict_Pop(current_tasks, task->task_loop, NULL); - if (ot == NULL) { - Py_XDECREF(et); - Py_XDECREF(tb); - Py_XDECREF(ev); - return NULL; - } - Py_DECREF(ot); - PyErr_Restore(et, ev, tb); + Py_XDECREF(ot); + _PyErr_ChainExceptions(et, ev, tb); return NULL; } else { @@ -2322,17 +2317,18 @@ task_step(TaskObj *task, PyObject *exc) static PyObject * task_wakeup(TaskObj *task, PyObject *o) { + PyObject *et, *ev, *tb; + PyObject *result; assert(o); if (Future_CheckExact(o) || Task_CheckExact(o)) { PyObject *fut_result = NULL; int res = future_get_result((FutureObj*)o, &fut_result); - PyObject *result; switch(res) { case -1: assert(fut_result == NULL); - return NULL; + break; /* exception raised */ case 0: Py_DECREF(fut_result); return task_call_step(task, NULL); @@ -2343,29 +2339,32 @@ task_wakeup(TaskObj *task, PyObject *o) return result; } } - - PyObject *fut_result = PyObject_CallMethod(o, "result", NULL); - if (fut_result == NULL) { - PyObject *et, *ev, *tb; - PyObject *res; - - PyErr_Fetch(&et, &ev, &tb); - if (!ev || !PyObject_TypeCheck(ev, (PyTypeObject *) et)) { - PyErr_NormalizeException(&et, &ev, &tb); + else { + PyObject *fut_result = PyObject_CallMethod(o, "result", NULL); + if (fut_result != NULL) { + Py_DECREF(fut_result); + return task_call_step(task, NULL); } + /* exception raised */ + } - res = task_call_step(task, ev); - - Py_XDECREF(et); - Py_XDECREF(tb); - Py_XDECREF(ev); - - return res; + PyErr_Fetch(&et, &ev, &tb); + if (!PyErr_GivenExceptionMatches(et, PyExc_Exception)) { + /* We've got a BaseException; re-raise it */ + PyErr_Restore(et, ev, tb); + return NULL; } - else { - Py_DECREF(fut_result); - return task_call_step(task, NULL); + if (!ev || !PyObject_TypeCheck(ev, (PyTypeObject *) et)) { + PyErr_NormalizeException(&et, &ev, &tb); } + + result = task_call_step(task, ev); + + Py_DECREF(et); + Py_XDECREF(tb); + Py_XDECREF(ev); + + return result; } @@ -2398,7 +2397,7 @@ module_init(void) Py_CLEAR(module); \ module = PyImport_ImportModule(NAME); \ if (module == NULL) { \ - return -1; \ + goto fail; \ } #define GET_MOD_ATTR(VAR, NAME) \ @@ -2429,7 +2428,7 @@ module_init(void) WITH_MOD("weakref") GET_MOD_ATTR(cls, "WeakSet") all_tasks = _PyObject_CallNoArg(cls); - Py_CLEAR(cls); + Py_DECREF(cls); if (all_tasks == NULL) { goto fail; } @@ -2439,7 +2438,7 @@ module_init(void) goto fail; } - Py_CLEAR(module); + Py_DECREF(module); return 0; fail: @@ -2478,7 +2477,7 @@ PyInit__asyncio(void) if (PyType_Ready(&FutureIterType) < 0) { return NULL; } - if (PyType_Ready(&TaskSendMethWrapper_Type) < 0) { + if (PyType_Ready(&TaskStepMethWrapper_Type) < 0) { return NULL; } if(PyType_Ready(&TaskWakeupMethWrapper_Type) < 0) { diff --git a/Modules/clinic/_asynciomodule.c.h b/Modules/clinic/_asynciomodule.c.h index 8f598ed..7627849 100644 --- a/Modules/clinic/_asynciomodule.c.h +++ b/Modules/clinic/_asynciomodule.c.h @@ -28,7 +28,7 @@ _asyncio_Future___init__(PyObject *self, PyObject *args, PyObject *kwargs) int return_value = -1; static const char * const _keywords[] = {"loop", NULL}; static _PyArg_Parser _parser = {"|$O:Future", _keywords, 0}; - PyObject *loop = NULL; + PyObject *loop = Py_None; if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, &loop)) { @@ -244,7 +244,7 @@ _asyncio_Task___init__(PyObject *self, PyObject *args, PyObject *kwargs) static const char * const _keywords[] = {"coro", "loop", NULL}; static _PyArg_Parser _parser = {"O|$O:Task", _keywords, 0}; PyObject *coro; - PyObject *loop = NULL; + PyObject *loop = Py_None; if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, &coro, &loop)) { @@ -477,7 +477,7 @@ _asyncio_Task__step(TaskObj *self, PyObject **args, Py_ssize_t nargs, PyObject * PyObject *return_value = NULL; static const char * const _keywords[] = {"exc", NULL}; static _PyArg_Parser _parser = {"|O:_step", _keywords, 0}; - PyObject *exc = NULL; + PyObject *exc = Py_None; if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, &exc)) { @@ -517,4 +517,4 @@ _asyncio_Task__wakeup(TaskObj *self, PyObject **args, Py_ssize_t nargs, PyObject exit: return return_value; } -/*[clinic end generated code: output=fe651840e0466fa9 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=b92f9cd2b9fb37ef input=a9049054013a1b77]*/ -- cgit v0.12