From 9f2ce2548107eedaf0970546a508c33d24920622 Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Sat, 15 Oct 2016 15:39:19 +0900 Subject: Issue #28428: Rename _futures module to _asyncio. It will have more speedup functions or classes other than asyncio.Future. --- Lib/asyncio/futures.py | 6 +- Modules/Setup.dist | 2 +- Modules/_asynciomodule.c | 1034 ++++++++++++++++++++++++++++++++++++ Modules/_futuresmodule.c | 1034 ------------------------------------ PCbuild/pythoncore.vcxproj | 2 +- PCbuild/pythoncore.vcxproj.filters | 6 +- setup.py | 4 +- 7 files changed, 1044 insertions(+), 1044 deletions(-) create mode 100644 Modules/_asynciomodule.c delete mode 100644 Modules/_futuresmodule.c diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py index 7c5b1aa..87ae30a 100644 --- a/Lib/asyncio/futures.py +++ b/Lib/asyncio/futures.py @@ -432,18 +432,18 @@ def _copy_future_state(source, dest): try: - import _futures + import _asyncio except ImportError: pass else: - _futures._init_module( + _asyncio._init_module( traceback.extract_stack, events.get_event_loop, _future_repr_info, InvalidStateError, CancelledError) - Future = _futures.Future + Future = _asyncio.Future def _chain_future(source, destination): diff --git a/Modules/Setup.dist b/Modules/Setup.dist index 3211bef..8b87fc8 100644 --- a/Modules/Setup.dist +++ b/Modules/Setup.dist @@ -181,7 +181,7 @@ _symtable symtablemodule.c #_datetime _datetimemodule.c # datetime accelerator #_bisect _bisectmodule.c # Bisection algorithms #_heapq _heapqmodule.c # Heap queue algorithm -#_futures _futuresmodule.c # Fast asyncio Future +#_asyncio _asynciomodule.c # Fast asyncio Future #unicodedata unicodedata.c # static Unicode character database 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; +} diff --git a/Modules/_futuresmodule.c b/Modules/_futuresmodule.c deleted file mode 100644 index 3e91a3c..0000000 --- a/Modules/_futuresmodule.c +++ /dev/null @@ -1,1034 +0,0 @@ -#include "Python.h" -#include "structmember.h" - - -/* identifiers used from some functions */ -_Py_IDENTIFIER(call_soon); - - -/* State of the _futures module */ -static int _futuremod_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 -_FuturesMod_EnsureState(void) -{ - if (!_futuremod_ready) { - PyErr_SetString(PyExc_RuntimeError, - "_futures 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 (_FuturesMod_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 (_FuturesMod_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 (_FuturesMod_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 (_FuturesMod_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) - "_futures.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) - "_futures.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, "Fast asyncio.Future implementation.\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); - - _futuremod_ready = 1; - - Py_RETURN_NONE; -} - - -static struct PyMethodDef futuresmod_methods[] = { - {"_init_module", _init_module, METH_VARARGS, NULL}, - {NULL, NULL} -}; - - -static struct PyModuleDef _futuresmodule = { - PyModuleDef_HEAD_INIT, /* m_base */ - "_futures", /* m_name */ - module_doc, /* m_doc */ - -1, /* m_size */ - futuresmod_methods, /* m_methods */ - NULL, /* m_slots */ - NULL, /* m_traverse */ - NULL, /* m_clear */ - NULL, /* m_free */ -}; - - -PyMODINIT_FUNC -PyInit__futures(void) -{ - if (PyType_Ready(&FutureType) < 0) { - return NULL; - } - if (PyType_Ready(&FutureIterType) < 0) { - return NULL; - } - - PyObject *m = PyModule_Create(&_futuresmodule); - if (m == NULL) { - return NULL; - } - - Py_INCREF(&FutureType); - if (PyModule_AddObject(m, "Future", (PyObject *)&FutureType) < 0) { - Py_DECREF(&FutureType); - return NULL; - } - - return m; -} diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 1507adb..aa6ba74 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -213,6 +213,7 @@ + @@ -221,7 +222,6 @@ - diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index ef24333..a45b9d9 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -446,6 +446,9 @@ + + Modules + Modules @@ -470,9 +473,6 @@ Modules - - Modules - Modules diff --git a/setup.py b/setup.py index 1d4a7f8..b54ef81 100644 --- a/setup.py +++ b/setup.py @@ -656,8 +656,8 @@ class PyBuildExt(build_ext): depends=['unicodedata_db.h', 'unicodename_db.h']) ) # _opcode module exts.append( Extension('_opcode', ['_opcode.c']) ) - # Fast asyncio Future implementation - exts.append( Extension("_futures", ["_futuresmodule.c"]) ) + # asyncio speedups + exts.append( Extension("_asyncio", ["_asynciomodule.c"]) ) # Modules with some UNIX dependencies -- on by default: # (If you have a really backward UNIX, select and socket may not be -- cgit v0.12