diff -r 46567fda0b29 Lib/asyncio/futures.py --- a/Lib/asyncio/futures.py Sat Jul 09 11:05:42 2016 +0200 +++ b/Lib/asyncio/futures.py Sun Jul 10 13:25:47 2016 +0900 @@ -105,59 +105,17 @@ if self.source_traceback: src = ''.join(traceback.format_list(self.source_traceback)) msg += 'Future/Task created at (most recent call last):\n' msg += '%s\n' % src.rstrip() msg += ''.join(self.tb).rstrip() self.loop.call_exception_handler({'message': msg}) -class Future: - """This class is *almost* compatible with concurrent.futures.Future. - - Differences: - - - result() and exception() do not take a timeout argument and - raise an exception when the future isn't done yet. - - - Callbacks registered with add_done_callback() are always called - via the event loop's call_soon_threadsafe(). - - - This class is not compatible with the wait() and as_completed() - methods in the concurrent.futures package. - - (In Python 3.4 or later we may be able to unify the implementations.) - """ - - # Class variables serving as defaults for instance variables. - _state = _PENDING - _result = None - _exception = None - _loop = None - _source_traceback = None - - _blocking = False # proper use of future (yield vs yield from) - - _log_traceback = False # Used for Python 3.4 and later - _tb_logger = None # Used for Python 3.3 only - - def __init__(self, *, loop=None): - """Initialize the future. - - The optional event_loop argument allows explicitly setting the event - loop object used by the future. If it's not provided, the future uses - the default event loop. - """ - if loop is None: - self._loop = events.get_event_loop() - else: - self._loop = loop - self._callbacks = [] - if self._loop.get_debug(): - self._source_traceback = traceback.extract_stack(sys._getframe(1)) +class _BaseFuture: def __format_callbacks(self): cb = self._callbacks size = len(cb) if not size: cb = '' def format_cb(callback): @@ -209,16 +167,61 @@ % self.__class__.__name__), 'exception': exc, 'future': self, } if self._source_traceback: context['source_traceback'] = self._source_traceback self._loop.call_exception_handler(context) + +class Future(_BaseFuture): + """This class is *almost* compatible with concurrent.futures.Future. + + Differences: + + - result() and exception() do not take a timeout argument and + raise an exception when the future isn't done yet. + + - Callbacks registered with add_done_callback() are always called + via the event loop's call_soon_threadsafe(). + + - This class is not compatible with the wait() and as_completed() + methods in the concurrent.futures package. + + (In Python 3.4 or later we may be able to unify the implementations.) + """ + + # Class variables serving as defaults for instance variables. + _state = _PENDING + _result = None + _exception = None + _loop = None + _source_traceback = None + + _blocking = False # proper use of future (yield vs yield from) + + _log_traceback = False # Used for Python 3.4 and later + _tb_logger = None # Used for Python 3.3 only + + def __init__(self, *, loop=None): + """Initialize the future. + + The optional event_loop argument allows to explicitly set the event + loop object used by the future. If it's not provided, the future uses + the default event loop. + """ + if loop is None: + self._loop = events.get_event_loop() + else: + self._loop = loop + self._callbacks = [] + if self._loop.get_debug(): + self._source_traceback = traceback.extract_stack(sys._getframe(1)) + def cancel(self): """Cancel the future and schedule callbacks. If the future is already done or cancelled, return False. Otherwise, change the future's state to cancelled, schedule the callbacks and return True. """ if self._state != _PENDING: @@ -403,16 +406,31 @@ exception = source.exception() if exception is not None: dest.set_exception(exception) else: result = source.result() dest.set_result(result) +try: + import _futures +except ImportError: + pass +else: + class Future(_BaseFuture, _futures.Future): + pass + + _futures._init_module( + traceback.extract_stack, + events.get_event_loop, + InvalidStateError, + CancelledError) + + def _chain_future(source, destination): """Chain two futures so that when one completes, so does the other. The result (or exception) of source will be copied to destination. If destination is cancelled, source gets cancelled too. Compatible with both asyncio.Future and concurrent.futures.Future. """ if not isinstance(source, (Future, concurrent.futures.Future)): diff -r 46567fda0b29 Modules/Setup.dist --- a/Modules/Setup.dist Sat Jul 09 11:05:42 2016 +0200 +++ b/Modules/Setup.dist Sun Jul 10 13:25:47 2016 +0900 @@ -175,16 +175,17 @@ #_weakref _weakref.c # basic weak reference support #_testcapi _testcapimodule.c # Python C API test module #_random _randommodule.c # Random number generator #_elementtree -I$(srcdir)/Modules/expat -DHAVE_EXPAT_CONFIG_H -DUSE_PYEXPAT_CAPI _elementtree.c # elementtree accelerator #_pickle _pickle.c # pickle accelerator #_datetime _datetimemodule.c # datetime accelerator #_bisect _bisectmodule.c # Bisection algorithms #_heapq _heapqmodule.c # Heap queue algorithm +#_futures _futuresmodule.c # Fast asyncio Future #unicodedata unicodedata.c # static Unicode character database # Modules with some UNIX dependencies -- on by default: # (If you have a really backward UNIX, select and socket may not be # supported...) diff -r 46567fda0b29 Modules/_futuresmodule.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Modules/_futuresmodule.c Sun Jul 10 13:25:47 2016 +0900 @@ -0,0 +1,856 @@ +#include "Python.h" +#include "structmember.h" + + +/* identifiers used from some functions */ +_Py_IDENTIFIER(call_soon); + + +/* State of the _futures module */ +typedef struct { + int ready; + + PyObject *traceback_extract_stack; + PyObject *asyncio_get_event_loop; + PyObject *asyncio_InvalidStateError; + PyObject *asyncio_CancelledError; +} FuturesModState; + + +/* Forward declaration of the _futures module definition. */ +static struct PyModuleDef _futuresmodule; + + +/* Given a module object, get its per-module state. */ +static FuturesModState * +_FuturesMod_GetState(PyObject *module) +{ + return (FuturesModState *) PyModule_GetState(module); +} + + +/* Find the module instance imported in the currently running sub-interpreter + and get the module's state. */ +static FuturesModState * +_FuturesMod_GetGlobalState(void) +{ + PyObject *m = PyState_FindModule(&_futuresmodule); + if (m == NULL) + return NULL; + return _FuturesMod_GetState(m); +} + + +/* Get the global module state and make sure it's initialized + and ready to be used. */ +static FuturesModState * +_FuturesMod_EnsureState(void) +{ + FuturesModState *st = _FuturesMod_GetGlobalState(); + + if (st == NULL) + goto error; + + if (!st->ready) + goto error; + + return st; + + error: + PyErr_SetString(PyExc_RuntimeError, + "_futures module wasn't properly initialized"); + return NULL; +} + + +/* Clear the given _futures module state. */ +static void +_FuturesMod_ClearState(FuturesModState *st) +{ + st->ready = 0; + Py_CLEAR(st->traceback_extract_stack); + Py_CLEAR(st->asyncio_get_event_loop); + Py_CLEAR(st->asyncio_InvalidStateError); + Py_CLEAR(st->asyncio_CancelledError); +} + + +/* Initialize the given pickle module state. */ +static int +_FuturesMod_InitState(PyObject *module) +{ + FuturesModState *st; + + st = _FuturesMod_GetState(module); + if (st == NULL) + return -1; + + st->ready = 0; + st->traceback_extract_stack = NULL; + st->asyncio_get_event_loop = NULL; + st->asyncio_InvalidStateError = NULL; + st->asyncio_CancelledError = NULL; + return 0; +} + + +typedef enum { + STATE_PENDING, + STATE_CANCELLED, + STATE_FINISHED +} fut_state; + + +typedef struct { + PyObject_HEAD + FuturesModState *fut_modstate; + 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; + FuturesModState *st; + _Py_IDENTIFIER(get_debug); + + st = _FuturesMod_EnsureState(); + if (st == NULL) + return -1; + fut->fut_modstate = st; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|$O", kwlist, &loop)) + return -1; + if (loop == NULL || loop == Py_None) { + loop = PyObject_CallObject(fut->fut_modstate->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( + fut->fut_modstate->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 void +FutureObj_dealloc(FutureObj *fut) +{ + FutureObj_clear(fut); + + if (fut->fut_weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *)fut); + + fut->fut_modstate = NULL; + Py_TYPE(fut)->tp_free(fut); +} + +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(fut->fut_modstate->asyncio_CancelledError, ""); + return NULL; + } + + if (fut->fut_state != STATE_FINISHED) { + PyErr_SetString(fut->fut_modstate->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) +{ + FuturesModState *st; + + st = _FuturesMod_EnsureState(); + if (st == NULL) + return NULL; + + if (fut->fut_state == STATE_CANCELLED) { + PyErr_SetString(fut->fut_modstate->asyncio_CancelledError, ""); + return NULL; + } + + if (fut->fut_state != STATE_FINISHED) { + PyErr_SetString(fut->fut_modstate->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) +{ + FuturesModState *st; + + st = _FuturesMod_EnsureState(); + if (st == NULL) + return NULL; + + if (fut->fut_state != STATE_PENDING) { + PyErr_SetString(fut->fut_modstate->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) +{ + FuturesModState *st; + PyObject *exc_val = NULL; + + st = _FuturesMod_EnsureState(); + if (st == NULL) + return NULL; + + if (fut->fut_state != STATE_PENDING) { + PyErr_SetString(fut->fut_modstate->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; +} + +static PyObject * +FutureObj_await(FutureObj *fut) +{ + Py_INCREF(fut); + return (PyObject *)fut; +} + +static PyObject * +FutureObj_iternext(FutureObj *fut) +{ + PyObject *res; + + 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) + return NULL; + + // normal result + PyErr_SetObject(PyExc_StopIteration, res); + Py_DECREF(res); + + return NULL; +} + +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_XDECREF(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) +{ + if (PyObject_IsTrue(val)) { + fut->fut_blocking = 1; + } else { + fut->fut_blocking = 0; + } + 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 PyAsyncMethods FutureType_as_async = { + (unaryfunc)FutureObj_await, /* am_await */ + 0, /* am_aiter */ + 0 /* am_anext */ +}; + +static PyMethodDef FutureType_methods[] = { + {"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}, + {"_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 PyTypeObject FutureType = { + PyVarObject_HEAD_INIT(0, 0) + "_futures.Future", + sizeof(FutureObj), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)FutureObj_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + &FutureType_as_async, /* 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 */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC + | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "Fast asyncio.Future implementation.", /* tp_doc */ + (traverseproc)FutureObj_traverse, /* tp_traverse */ + (inquiry)FutureObj_clear, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(FutureObj, fut_weakreflist), /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)FutureObj_iternext, /* tp_iternext */ + FutureType_methods, /* tp_methods */ + 0, /* tp_members */ + FutureType_getsetlist, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + offsetof(FutureObj, dict), /* tp_dictoffset */ + (initproc)FutureObj_init, /* tp_init */ + 0, /* tp_alloc */ + PyType_GenericNew, /* tp_new */ + 0, /* tp_free */ +}; + + +PyDoc_STRVAR(module_doc, "Fast asyncio.Future implementation.\n"); + + +PyObject * +_init_module(PyObject *self, PyObject *args) +{ + FuturesModState *st; + + PyObject *traceback_extract_stack; + PyObject *asyncio_get_event_loop; + PyObject *asyncio_InvalidStateError; + PyObject *asyncio_CancelledError; + + if (!PyArg_UnpackTuple(args, "_init_module", 4, 4, + &traceback_extract_stack, + &asyncio_get_event_loop, + &asyncio_InvalidStateError, + &asyncio_CancelledError)) + return NULL; + + st = _FuturesMod_GetGlobalState(); + assert(st != NULL); + + Py_INCREF(traceback_extract_stack); + st->traceback_extract_stack = traceback_extract_stack; + + Py_INCREF(asyncio_get_event_loop); + st->asyncio_get_event_loop = asyncio_get_event_loop; + + Py_INCREF(asyncio_InvalidStateError); + st->asyncio_InvalidStateError = asyncio_InvalidStateError; + + Py_INCREF(asyncio_CancelledError); + st->asyncio_CancelledError = asyncio_CancelledError; + + st->ready = 1; + + Py_RETURN_NONE; +} + + +static void +futuresmod_free(PyObject *m) +{ + _FuturesMod_ClearState(_FuturesMod_GetState(m)); +} + + +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 */ + sizeof(FuturesModState), /* m_size */ + futuresmod_methods, /* m_methods */ + NULL, /* m_slots */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + (freefunc)futuresmod_free /* m_free */ +}; + + +PyMODINIT_FUNC +PyInit__futures(void) +{ + PyObject *m; + + m = PyState_FindModule(&_futuresmodule); + if (m) { + Py_INCREF(m); + return m; + } + + if (PyType_Ready(&FutureType) < 0) + return NULL; + + 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; + } + + if (_FuturesMod_InitState(m) < 0) + return NULL; + + return m; +} diff -r 46567fda0b29 PCbuild/pythoncore.vcxproj --- a/PCbuild/pythoncore.vcxproj Sat Jul 09 11:05:42 2016 +0200 +++ b/PCbuild/pythoncore.vcxproj Sun Jul 10 13:25:47 2016 +0900 @@ -213,16 +213,17 @@ + diff -r 46567fda0b29 PCbuild/pythoncore.vcxproj.filters --- a/PCbuild/pythoncore.vcxproj.filters Sat Jul 09 11:05:42 2016 +0200 +++ b/PCbuild/pythoncore.vcxproj.filters Sun Jul 10 13:25:47 2016 +0900 @@ -456,16 +456,19 @@ Modules Modules Modules + + Modules + Modules Modules Modules diff -r 46567fda0b29 setup.py --- a/setup.py Sat Jul 09 11:05:42 2016 +0200 +++ b/setup.py Sun Jul 10 13:25:47 2016 +0900 @@ -650,16 +650,18 @@ # Test multi-phase extension module init (PEP 489) exts.append( Extension('_testmultiphase', ['_testmultiphase.c']) ) # profiler (_lsprof is for cProfile.py) exts.append( Extension('_lsprof', ['_lsprof.c', 'rotatingtree.c']) ) # static Unicode character database exts.append( Extension('unicodedata', ['unicodedata.c']) ) # _opcode module exts.append( Extension('_opcode', ['_opcode.c']) ) + # Fast asyncio Future implementation + exts.append( Extension("_futures", ["_futuresmodule.c"]) ) # Modules with some UNIX dependencies -- on by default: # (If you have a really backward UNIX, select and socket may not be # supported...) # fcntl(2) and ioctl(2) libs = [] if (config_h_vars.get('FLOCK_NEEDS_LIBBSD', False)):