diff -r 8ee02ec9b634 Lib/asyncio/futures.py
--- a/Lib/asyncio/futures.py Sat Jan 09 23:56:40 2016 -0800
+++ b/Lib/asyncio/futures.py Mon Jan 11 12:19:13 2016 -0500
@@ -110,50 +110,7 @@
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 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))
-
+class _BaseFuture:
def __format_callbacks(self):
cb = self._callbacks
size = len(cb)
@@ -214,6 +171,51 @@
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.
@@ -405,6 +407,23 @@
dest.set_result(result)
+try:
+ import _futures
+except ImportError:
+ pass
+else:
+ # class Future(_futures.Future, _BaseFuture):
+ # pass
+
+ Future = _futures.Future
+
+ _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.
diff -r 8ee02ec9b634 Lib/asyncio/tasks.py
--- a/Lib/asyncio/tasks.py Sat Jan 09 23:56:40 2016 -0800
+++ b/Lib/asyncio/tasks.py Mon Jan 11 12:19:13 2016 -0500
@@ -80,7 +80,7 @@
# On Python 3.3 or older, objects with a destructor that are part of a
# reference cycle are never destroyed. That's not the case any more on
# Python 3.4 thanks to the PEP 442.
- if compat.PY34:
+ if compat.PY34 and 0:
def __del__(self):
if self._state == futures._PENDING and self._log_destroy_pending:
context = {
@@ -90,7 +90,7 @@
if self._source_traceback:
context['source_traceback'] = self._source_traceback
self._loop.call_exception_handler(context)
- futures.Future.__del__(self)
+ super().__del__()
def _repr_info(self):
info = super()._repr_info()
diff -r 8ee02ec9b634 Modules/Setup.dist
--- a/Modules/Setup.dist Sat Jan 09 23:56:40 2016 -0800
+++ b/Modules/Setup.dist Mon Jan 11 12:19:13 2016 -0500
@@ -180,6 +180,7 @@
#_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
diff -r 8ee02ec9b634 Modules/_futuresmodule.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Modules/_futuresmodule.c Mon Jan 11 12:19:13 2016 -0500
@@ -0,0 +1,742 @@
+#include "Python.h"
+#include "structmember.h"
+
+/*
+TODO
+
+1. expose read-only '_state' prop
+2. add _init_futuresmod
+3. This isn't a Future class; it's a BaseFuture
+*/
+
+
+/* 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;
+ _Py_IDENTIFIER(call_soon);
+
+ 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 PyObject *
+FutureObj_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ FuturesModState *st;
+ FutureObj *fut;
+
+ st = _FuturesMod_EnsureState();
+ if (st == NULL)
+ return NULL;
+
+ fut = PyObject_GC_New(FutureObj, type);
+ if (fut == NULL)
+ return NULL;
+
+ fut->dict = NULL;
+
+ fut->fut_modstate = st;
+ fut->fut_state = STATE_PENDING;
+ fut->fut_log_tb = 0;
+ fut->fut_blocking = 0;
+ fut->fut_exception = NULL;
+ fut->fut_result = NULL;
+ fut->fut_loop = NULL;
+ fut->fut_callbacks = NULL;
+ fut->fut_weakreflist = NULL;
+ fut->fut_source_tb = NULL;
+
+ PyObject_GC_Track(fut);
+ return (PyObject *)fut;
+}
+
+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 (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &loop))
+ return -1;
+ if (loop == NULL || loop == Py_None) {
+ Py_CLEAR(loop);
+ loop = PyObject_CallObject(fut->fut_modstate->asyncio_get_event_loop,
+ NULL);
+ if (loop == NULL)
+ return -1;
+ } else {
+ Py_INCREF(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);
+ PyObject *arg_tuple = PyTuple_New(0);
+ fut->fut_source_tb = PyObject_Call(
+ fut->fut_modstate->traceback_extract_stack,
+ arg_tuple, NULL);
+ Py_CLEAR(arg_tuple);
+ 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 void
+FutureObj_dealloc(FutureObj *fut)
+{
+ PyObject_GC_UnTrack(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);
+
+ if (fut->fut_weakreflist != NULL)
+ PyObject_ClearWeakRefs((PyObject *)fut);
+
+ fut->fut_modstate = NULL;
+}
+
+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->dict);
+ Py_VISIT(fut->fut_source_tb);
+ return 0;
+}
+
+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;
+}
+
+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) {
+ Py_INCREF(fut->fut_exception);
+ return fut->fut_exception;
+ }
+
+ Py_RETURN_NONE;
+}
+
+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;
+}
+
+static PyObject *
+FutureObj_set_exception(FutureObj *fut, PyObject *exc)
+{
+ 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;
+ }
+
+ PyObject *exc_val = NULL;
+ if (PyExceptionClass_Check(exc)) {
+ exc_val = PyObject_CallObject(exc, NULL);
+ if (exc_val == NULL)
+ return NULL;
+ }
+ if (exc_val == NULL) {
+ 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;
+ }
+
+ 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;
+}
+
+static PyObject *
+FutureObj_add_done_callback(FutureObj *fut, PyObject *arg)
+{
+ PyObject *handle;
+ _Py_IDENTIFIER(call_soon);
+
+ if (fut->fut_state != STATE_PENDING) {
+ 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;
+}
+
+static PyObject *
+FutureObj_remove_done_callback(FutureObj *fut, PyObject *arg)
+{
+ /* XXX */
+ Py_ssize_t len;
+ len = PyList_GET_SIZE(fut->fut_callbacks);
+
+ if (len) {
+ if (PyList_SetSlice(fut->fut_callbacks, 0, len, NULL) < 0) {
+ return NULL;
+ }
+ }
+
+ Py_RETURN_NONE;
+}
+
+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;
+}
+
+static PyObject *
+FutureObj_cancelled(FutureObj *fut, PyObject *arg)
+{
+ if (fut->fut_state == STATE_CANCELLED) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+
+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_loop(FutureObj *fut)
+{
+ if (fut->fut_loop == NULL)
+ Py_RETURN_NONE;
+
+ Py_INCREF(fut->fut_loop);
+ return fut->fut_loop;
+}
+
+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)
+{
+ if (fut->fut_state == STATE_PENDING)
+ return PyUnicode_FromString("PENDING");
+
+ if (fut->fut_state == STATE_CANCELLED)
+ return PyUnicode_FromString("CANCELLED");
+
+ assert(fut->fut_state == STATE_FINISHED);
+ return PyUnicode_FromString("FINISHED");
+}
+
+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, NULL},
+ {"remove_done_callback", (PyCFunction)FutureObj_remove_done_callback,
+ METH_O, NULL},
+ {"set_result", (PyCFunction)FutureObj_set_result, METH_O, NULL},
+ {"set_exception", (PyCFunction)FutureObj_set_exception, METH_O, NULL},
+ {"cancel", (PyCFunction)FutureObj_cancel, METH_NOARGS, NULL},
+ {"cancelled", (PyCFunction)FutureObj_cancelled, METH_NOARGS, NULL},
+ {"done", (PyCFunction)FutureObj_done, METH_NOARGS, NULL},
+ {"result", (PyCFunction)FutureObj_result, METH_NOARGS, NULL},
+ {"exception", (PyCFunction)FutureObj_exception, METH_NOARGS, NULL},
+ {NULL, NULL} /* Sentinel */
+};
+
+static PyGetSetDef FutureType_getsetlist[] = {
+ {"_blocking", (getter)FutureObj_get_blocking,
+ (setter)FutureObj_set_blocking, NULL},
+ {"_loop", (getter)FutureObj_get_loop, NULL, NULL},
+ {"_exception", (getter)FutureObj_get_exception, NULL, NULL},
+ {"_source_traceback", (getter)FutureObj_get_source_traceback, NULL, NULL},
+ {"_state", (getter)FutureObj_get_state, NULL, NULL},
+ {NULL} /* Sentinel */
+};
+
+static PyTypeObject FutureType = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ "asyncio.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 */
+ PyObject_GenericGetAttr, /* 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 */
+ 0, /* 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,
+ 0,
+ 0,
+ 0,
+ offsetof(FutureObj, dict), /* tp_dictoffset */
+ (initproc)FutureObj_init, /* tp_init */
+ 0, /* tp_alloc */
+ FutureObj_new, /* tp_new */
+ PyObject_GC_Del, /* 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 8ee02ec9b634 PCbuild/pythoncore.vcxproj
--- a/PCbuild/pythoncore.vcxproj Sat Jan 09 23:56:40 2016 -0800
+++ b/PCbuild/pythoncore.vcxproj Mon Jan 11 12:19:13 2016 -0500
@@ -217,6 +217,7 @@
+
@@ -417,4 +418,4 @@
-
\ No newline at end of file
+
diff -r 8ee02ec9b634 PCbuild/pythoncore.vcxproj.filters
--- a/PCbuild/pythoncore.vcxproj.filters Sat Jan 09 23:56:40 2016 -0800
+++ b/PCbuild/pythoncore.vcxproj.filters Mon Jan 11 12:19:13 2016 -0500
@@ -455,6 +455,9 @@
Modules
+
+ Modules
+
Modules
@@ -980,4 +983,4 @@
Resource Files
-
\ No newline at end of file
+
diff -r 8ee02ec9b634 setup.py
--- a/setup.py Sat Jan 09 23:56:40 2016 -0800
+++ b/setup.py Mon Jan 11 12:19:13 2016 -0500
@@ -628,6 +628,8 @@
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