diff options
author | INADA Naoki <songofacandy@gmail.com> | 2016-10-15 06:39:19 (GMT) |
---|---|---|
committer | INADA Naoki <songofacandy@gmail.com> | 2016-10-15 06:39:19 (GMT) |
commit | 9f2ce2548107eedaf0970546a508c33d24920622 (patch) | |
tree | 2a410ccb15a3acb857985a3ce15e71fc7bdc3cda /Modules/_asynciomodule.c | |
parent | 479eb760f4dd5ae5cfc5ccf8a361cdea3d48624a (diff) | |
download | cpython-9f2ce2548107eedaf0970546a508c33d24920622.zip cpython-9f2ce2548107eedaf0970546a508c33d24920622.tar.gz cpython-9f2ce2548107eedaf0970546a508c33d24920622.tar.bz2 |
Issue #28428: Rename _futures module to _asyncio.
It will have more speedup functions or classes other than asyncio.Future.
Diffstat (limited to 'Modules/_asynciomodule.c')
-rw-r--r-- | Modules/_asynciomodule.c | 1034 |
1 files changed, 1034 insertions, 0 deletions
diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c new file mode 100644 index 0000000..ce576e5 --- /dev/null +++ b/Modules/_asynciomodule.c @@ -0,0 +1,1034 @@ +#include "Python.h" +#include "structmember.h" + + +/* identifiers used from some functions */ +_Py_IDENTIFIER(call_soon); + + +/* State of the _asyncio module */ +static int _asynciomod_ready; +static PyObject *traceback_extract_stack; +static PyObject *asyncio_get_event_loop; +static PyObject *asyncio_repr_info_func; +static PyObject *asyncio_InvalidStateError; +static PyObject *asyncio_CancelledError; + + +/* Get FutureIter from Future */ +static PyObject* new_future_iter(PyObject *fut); + + +/* make sure module state is initialized and ready to be used. */ +static int +_AsyncioMod_EnsureState(void) +{ + if (!_asynciomod_ready) { + PyErr_SetString(PyExc_RuntimeError, + "_asyncio module wasn't properly initialized"); + return -1; + } + return 0; +} + + +typedef enum { + STATE_PENDING, + STATE_CANCELLED, + STATE_FINISHED +} fut_state; + + +typedef struct { + PyObject_HEAD + PyObject *fut_loop; + PyObject *fut_callbacks; + PyObject *fut_exception; + PyObject *fut_result; + PyObject *fut_source_tb; + fut_state fut_state; + int fut_log_tb; + int fut_blocking; + PyObject *dict; + PyObject *fut_weakreflist; +} FutureObj; + + +static int +_schedule_callbacks(FutureObj *fut) +{ + Py_ssize_t len; + PyObject* iters; + int i; + + if (fut->fut_callbacks == NULL) { + PyErr_SetString(PyExc_RuntimeError, "NULL callbacks"); + return -1; + } + + len = PyList_GET_SIZE(fut->fut_callbacks); + if (len == 0) { + return 0; + } + + iters = PyList_GetSlice(fut->fut_callbacks, 0, len); + if (iters == NULL) { + return -1; + } + if (PyList_SetSlice(fut->fut_callbacks, 0, len, NULL) < 0) { + Py_DECREF(iters); + return -1; + } + + for (i = 0; i < len; i++) { + PyObject *handle = NULL; + PyObject *cb = PyList_GET_ITEM(iters, i); + + handle = _PyObject_CallMethodId( + fut->fut_loop, &PyId_call_soon, "OO", cb, fut, NULL); + + if (handle == NULL) { + Py_DECREF(iters); + return -1; + } + else { + Py_DECREF(handle); + } + } + + Py_DECREF(iters); + return 0; +} + +static int +FutureObj_init(FutureObj *fut, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"loop", NULL}; + PyObject *loop = NULL; + PyObject *res = NULL; + _Py_IDENTIFIER(get_debug); + + if (_AsyncioMod_EnsureState()) { + return -1; + } + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|$O", kwlist, &loop)) { + return -1; + } + if (loop == NULL || loop == Py_None) { + loop = PyObject_CallObject(asyncio_get_event_loop, NULL); + if (loop == NULL) { + return -1; + } + } + else { + Py_INCREF(loop); + } + Py_CLEAR(fut->fut_loop); + 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_CallObject(traceback_extract_stack, NULL); + if (fut->fut_source_tb == NULL) { + return -1; + } + } + else { + Py_CLEAR(res); + } + + fut->fut_callbacks = PyList_New(0); + if (fut->fut_callbacks == NULL) { + return -1; + } + return 0; +} + +static int +FutureObj_clear(FutureObj *fut) +{ + Py_CLEAR(fut->fut_loop); + Py_CLEAR(fut->fut_callbacks); + Py_CLEAR(fut->fut_result); + Py_CLEAR(fut->fut_exception); + Py_CLEAR(fut->fut_source_tb); + Py_CLEAR(fut->dict); + return 0; +} + +static int +FutureObj_traverse(FutureObj *fut, visitproc visit, void *arg) +{ + Py_VISIT(fut->fut_loop); + Py_VISIT(fut->fut_callbacks); + Py_VISIT(fut->fut_result); + Py_VISIT(fut->fut_exception); + Py_VISIT(fut->fut_source_tb); + Py_VISIT(fut->dict); + return 0; +} + +PyDoc_STRVAR(pydoc_result, + "Return the result this future represents.\n" + "\n" + "If the future has been cancelled, raises CancelledError. If the\n" + "future's result isn't yet available, raises InvalidStateError. If\n" + "the future is done and has an exception set, this exception is raised." +); + +static PyObject * +FutureObj_result(FutureObj *fut, PyObject *arg) +{ + if (fut->fut_state == STATE_CANCELLED) { + PyErr_SetString(asyncio_CancelledError, ""); + return NULL; + } + + if (fut->fut_state != STATE_FINISHED) { + PyErr_SetString(asyncio_InvalidStateError, "Result is not ready."); + return NULL; + } + + fut->fut_log_tb = 0; + if (fut->fut_exception != NULL) { + PyObject *type = NULL; + type = PyExceptionInstance_Class(fut->fut_exception); + PyErr_SetObject(type, fut->fut_exception); + return NULL; + } + + Py_INCREF(fut->fut_result); + return fut->fut_result; +} + +PyDoc_STRVAR(pydoc_exception, + "Return the exception that was set on this future.\n" + "\n" + "The exception (or None if no exception was set) is returned only if\n" + "the future is done. If the future has been cancelled, raises\n" + "CancelledError. If the future isn't done yet, raises\n" + "InvalidStateError." +); + +static PyObject * +FutureObj_exception(FutureObj *fut, PyObject *arg) +{ + if (_AsyncioMod_EnsureState()) { + return NULL; + } + + if (fut->fut_state == STATE_CANCELLED) { + PyErr_SetString(asyncio_CancelledError, ""); + return NULL; + } + + if (fut->fut_state != STATE_FINISHED) { + PyErr_SetString(asyncio_InvalidStateError, "Result is not ready."); + return NULL; + } + + if (fut->fut_exception != NULL) { + fut->fut_log_tb = 0; + Py_INCREF(fut->fut_exception); + return fut->fut_exception; + } + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pydoc_set_result, + "Mark the future done and set its result.\n" + "\n" + "If the future is already done when this method is called, raises\n" + "InvalidStateError." +); + +static PyObject * +FutureObj_set_result(FutureObj *fut, PyObject *res) +{ + if (_AsyncioMod_EnsureState()) { + return NULL; + } + + if (fut->fut_state != STATE_PENDING) { + PyErr_SetString(asyncio_InvalidStateError, "invalid state"); + return NULL; + } + + Py_INCREF(res); + fut->fut_result = res; + fut->fut_state = STATE_FINISHED; + + if (_schedule_callbacks(fut) == -1) { + return NULL; + } + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pydoc_set_exception, + "Mark the future done and set an exception.\n" + "\n" + "If the future is already done when this method is called, raises\n" + "InvalidStateError." +); + +static PyObject * +FutureObj_set_exception(FutureObj *fut, PyObject *exc) +{ + PyObject *exc_val = NULL; + + if (_AsyncioMod_EnsureState()) { + return NULL; + } + + if (fut->fut_state != STATE_PENDING) { + PyErr_SetString(asyncio_InvalidStateError, "invalid state"); + return NULL; + } + + if (PyExceptionClass_Check(exc)) { + exc_val = PyObject_CallObject(exc, NULL); + if (exc_val == NULL) { + return NULL; + } + } + else { + exc_val = exc; + Py_INCREF(exc_val); + } + if (!PyExceptionInstance_Check(exc_val)) { + Py_DECREF(exc_val); + PyErr_SetString(PyExc_TypeError, "invalid exception object"); + return NULL; + } + if ((PyObject*)Py_TYPE(exc_val) == PyExc_StopIteration) { + Py_DECREF(exc_val); + PyErr_SetString(PyExc_TypeError, + "StopIteration interacts badly with generators " + "and cannot be raised into a Future"); + return NULL; + } + + fut->fut_exception = exc_val; + fut->fut_state = STATE_FINISHED; + + if (_schedule_callbacks(fut) == -1) { + return NULL; + } + + fut->fut_log_tb = 1; + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pydoc_add_done_callback, + "Add a callback to be run when the future becomes done.\n" + "\n" + "The callback is called with a single argument - the future object. If\n" + "the future is already done when this is called, the callback is\n" + "scheduled with call_soon."; +); + +static PyObject * +FutureObj_add_done_callback(FutureObj *fut, PyObject *arg) +{ + if (fut->fut_state != STATE_PENDING) { + PyObject *handle = _PyObject_CallMethodId( + fut->fut_loop, &PyId_call_soon, "OO", arg, fut, NULL); + + if (handle == NULL) { + return NULL; + } + else { + Py_DECREF(handle); + } + } + else { + int err = PyList_Append(fut->fut_callbacks, arg); + if (err != 0) { + return NULL; + } + } + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pydoc_remove_done_callback, + "Remove all instances of a callback from the \"call when done\" list.\n" + "\n" + "Returns the number of callbacks removed." +); + +static PyObject * +FutureObj_remove_done_callback(FutureObj *fut, PyObject *arg) +{ + PyObject *newlist; + Py_ssize_t len, i, j=0; + + len = PyList_GET_SIZE(fut->fut_callbacks); + if (len == 0) { + return PyLong_FromSsize_t(0); + } + + newlist = PyList_New(len); + if (newlist == NULL) { + return NULL; + } + + for (i = 0; i < len; i++) { + int ret; + PyObject *item = PyList_GET_ITEM(fut->fut_callbacks, i); + + if ((ret = PyObject_RichCompareBool(arg, item, Py_EQ)) < 0) { + goto fail; + } + if (ret == 0) { + Py_INCREF(item); + PyList_SET_ITEM(newlist, j, item); + j++; + } + } + + if (PyList_SetSlice(newlist, j, len, NULL) < 0) { + goto fail; + } + if (PyList_SetSlice(fut->fut_callbacks, 0, len, newlist) < 0) { + goto fail; + } + Py_DECREF(newlist); + return PyLong_FromSsize_t(len - j); + +fail: + Py_DECREF(newlist); + return NULL; +} + +PyDoc_STRVAR(pydoc_cancel, + "Cancel the future and schedule callbacks.\n" + "\n" + "If the future is already done or cancelled, return False. Otherwise,\n" + "change the future's state to cancelled, schedule the callbacks and\n" + "return True." +); + +static PyObject * +FutureObj_cancel(FutureObj *fut, PyObject *arg) +{ + if (fut->fut_state != STATE_PENDING) { + Py_RETURN_FALSE; + } + fut->fut_state = STATE_CANCELLED; + + if (_schedule_callbacks(fut) == -1) { + return NULL; + } + + Py_RETURN_TRUE; +} + +PyDoc_STRVAR(pydoc_cancelled, "Return True if the future was cancelled."); + +static PyObject * +FutureObj_cancelled(FutureObj *fut, PyObject *arg) +{ + if (fut->fut_state == STATE_CANCELLED) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +PyDoc_STRVAR(pydoc_done, + "Return True if the future is done.\n" + "\n" + "Done means either that a result / exception are available, or that the\n" + "future was cancelled." +); + +static PyObject * +FutureObj_done(FutureObj *fut, PyObject *arg) +{ + if (fut->fut_state == STATE_PENDING) { + Py_RETURN_FALSE; + } + else { + Py_RETURN_TRUE; + } +} + +static PyObject * +FutureObj_get_blocking(FutureObj *fut) +{ + if (fut->fut_blocking) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +static int +FutureObj_set_blocking(FutureObj *fut, PyObject *val) +{ + int is_true = PyObject_IsTrue(val); + if (is_true < 0) { + return -1; + } + fut->fut_blocking = is_true; + return 0; +} + +static PyObject * +FutureObj_get_log_traceback(FutureObj *fut) +{ + if (fut->fut_log_tb) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +static PyObject * +FutureObj_get_loop(FutureObj *fut) +{ + if (fut->fut_loop == NULL) { + Py_RETURN_NONE; + } + Py_INCREF(fut->fut_loop); + return fut->fut_loop; +} + +static PyObject * +FutureObj_get_callbacks(FutureObj *fut) +{ + if (fut->fut_callbacks == NULL) { + Py_RETURN_NONE; + } + Py_INCREF(fut->fut_callbacks); + return fut->fut_callbacks; +} + +static PyObject * +FutureObj_get_result(FutureObj *fut) +{ + if (fut->fut_result == NULL) { + Py_RETURN_NONE; + } + Py_INCREF(fut->fut_result); + return fut->fut_result; +} + +static PyObject * +FutureObj_get_exception(FutureObj *fut) +{ + if (fut->fut_exception == NULL) { + Py_RETURN_NONE; + } + Py_INCREF(fut->fut_exception); + return fut->fut_exception; +} + +static PyObject * +FutureObj_get_source_traceback(FutureObj *fut) +{ + if (fut->fut_source_tb == NULL) { + Py_RETURN_NONE; + } + Py_INCREF(fut->fut_source_tb); + return fut->fut_source_tb; +} + +static PyObject * +FutureObj_get_state(FutureObj *fut) +{ + _Py_IDENTIFIER(PENDING); + _Py_IDENTIFIER(CANCELLED); + _Py_IDENTIFIER(FINISHED); + PyObject *ret = NULL; + + switch (fut->fut_state) { + case STATE_PENDING: + ret = _PyUnicode_FromId(&PyId_PENDING); + break; + case STATE_CANCELLED: + ret = _PyUnicode_FromId(&PyId_CANCELLED); + break; + case STATE_FINISHED: + ret = _PyUnicode_FromId(&PyId_FINISHED); + break; + default: + assert (0); + } + Py_INCREF(ret); + return ret; +} + +static PyObject* +FutureObj__repr_info(FutureObj *fut) +{ + if (asyncio_repr_info_func == NULL) { + return PyList_New(0); + } + return PyObject_CallFunctionObjArgs(asyncio_repr_info_func, fut, NULL); +} + +static PyObject * +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); + 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); + Py_DECREF(rinfo); + if (rinfo_s == NULL) { + return NULL; + } + + PyObject *rstr = NULL; + PyObject *type_name = PyObject_GetAttrString((PyObject*)Py_TYPE(fut), + "__name__"); + if (type_name != NULL) { + rstr = PyUnicode_FromFormat("<%S %S>", type_name, rinfo_s); + Py_DECREF(type_name); + } + Py_DECREF(rinfo_s); + return rstr; +} + +static void +FutureObj_finalize(FutureObj *fut) +{ + _Py_IDENTIFIER(call_exception_handler); + _Py_IDENTIFIER(message); + _Py_IDENTIFIER(exception); + _Py_IDENTIFIER(future); + _Py_IDENTIFIER(source_traceback); + + if (!fut->fut_log_tb) { + return; + } + assert(fut->fut_exception != NULL); + 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; + } + + type_name = PyObject_GetAttrString((PyObject*)Py_TYPE(fut), "__name__"); + if (type_name == NULL) { + goto finally; + } + + message = PyUnicode_FromFormat( + "%S exception was never retrieved", type_name); + if (message == NULL) { + goto finally; + } + + if (_PyDict_SetItemId(context, &PyId_message, message) < 0 || + _PyDict_SetItemId(context, &PyId_exception, fut->fut_exception) < 0 || + _PyDict_SetItemId(context, &PyId_future, (PyObject*)fut) < 0) { + goto finally; + } + if (fut->fut_source_tb != NULL) { + if (_PyDict_SetItemId(context, &PyId_source_traceback, + fut->fut_source_tb) < 0) { + goto finally; + } + } + + func = _PyObject_GetAttrId(fut->fut_loop, &PyId_call_exception_handler); + if (func != NULL) { + res = _PyObject_CallArg1(func, context); + if (res == NULL) { + PyErr_WriteUnraisable(func); + } + } + +finally: + Py_CLEAR(context); + Py_CLEAR(type_name); + Py_CLEAR(message); + Py_CLEAR(func); + Py_CLEAR(res); + + /* Restore the saved exception. */ + PyErr_Restore(error_type, error_value, error_traceback); +} + + +static PyAsyncMethods FutureType_as_async = { + (unaryfunc)new_future_iter, /* am_await */ + 0, /* am_aiter */ + 0 /* am_anext */ +}; + +static PyMethodDef FutureType_methods[] = { + {"_repr_info", (PyCFunction)FutureObj__repr_info, METH_NOARGS, NULL}, + {"add_done_callback", + (PyCFunction)FutureObj_add_done_callback, + METH_O, pydoc_add_done_callback}, + {"remove_done_callback", + (PyCFunction)FutureObj_remove_done_callback, + METH_O, pydoc_remove_done_callback}, + {"set_result", + (PyCFunction)FutureObj_set_result, METH_O, pydoc_set_result}, + {"set_exception", + (PyCFunction)FutureObj_set_exception, METH_O, pydoc_set_exception}, + {"cancel", (PyCFunction)FutureObj_cancel, METH_NOARGS, pydoc_cancel}, + {"cancelled", + (PyCFunction)FutureObj_cancelled, METH_NOARGS, pydoc_cancelled}, + {"done", (PyCFunction)FutureObj_done, METH_NOARGS, pydoc_done}, + {"result", (PyCFunction)FutureObj_result, METH_NOARGS, pydoc_result}, + {"exception", + (PyCFunction)FutureObj_exception, METH_NOARGS, pydoc_exception}, + {NULL, NULL} /* Sentinel */ +}; + +static PyGetSetDef FutureType_getsetlist[] = { + {"_state", (getter)FutureObj_get_state, NULL, NULL}, + {"_asyncio_future_blocking", (getter)FutureObj_get_blocking, + (setter)FutureObj_set_blocking, NULL}, + {"_loop", (getter)FutureObj_get_loop, NULL, NULL}, + {"_callbacks", (getter)FutureObj_get_callbacks, NULL, NULL}, + {"_result", (getter)FutureObj_get_result, NULL, NULL}, + {"_exception", (getter)FutureObj_get_exception, NULL, NULL}, + {"_log_traceback", (getter)FutureObj_get_log_traceback, NULL, NULL}, + {"_source_traceback", (getter)FutureObj_get_source_traceback, NULL, NULL}, + {NULL} /* Sentinel */ +}; + +static void FutureObj_dealloc(PyObject *self); + +static PyTypeObject FutureType = { + PyVarObject_HEAD_INIT(0, 0) + "_asyncio.Future", + sizeof(FutureObj), /* tp_basicsize */ + .tp_dealloc = FutureObj_dealloc, + .tp_as_async = &FutureType_as_async, + .tp_repr = (reprfunc)FutureObj_repr, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE + | Py_TPFLAGS_HAVE_FINALIZE, + .tp_doc = "Fast asyncio.Future implementation.", + .tp_traverse = (traverseproc)FutureObj_traverse, + .tp_clear = (inquiry)FutureObj_clear, + .tp_weaklistoffset = offsetof(FutureObj, fut_weakreflist), + .tp_iter = (getiterfunc)new_future_iter, + .tp_methods = FutureType_methods, + .tp_getset = FutureType_getsetlist, + .tp_dictoffset = offsetof(FutureObj, dict), + .tp_init = (initproc)FutureObj_init, + .tp_new = PyType_GenericNew, + .tp_finalize = (destructor)FutureObj_finalize, +}; + +static void +FutureObj_dealloc(PyObject *self) +{ + FutureObj *fut = (FutureObj *)self; + + if (Py_TYPE(fut) == &FutureType) { + /* When fut is subclass of Future, finalizer is called from + * subtype_dealloc. + */ + if (PyObject_CallFinalizerFromDealloc(self) < 0) { + // resurrected. + return; + } + } + + if (fut->fut_weakreflist != NULL) { + PyObject_ClearWeakRefs(self); + } + + FutureObj_clear(fut); + Py_TYPE(fut)->tp_free(fut); +} + + +/*********************** Future Iterator **************************/ + +typedef struct { + PyObject_HEAD + FutureObj *future; +} futureiterobject; + +static void +FutureIter_dealloc(futureiterobject *it) +{ + _PyObject_GC_UNTRACK(it); + Py_XDECREF(it->future); + PyObject_GC_Del(it); +} + +static PyObject * +FutureIter_iternext(futureiterobject *it) +{ + PyObject *res; + FutureObj *fut = it->future; + + if (fut == NULL) { + return NULL; + } + + if (fut->fut_state == STATE_PENDING) { + if (!fut->fut_blocking) { + fut->fut_blocking = 1; + Py_INCREF(fut); + return (PyObject *)fut; + } + PyErr_Format(PyExc_AssertionError, + "yield from wasn't used with future"); + return NULL; + } + + res = FutureObj_result(fut, NULL); + if (res != NULL) { + // normal result + PyErr_SetObject(PyExc_StopIteration, res); + Py_DECREF(res); + } + + it->future = NULL; + Py_DECREF(fut); + return NULL; +} + +static PyObject * +FutureIter_send(futureiterobject *self, PyObject *arg) +{ + if (arg != Py_None) { + PyErr_Format(PyExc_TypeError, + "can't send non-None value to a FutureIter"); + return NULL; + } + return FutureIter_iternext(self); +} + +static PyObject * +FutureIter_throw(futureiterobject *self, PyObject *args) +{ + PyObject *type=NULL, *val=NULL, *tb=NULL; + if (!PyArg_ParseTuple(args, "O|OO", &type, &val, &tb)) + return NULL; + + if (val == Py_None) { + val = NULL; + } + if (tb == Py_None) { + tb = NULL; + } + + Py_CLEAR(self->future); + + if (tb != NULL) { + PyErr_Restore(type, val, tb); + } + else if (val != NULL) { + PyErr_SetObject(type, val); + } + else { + if (PyExceptionClass_Check(type)) { + val = PyObject_CallObject(type, NULL); + } + else { + val = type; + assert (PyExceptionInstance_Check(val)); + type = (PyObject*)Py_TYPE(val); + assert (PyExceptionClass_Check(type)); + } + PyErr_SetObject(type, val); + } + return FutureIter_iternext(self); +} + +static PyObject * +FutureIter_close(futureiterobject *self, PyObject *arg) +{ + Py_CLEAR(self->future); + Py_RETURN_NONE; +} + +static int +FutureIter_traverse(futureiterobject *it, visitproc visit, void *arg) +{ + Py_VISIT(it->future); + return 0; +} + +static PyMethodDef FutureIter_methods[] = { + {"send", (PyCFunction)FutureIter_send, METH_O, NULL}, + {"throw", (PyCFunction)FutureIter_throw, METH_VARARGS, NULL}, + {"close", (PyCFunction)FutureIter_close, METH_NOARGS, NULL}, + {NULL, NULL} /* Sentinel */ +}; + +static PyTypeObject FutureIterType = { + PyVarObject_HEAD_INIT(0, 0) + "_asyncio.FutureIter", + sizeof(futureiterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)FutureIter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_as_async */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + (traverseproc)FutureIter_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)FutureIter_iternext, /* tp_iternext */ + FutureIter_methods, /* tp_methods */ + 0, /* tp_members */ +}; + +static PyObject * +new_future_iter(PyObject *fut) +{ + futureiterobject *it; + + if (!PyObject_TypeCheck(fut, &FutureType)) { + PyErr_BadInternalCall(); + return NULL; + } + it = PyObject_GC_New(futureiterobject, &FutureIterType); + if (it == NULL) { + return NULL; + } + Py_INCREF(fut); + it->future = (FutureObj*)fut; + PyObject_GC_Track(it); + return (PyObject*)it; +} + +/*********************** Module **************************/ + +PyDoc_STRVAR(module_doc, "asyncio speedups.\n"); + +PyObject * +_init_module(PyObject *self, PyObject *args) +{ + PyObject *extract_stack; + PyObject *get_event_loop; + PyObject *repr_info_func; + PyObject *invalidStateError; + PyObject *cancelledError; + + if (!PyArg_UnpackTuple(args, "_init_module", 5, 5, + &extract_stack, + &get_event_loop, + &repr_info_func, + &invalidStateError, + &cancelledError)) { + return NULL; + } + + Py_INCREF(extract_stack); + Py_XSETREF(traceback_extract_stack, extract_stack); + + Py_INCREF(get_event_loop); + Py_XSETREF(asyncio_get_event_loop, get_event_loop); + + Py_INCREF(repr_info_func); + Py_XSETREF(asyncio_repr_info_func, repr_info_func); + + Py_INCREF(invalidStateError); + Py_XSETREF(asyncio_InvalidStateError, invalidStateError); + + Py_INCREF(cancelledError); + Py_XSETREF(asyncio_CancelledError, cancelledError); + + _asynciomod_ready = 1; + + Py_RETURN_NONE; +} + + +static struct PyMethodDef asynciomod_methods[] = { + {"_init_module", _init_module, METH_VARARGS, NULL}, + {NULL, NULL} +}; + + +static struct PyModuleDef _asynciomodule = { + PyModuleDef_HEAD_INIT, /* m_base */ + "_asyncio", /* m_name */ + module_doc, /* m_doc */ + -1, /* m_size */ + asynciomod_methods, /* m_methods */ + NULL, /* m_slots */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ +}; + + +PyMODINIT_FUNC +PyInit__asyncio(void) +{ + if (PyType_Ready(&FutureType) < 0) { + return NULL; + } + if (PyType_Ready(&FutureIterType) < 0) { + return NULL; + } + + PyObject *m = PyModule_Create(&_asynciomodule); + if (m == NULL) { + return NULL; + } + + Py_INCREF(&FutureType); + if (PyModule_AddObject(m, "Future", (PyObject *)&FutureType) < 0) { + Py_DECREF(&FutureType); + return NULL; + } + + return m; +} |