#ifndef Py_BUILD_CORE_BUILTIN
# define Py_BUILD_CORE_MODULE 1
#endif
#include "Python.h"
#include "pycore_pyerrors.h"
#include "pycore_pystate.h"
#include "pycore_runtime_init.h"
#include "pycore_moduleobject.h"
#include "structmember.h"
#include <stddef.h>
#define FI_FREELIST_MAXLEN 255
typedef struct futureiterobject futureiterobject;
typedef struct {
PyTypeObject *FutureIterType;
PyTypeObject *TaskStepMethWrapper_Type;
PyTypeObject *FutureType;
PyTypeObject *TaskType;
PyObject *asyncio_mod;
PyObject *context_kwname;
PyObject *current_tasks;
PyObject *scheduled_tasks;
PyObject *eager_tasks;
PyObject *iscoroutine_typecache;
PyObject *asyncio_get_event_loop_policy;
PyObject *asyncio_future_repr_func;
PyObject *asyncio_CancelledError;
PyObject *asyncio_InvalidStateError;
PyObject *asyncio_task_get_stack_func;
PyObject *asyncio_task_print_stack_func;
PyObject *asyncio_task_repr_func;
PyObject *asyncio_iscoroutine_func;
PyObject *traceback_extract_stack;
PyObject *cached_running_loop;
volatile uint64_t cached_running_loop_tsid;
uint64_t task_name_counter;
futureiterobject *fi_freelist;
Py_ssize_t fi_freelist_len;
} asyncio_state;
static inline asyncio_state *
get_asyncio_state(PyObject *mod)
{
asyncio_state *state = _PyModule_GetState(mod);
assert(state != NULL);
return state;
}
static inline asyncio_state *
get_asyncio_state_by_cls(PyTypeObject *cls)
{
asyncio_state *state = (asyncio_state *)_PyType_GetModuleState(cls);
assert(state != NULL);
return state;
}
static struct PyModuleDef _asynciomodule;
static inline asyncio_state *
get_asyncio_state_by_def(PyObject *self)
{
PyTypeObject *tp = Py_TYPE(self);
PyObject *mod = PyType_GetModuleByDef(tp, &_asynciomodule);
assert(mod != NULL);
return get_asyncio_state(mod);
}
typedef enum {
STATE_PENDING,
STATE_CANCELLED,
STATE_FINISHED
} fut_state;
#define FutureObj_HEAD(prefix) \
PyObject_HEAD \
PyObject *prefix##_loop; \
PyObject *prefix##_callback0; \
PyObject *prefix##_context0; \
PyObject *prefix##_callbacks; \
PyObject *prefix##_exception; \
PyObject *prefix##_exception_tb; \
PyObject *prefix##_result; \
PyObject *prefix##_source_tb; \
PyObject *prefix##_cancel_msg; \
PyObject *prefix##_weakreflist; \
PyObject *prefix##_cancelled_exc; \
fut_state prefix##_state; \
\
unsigned prefix##_log_tb: 1; \
unsigned prefix##_blocking: 1;
typedef struct {
FutureObj_HEAD(fut)
} FutureObj;
typedef struct {
FutureObj_HEAD(task)
unsigned task_must_cancel: 1;
unsigned task_log_destroy_pending: 1;
int task_num_cancels_requested;
PyObject *task_fut_waiter;
PyObject *task_coro;
PyObject *task_name;
PyObject *task_context;
} TaskObj;
typedef struct {
PyObject_HEAD
TaskObj *sw_task;
PyObject *sw_arg;
} TaskStepMethWrapper;
#define Future_CheckExact(state, obj) Py_IS_TYPE(obj, state->FutureType)
#define Task_CheckExact(state, obj) Py_IS_TYPE(obj, state->TaskType)
#define Future_Check(state, obj) PyObject_TypeCheck(obj, state->FutureType)
#define Task_Check(state, obj) PyObject_TypeCheck(obj, state->TaskType)
#include "clinic/_asynciomodule.c.h"
static PyObject * future_new_iter(PyObject *);
static PyObject *
task_step_handle_result_impl(asyncio_state *state, TaskObj *task, PyObject *result);
static int
_is_coroutine(asyncio_state *state, PyObject *coro)
{
PyObject *res = PyObject_CallOneArg(state->asyncio_iscoroutine_func, coro);
if (res == NULL) {
return -1;
}
int is_res_true = PyObject_IsTrue(res);
Py_DECREF(res);
if (is_res_true <= 0) {
return is_res_true;
}
if (PySet_GET_SIZE(state->iscoroutine_typecache) < 100) {
if (PySet_Add(state->iscoroutine_typecache, (PyObject*) Py_TYPE(coro))) {
return -1;
}
}
return 1;
}
static inline int
is_coroutine(asyncio_state *state, PyObject *coro)
{
if (PyCoro_CheckExact(coro)) {
return 1;
}
int has_it = PySet_Contains(
state->iscoroutine_typecache, (PyObject*) Py_TYPE(coro));
if (has_it == 0) {
return _is_coroutine(state, coro);
}
return has_it;
}
static PyObject *
get_future_loop(asyncio_state *state, PyObject *fut)
{
PyObject *getloop;
if (Future_CheckExact(state, fut) || Task_CheckExact(state, fut)) {
PyObject *loop = ((FutureObj *)fut)->fut_loop;
return Py_NewRef(loop);
}
if (_PyObject_LookupAttr(fut, &_Py_ID(get_loop), &getloop) < 0) {
return NULL;
}
if (getloop != NULL) {
PyObject *res = PyObject_CallNoArgs(getloop);
Py_DECREF(getloop);
return res;
}
return PyObject_GetAttr(fut, &_Py_ID(_loop));
}
static int
get_running_loop(asyncio_state *state, PyObject **loop)
{
PyObject *rl;
PyThreadState *ts = _PyThreadState_GET();
uint64_t ts_id = PyThreadState_GetID(ts);
if (state->cached_running_loop_tsid == ts_id &&
state->cached_running_loop != NULL)
{
rl = state->cached_running_loop;
}
else {
PyObject *ts_dict = _PyThreadState_GetDict(ts);
if (ts_dict == NULL) {
goto not_found;
}
rl = PyDict_GetItemWithError(
ts_dict, &_Py_ID(__asyncio_running_event_loop__));
if (rl == NULL) {
if (PyErr_Occurred()) {
goto error;
}
else {
goto not_found;
}
}
state->cached_running_loop = rl;
state->cached_running_loop_tsid = ts_id;
}
if (rl == Py_None) {
goto not_found;
}
*loop = Py_NewRef(rl);
return 0;
not_found:
*loop = NULL;
return 0;
error:
*loop = NULL;
return -1;
}
static int
set_running_loop(asyncio_state *state, PyObject *loop)
{
PyObject *ts_dict = NULL;
PyThreadState *tstate = _PyThreadState_GET();
if (tstate != NULL) {
ts_dict = _PyThreadState_GetDict(tstate);
}
if (ts_dict == NULL) {
PyErr_SetString(
PyExc_RuntimeError, "thread-local storage is not available");
return -1;
}
if (PyDict_SetItem(
ts_dict, &_Py_ID(__asyncio_running_event_loop__), loop) < 0)
{
return -1;
}
state->cached_running_loop = loop;
state->cached_running_loop_tsid = PyThreadState_GetID(tstate);
return 0;
}
static PyObject *
get_event_loop(asyncio_state *state)
{
PyObject *loop;
PyObject *policy;
if (get_running_loop(state, &loop)) {
return NULL;
}
if (loop != NULL) {
return loop;
}
policy = PyObject_CallNoArgs(state->asyncio_get_event_loop_policy);
if (policy == NULL) {
return NULL;
}
loop = PyObject_CallMethodNoArgs(policy, &_Py_ID(get_event_loop));
Py_DECREF(policy);
return loop;
}
static int
call_soon(asyncio_state *state, PyObject *loop, PyObject *func, PyObject *arg,
PyObject *ctx)
{
PyObject *handle;
if (ctx == NULL) {
PyObject *stack[] = {loop, func, arg};
size_t nargsf = 3 | PY_VECTORCALL_ARGUMENTS_OFFSET;
handle = PyObject_VectorcallMethod(&_Py_ID(call_soon), stack, nargsf, NULL);
}
else {
PyObject *stack[4];
size_t nargs = 2;
stack[0] = loop;
stack[1] = func;
if (arg != NULL) {
stack[2] = arg;
nargs++;
}
stack[nargs] = (PyObject *)ctx;
size_t nargsf = nargs | PY_VECTORCALL_ARGUMENTS_OFFSET;
handle = PyObject_VectorcallMethod(&_Py_ID(call_soon), stack, nargsf,
state->context_kwname);
}
if (handle == NULL) {
return -1;
}
Py_DECREF(handle);
return 0;
}
static inline int
future_is_alive(FutureObj *fut)
{
return fut->fut_loop != NULL;
}
static inline int
future_ensure_alive(FutureObj *fut)
{
if (!future_is_alive(fut)) {
PyErr_SetString(PyExc_RuntimeError,
"Future object is not initialized.");
return -1;
}
return 0;
}
#define ENSURE_FUTURE_ALIVE(state, fut) \
do { \
assert(Future_Check(state, fut) || Task_Check(state, fut)); \
(void)state; \
if (future_ensure_alive((FutureObj*)fut)) { \
return NULL; \
} \
} while(0);
static int
future_schedule_callbacks(asyncio_state *state, FutureObj *fut)
{
Py_ssize_t len;
Py_ssize_t i;
if (fut->fut_callback0 != NULL) {
int ret = call_soon(state,
fut->fut_loop, fut->fut_callback0,
(PyObject *)fut, fut->fut_context0);
Py_CLEAR(fut->fut_callback0);
Py_CLEAR(fut->fut_context0);
if (ret) {
Py_CLEAR(fut->fut_callbacks);
return ret;
}
}
if (fut->fut_callbacks == NULL) {
return 0;
}
len = PyList_GET_SIZE(fut->fut_callbacks);
if (len == 0) {
Py_CLEAR(fut->fut_callbacks);
return 0;
}
for (i = 0; i < len; i++) {
PyObject *cb_tup = PyList_GET_ITEM(fut->fut_callbacks, i);
PyObject *cb = PyTuple_GET_ITEM(cb_tup, 0);
PyObject *ctx = PyTuple_GET_ITEM(cb_tup, 1);
if (call_soon(state, fut->fut_loop, cb, (PyObject *)fut, ctx)) {
Py_CLEAR(fut->fut_callbacks);
return -1;
}
}
Py_CLEAR(fut->fut_callbacks);
return 0;
}
static int
future_init(FutureObj *fut, PyObject *loop)
{
PyObject *res;
int is_true;
Py_CLEAR(fut->fut_loop);
Py_CLEAR(fut->fut_callback0);
Py_CLEAR(fut->fut_context0);
Py_CLEAR(fut->fut_callbacks);
Py_CLEAR(fut->fut_result);
Py_CLEAR(fut->fut_exception);
Py_CLEAR(fut->fut_exception_tb);
Py_CLEAR(fut->fut_source_tb);
Py_CLEAR(fut->fut_cancel_msg);
Py_CLEAR(fut->fut_cancelled_exc);
fut->fut_state = STATE_PENDING;
fut->fut_log_tb = 0;
fut->fut_blocking = 0;
if (loop == Py_None) {
asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut);
loop = get_event_loop(state);
if (loop == NULL) {
return -1;
}
}
else {
Py_INCREF(loop);
}
fut->fut_loop = loop;
res = PyObject_CallMethodNoArgs(fut->fut_loop, &_Py_ID(get_debug));
if (res == NULL) {
return -1;
}
is_true = PyObject_IsTrue(res);
Py_DECREF(res);
if (is_true < 0) {
return -1;
}
if (is_true && !_Py_IsInterpreterFinalizing(PyInterpreterState_Get())) {
asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut);
fut->fut_source_tb = PyObject_CallNoArgs(state->traceback_extract_stack);
if (fut->fut_source_tb == NULL) {
return -1;
}
}
return 0;
}
static PyObject *
future_set_result(asyncio_state *state, FutureObj *fut, PyObject *res)
{
if (future_ensure_alive(fut)) {
return NULL;
}
if (fut->fut_state != STATE_PENDING) {
PyErr_SetString(state->asyncio_InvalidStateError, "invalid state");
return NULL;
}
assert(!fut->fut_result);
fut->fut_result = Py_NewRef(res);
fut->fut_state = STATE_FINISHED;
if (future_schedule_callbacks(state, fut) == -1) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *
future_set_exception(asyncio_state *state, FutureObj *fut, PyObject *exc)
{
PyObject *exc_val = NULL;
if (fut->fut_state != STATE_PENDING) {
PyErr_SetString(state->asyncio_InvalidStateError, "invalid state");
return NULL;
}
if (PyExceptionClass_Check(exc)) {
exc_val = PyObject_CallNoArgs(exc);
if (exc_val == NULL) {
return NULL;
}
if (fut->fut_state != STATE_PENDING) {
Py_DECREF(exc_val);
PyErr_SetString(state->asyncio_InvalidStateError, "invalid state");
return NULL;
}
}
else {
exc_val = Py_NewRef(exc);
}
if (!PyExceptionInstance_Check(exc_val)) {
Py_DECREF(exc_val);
PyErr_SetString(PyExc_TypeError, "invalid exception object");
return NULL;
}
if (Py_IS_TYPE(exc_val, (PyTypeObject *)PyExc_StopIteration)) {
Py_DECREF(exc_val);
PyErr_SetString(PyExc_TypeError,
"StopIteration interacts badly with generators "
"and cannot be raised into a Future");
return NULL;
}
assert(!fut->fut_exception);
assert(!fut->fut_exception_tb);
fut->fut_exception = exc_val;
fut->fut_exception_tb = PyException_GetTraceback(exc_val);
fut->fut_state = STATE_FINISHED;
if (future_schedule_callbacks(state, fut) == -1) {
return NULL;
}
fut->fut_log_tb = 1;
Py_RETURN_NONE;
}
static PyObject *
create_cancelled_error(asyncio_state *state, FutureObj *fut)
{
PyObject *exc;
if (fut->fut_cancelled_exc != NULL) {
exc = fut->fut_cancelled_exc;
fut->fut_cancelled_exc = NULL;
return exc;
}
PyObject *msg = fut->fut_cancel_msg;
if (msg == NULL || msg == Py_None) {
exc = PyObject_CallNoArgs(state->asyncio_CancelledError);
} else {
exc = PyObject_CallOneArg(state->asyncio_CancelledError, msg);
}
return exc;
}
static void
future_set_cancelled_error(asyncio_state *state, FutureObj *fut)
{
PyObject *exc = create_cancelled_error(state, fut);
if (exc == NULL) {
return;
}
PyErr_SetObject(state->asyncio_CancelledError, exc);
Py_DECREF(exc);
}
static int
future_get_result(asyncio_state *state, FutureObj *fut, PyObject **result)
{
if (fut->fut_state == STATE_CANCELLED) {
future_set_cancelled_error(state, fut);
return -1;
}
if (fut->fut_state != STATE_FINISHED) {
PyErr_SetString(state->asyncio_InvalidStateError,
"Result is not set.");
return -1;
}
fut->fut_log_tb = 0;
if (fut->fut_exception != NULL) {
PyObject *tb = fut->fut_exception_tb;
if (tb == NULL) {
tb = Py_None;
}
if (PyException_SetTraceback(fut->fut_exception, tb) < 0) {
return -1;
}
*result = Py_NewRef(fut->fut_exception);
Py_CLEAR(fut->fut_exception_tb);
return 1;
}
*result = Py_NewRef(fut->fut_result);
return 0;
}
static PyObject *
future_add_done_callback(asyncio_state *state, FutureObj *fut, PyObject *arg,
PyObject *ctx)
{
if (!future_is_alive(fut)) {
PyErr_SetString(PyExc_RuntimeError, "uninitialized Future object");
return NULL;
}
if (fut->fut_state != STATE_PENDING) {
if (call_soon(state, fut->fut_loop, arg, (PyObject*) fut, ctx)) {
return NULL;
}
}
else {
if (fut->fut_callbacks == NULL && fut->fut_callback0 == NULL) {
fut->fut_callback0 = Py_NewRef(arg);
fut->fut_context0 = Py_NewRef(ctx);
}
else {
PyObject *tup = PyTuple_New(2);
if (tup == NULL) {
return NULL;
}
Py_INCREF(arg);
PyTuple_SET_ITEM(tup, 0, arg);
Py_INCREF(ctx);
PyTuple_SET_ITEM(tup, 1, (PyObject *)ctx);
if (fut->fut_callbacks != NULL) {
int err = PyList_Append(fut->fut_callbacks, tup);
if (err) {
Py_DECREF(tup);
return NULL;
}
Py_DECREF(tup);
}
else {
fut->fut_callbacks = PyList_New(1);
if (fut->fut_callbacks == NULL) {
Py_DECREF(tup);
return NULL;
}
PyList_SET_ITEM(fut->fut_callbacks, 0, tup);
}
}
}
Py_RETURN_NONE;
}
static PyObject *
future_cancel(asyncio_state *state, FutureObj *fut, PyObject *msg)
{
fut->fut_log_tb = 0;
if (fut->fut_state != STATE_PENDING) {
Py_RETURN_FALSE;
}
fut->fut_state = STATE_CANCELLED;
Py_XINCREF(msg);
Py_XSETREF(fut->fut_cancel_msg, msg);
if (future_schedule_callbacks(state, fut) == -1) {
return NULL;
}
Py_RETURN_TRUE;
}
static int
_asyncio_Future___init___impl(FutureObj *self, PyObject *loop)
{
return future_init(self, loop);
}
static int
FutureObj_clear(FutureObj *fut)
{
Py_CLEAR(fut->fut_loop);
Py_CLEAR(fut->fut_callback0);
Py_CLEAR(fut->fut_context0);
Py_CLEAR(fut->fut_callbacks);
Py_CLEAR(fut->fut_result);
Py_CLEAR(fut->fut_exception);
Py_CLEAR(fut->fut_exception_tb);
Py_CLEAR(fut->fut_source_tb);
Py_CLEAR(fut->fut_cancel_msg);
Py_CLEAR(fut->fut_cancelled_exc);
_PyObject_ClearManagedDict((PyObject *)fut);
return 0;
}
static int
FutureObj_traverse(FutureObj *fut, visitproc visit, void *arg)
{
Py_VISIT(Py_TYPE(fut));
Py_VISIT(fut->fut_loop);
Py_VISIT(fut->fut_callback0);
Py_VISIT(fut->fut_context0);
Py_VISIT(fut->fut_callbacks);
Py_VISIT(fut->fut_result);
Py_VISIT(fut->fut_exception);
Py_VISIT(fut->fut_exception_tb);
Py_VISIT(fut->fut_source_tb);
Py_VISIT(fut->fut_cancel_msg);
Py_VISIT(fut->fut_cancelled_exc);
_PyObject_VisitManagedDict((PyObject *)fut, visit, arg);
return 0;
}
static PyObject *
_asyncio_Future_result_impl(FutureObj *self)
{
asyncio_state *state = get_asyncio_state_by_def((PyObject *)self);
PyObject *result;
if (!future_is_alive(self)) {
PyErr_SetString(state->asyncio_InvalidStateError,
"Future object is not initialized.");
return NULL;
}
int res = future_get_result(state, self, &result);
if (res == -1) {
return NULL;
}
if (res == 0) {
return result;
}
assert(res == 1);
PyErr_SetObject(PyExceptionInstance_Class(result), result);
Py_DECREF(result);
return NULL;
}
static PyObject *
_asyncio_Future_exception_impl(FutureObj *self, PyTypeObject *cls)
{
if (!future_is_alive(self)) {
asyncio_state *state = get_asyncio_state_by_cls(cls);
PyErr_SetString(state->asyncio_InvalidStateError,
"Future object is not initialized.");
return NULL;
}
if (self->fut_state == STATE_CANCELLED) {
asyncio_state *state = get_asyncio_state_by_cls(cls);
future_set_cancelled_error(state, self);
return NULL;
}
if (self->fut_state != STATE_FINISHED) {
asyncio_state *state = get_asyncio_state_by_cls(cls);
PyErr_SetString(state->asyncio_InvalidStateError,
"Exception is not set.");
return NULL;
}
if (self->fut_exception != NULL) {
self->fut_log_tb = 0;
return Py_NewRef(self->fut_exception);
}
Py_RETURN_NONE;
}
static PyObject *
_asyncio_Future_set_result_impl(FutureObj *self, PyTypeObject *cls,
PyObject *result)
{
asyncio_state *state = get_asyncio_state_by_cls(cls);
ENSURE_FUTURE_ALIVE(state, self)
return future_set_result(state, self, result);
}
static PyObject *
_asyncio_Future_set_exception_impl(FutureObj *self, PyTypeObject *cls,
PyObject *exception)
{
asyncio_state *state = get_asyncio_state_by_cls(cls);
ENSURE_FUTURE_ALIVE(state, self)
return future_set_exception(state, self, exception);
}
static PyObject *
_asyncio_Future_add_done_callback_impl(FutureObj *self, PyTypeObject *cls,
PyObject *fn, PyObject *context)
{
asyncio_state *state = get_asyncio_state_by_cls(cls);
if (context == NULL) {
context = PyContext_CopyCurrent();
if (context == NULL) {
return NULL;
}
PyObject *res = future_add_done_callback(state, self, fn, context);
Py_DECREF(context);
return res;
}
return future_add_done_callback(state, self, fn, context);
}
static PyObject *
_asyncio_Future_remove_done_callback_impl(FutureObj *self, PyTypeObject *cls,
PyObject *fn)
{
PyObject *newlist;
Py_ssize_t len, i, j=0;
Py_ssize_t cleared_callback0 = 0;
asyncio_state *state = get_asyncio_state_by_cls(cls);
ENSURE_FUTURE_ALIVE(state, self)
if (self->fut_callback0 != NULL) {
int cmp = PyObject_RichCompareBool(self->fut_callback0, fn, Py_EQ);
if (cmp == -1) {
return NULL;
}
if (cmp == 1) {
Py_CLEAR(self->fut_callback0);
Py_CLEAR(self->fut_context0);
cleared_callback0 = 1;
}
}
if (self->fut_callbacks == NULL) {
return PyLong_FromSsize_t(cleared_callback0);
}
len = PyList_GET_SIZE(self->fut_callbacks);
if (len == 0) {
Py_CLEAR(self->fut_callbacks);
return PyLong_FromSsize_t(cleared_callback0);
}
if (len == 1) {
PyObject *cb_tup = PyList_GET_ITEM(self->fut_callbacks, 0);
int cmp = PyObject_RichCompareBool(
PyTuple_GET_ITEM(cb_tup, 0), fn, Py_EQ);
if (cmp == -1) {
return NULL;
}
if (cmp == 1) {
Py_CLEAR(self->fut_callbacks);
return PyLong_FromSsize_t(1 + cleared_callback0);
}
return PyLong_FromSsize_t(cleared_callback0);
}
newlist = PyList_New(len);
if (newlist == NULL) {
return NULL;
}
for (i = 0;
self->fut_callbacks != NULL && i < PyList_GET_SIZE(self->fut_callbacks);
i++) {
int ret;
PyObject *item = PyList_GET_ITEM(self->fut_callbacks, i);
Py_INCREF(item);
ret = PyObject_RichCompareBool(PyTuple_GET_ITEM(item, 0), fn, Py_EQ);
if (ret == 0) {
if (j < len) {
PyList_SET_ITEM(newlist, j, item);
j++;
continue;
}
ret = PyList_Append(newlist, item);
}
Py_DECREF(item);
if (ret < 0) {
goto fail;
}
}
if (j == 0 || self->fut_callbacks == NULL) {
Py_CLEAR(self->fut_callbacks);
Py_DECREF(newlist);
return PyLong_FromSsize_t(len + cleared_callback0);
}
if (j < len) {
Py_SET_SIZE(newlist, j);
}
j = PyList_GET_SIZE(newlist);
len = PyList_GET_SIZE(self->fut_callbacks);
if (j != len) {
if (PyList_SetSlice(self->fut_callbacks, 0, len, newlist) < 0) {
goto fail;
}
}
Py_DECREF(newlist);
return PyLong_FromSsize_t(len - j + cleared_callback0);
fail:
Py_DECREF(newlist);
return NULL;
}
static PyObject *
_asyncio_Future_cancel_impl(FutureObj *self, PyTypeObject *cls,
PyObject *msg)
{
asyncio_state *state = get_asyncio_state_by_cls(cls);
ENSURE_FUTURE_ALIVE(state, self)
return future_cancel(state, self, msg);
}
static PyObject *
_asyncio_Future_cancelled_impl(FutureObj *self)
{
if (future_is_alive(self) && self->fut_state == STATE_CANCELLED) {
Py_RETURN_TRUE;
}
else {
Py_RETURN_FALSE;
}
}
static PyObject *
_asyncio_Future_done_impl(FutureObj *self)
{
if (!future_is_alive(self) || self->fut_state == STATE_PENDING) {
Py_RETURN_FALSE;
}
else {
Py_RETURN_TRUE;
}
}
static PyObject *
_asyncio_Future_get_loop_impl(FutureObj *self, PyTypeObject *cls)
{
asyncio_state *state = get_asyncio_state_by_cls(cls);
ENSURE_FUTURE_ALIVE(state, self)
return Py_NewRef(self->fut_loop);
}
static PyObject *
FutureObj_get_blocking(FutureObj *fut, void *Py_UNUSED(ignored))
{
if (future_is_alive(fut) && fut->fut_blocking) {
Py_RETURN_TRUE;
}
else {
Py_RETURN_FALSE;
}
}
static int
FutureObj_set_blocking(FutureObj *fut, PyObject *val, void *Py_UNUSED(ignored))
{
if (future_ensure_alive(fut)) {
return -1;
}
if (val == NULL) {
PyErr_SetString(PyExc_AttributeError, "cannot delete attribute");
return -1;
}
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, void *Py_UNUSED(ignored))
{
asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut);
ENSURE_FUTURE_ALIVE(state, fut)
if (fut->fut_log_tb) {
Py_RETURN_TRUE;
}
else {
Py_RETURN_FALSE;
}
}
static int
FutureObj_set_log_traceback(FutureObj *fut, PyObject *val, void *Py_UNUSED(ignored))
{
if (val == NULL) {
PyErr_SetString(PyExc_AttributeError, "cannot delete attribute");
return -1;
}
int is_true = PyObject_IsTrue(val);
if (is_true < 0) {
return -1;
}
if (is_true) {
PyErr_SetString(PyExc_ValueError,
"_log_traceback can only be set to False");
return -1;
}
fut->fut_log_tb = is_true;
return 0;
}
static PyObject *
FutureObj_get_loop(FutureObj *fut, void *Py_UNUSED(ignored))
{
if (!future_is_alive(fut)) {
Py_RETURN_NONE;
}
return Py_NewRef(fut->fut_loop);
}
static PyObject *
FutureObj_get_callbacks(FutureObj *fut, void *Py_UNUSED(ignored))
{
asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut);
Py_ssize_t i;
ENSURE_FUTURE_ALIVE(state, fut)
if (fut->fut_callback0 == NULL) {
if (fut->fut_callbacks == NULL) {
Py_RETURN_NONE;
}
return Py_NewRef(fut->fut_callbacks);
}
Py_ssize_t len = 1;
if (fut->fut_callbacks != NULL) {
len += PyList_GET_SIZE(fut->fut_callbacks);
}
PyObject *new_list = PyList_New(len);
if (new_list == NULL) {
return NULL;
}
PyObject *tup0 = PyTuple_New(2);
if (tup0 == NULL) {
Py_DECREF(new_list);
return NULL;
}
Py_INCREF(fut->fut_callback0);
PyTuple_SET_ITEM(tup0, 0, fut->fut_callback0);
assert(fut->fut_context0 != NULL);
Py_INCREF(fut->fut_context0);
PyTuple_SET_ITEM(tup0, 1, (PyObject *)fut->fut_context0);
PyList_SET_ITEM(new_list, 0, tup0);
if (fut->fut_callbacks != NULL) {
for (i = 0; i < PyList_GET_SIZE(fut->fut_callbacks); i++) {
PyObject *cb = PyList_GET_ITEM(fut->fut_callbacks, i);
Py_INCREF(cb);
PyList_SET_ITEM(new_list, i + 1, cb);
}
}
return new_list;
}
static PyObject *
FutureObj_get_result(FutureObj *fut, void *Py_UNUSED(ignored))
{
asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut);
ENSURE_FUTURE_ALIVE(state, fut)
if (fut->fut_result == NULL) {
Py_RETURN_NONE;
}
return Py_NewRef(fut->fut_result);
}
static PyObject *
FutureObj_get_exception(FutureObj *fut, void *Py_UNUSED(ignored))
{
asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut);
ENSURE_FUTURE_ALIVE(state, fut)
if (fut->fut_exception == NULL) {
Py_RETURN_NONE;
}
return Py_NewRef(fut->fut_exception);
}
static PyObject *
FutureObj_get_source_traceback(FutureObj *fut, void *Py_UNUSED(ignored))
{
if (!future_is_alive(fut) || fut->fut_source_tb == NULL) {
Py_RETURN_NONE;
}
return Py_NewRef(fut->fut_source_tb);
}
static PyObject *
FutureObj_get_cancel_message(FutureObj *fut, void *Py_UNUSED(ignored))
{
if (fut->fut_cancel_msg == NULL) {
Py_RETURN_NONE;
}
return Py_NewRef(fut->fut_cancel_msg);
}
static int
FutureObj_set_cancel_message(FutureObj *fut, PyObject *msg,
void *Py_UNUSED(ignored))
{
if (msg == NULL) {
PyErr_SetString(PyExc_AttributeError, "cannot delete attribute");
return -1;
}
Py_INCREF(msg);
Py_XSETREF(fut->fut_cancel_msg, msg);
return 0;
}
static PyObject *
FutureObj_get_state(FutureObj *fut, void *Py_UNUSED(ignored))
{
asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut);
PyObject *ret = NULL;
ENSURE_FUTURE_ALIVE(state, fut)
switch (fut->fut_state) {
case STATE_PENDING:
ret = &_Py_ID(PENDING);
break;
case STATE_CANCELLED:
ret = &_Py_ID(CANCELLED);
break;
case STATE_FINISHED:
ret = &_Py_ID(FINISHED);
break;
default:
assert (0);
}
return Py_XNewRef(ret);
}
static PyObject *
FutureObj_repr(FutureObj *fut)
{
asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut);
ENSURE_FUTURE_ALIVE(state, fut)
return PyObject_CallOneArg(state->asyncio_future_repr_func, (PyObject *)fut);
}
static PyObject *
_asyncio_Future__make_cancelled_error_impl(FutureObj *self)
{
asyncio_state *state = get_asyncio_state_by_def((PyObject *)self);
return create_cancelled_error(state, self);
}
static void
FutureObj_finalize(FutureObj *fut)
{
PyObject *context;
PyObject *message = NULL;
PyObject *func;
if (!fut->fut_log_tb) {
return;
}
assert(fut->fut_exception != NULL);
fut->fut_log_tb = 0;
PyObject *exc = PyErr_GetRaisedException();
context = PyDict_New();
if (context == NULL) {
goto finally;
}
message = PyUnicode_FromFormat(
"%s exception was never retrieved", _PyType_Name(Py_TYPE(fut)));
if (message == NULL) {
goto finally;
}
if (PyDict_SetItem(context, &_Py_ID(message), message) < 0 ||
PyDict_SetItem(context, &_Py_ID(exception), fut->fut_exception) < 0 ||
PyDict_SetItem(context, &_Py_ID(future), (PyObject*)fut) < 0) {
goto finally;
}
if (fut->fut_source_tb != NULL) {
if (PyDict_SetItem(context, &_Py_ID(source_traceback),
fut->fut_source_tb) < 0) {
goto finally;
}
}
func = PyObject_GetAttr(fut->fut_loop, &_Py_ID(call_exception_handler));
if (func != NULL) {
PyObject *res = PyObject_CallOneArg(func, context);
if (res == NULL) {
PyErr_WriteUnraisable(func);
}
else {
Py_DECREF(res);
}
Py_DECREF(func);
}
finally:
Py_XDECREF(context);
Py_XDECREF(message);
PyErr_SetRaisedException(exc);
}
static PyMethodDef FutureType_methods[] = {
_ASYNCIO_FUTURE_RESULT_METHODDEF
_ASYNCIO_FUTURE_EXCEPTION_METHODDEF
_ASYNCIO_FUTURE_SET_RESULT_METHODDEF
_ASYNCIO_FUTURE_SET_EXCEPTION_METHODDEF
_ASYNCIO_FUTURE_ADD_DONE_CALLBACK_METHODDEF
_ASYNCIO_FUTURE_REMOVE_DONE_CALLBACK_METHODDEF
_ASYNCIO_FUTURE_CANCEL_METHODDEF
_ASYNCIO_FUTURE_CANCELLED_METHODDEF
_ASYNCIO_FUTURE_DONE_METHODDEF
_ASYNCIO_FUTURE_GET_LOOP_METHODDEF
_ASYNCIO_FUTURE__MAKE_CANCELLED_ERROR_METHODDEF
{"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
{NULL, NULL}
};
static PyMemberDef FutureType_members[] = {
{"__weaklistoffset__", T_PYSSIZET, offsetof(FutureObj, fut_weakreflist), READONLY},
{NULL},
};
#define FUTURE_COMMON_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, \
(setter)FutureObj_set_log_traceback, NULL}, \
{"_source_traceback", (getter)FutureObj_get_source_traceback, \
NULL, NULL}, \
{"_cancel_message", (getter)FutureObj_get_cancel_message, \
(setter)FutureObj_set_cancel_message, NULL},
static PyGetSetDef FutureType_getsetlist[] = {
FUTURE_COMMON_GETSETLIST
{NULL}
};
static void FutureObj_dealloc(PyObject *self);
static PyType_Slot Future_slots[] = {
{Py_tp_dealloc, FutureObj_dealloc},
{Py_tp_repr, (reprfunc)FutureObj_repr},
{Py_tp_doc, (void *)_asyncio_Future___init____doc__},
{Py_tp_traverse, (traverseproc)FutureObj_traverse},
{Py_tp_clear, (inquiry)FutureObj_clear},
{Py_tp_iter, (getiterfunc)future_new_iter},
{Py_tp_methods, FutureType_methods},
{Py_tp_members, FutureType_members},
{Py_tp_getset, FutureType_getsetlist},
{Py_tp_init, (initproc)_asyncio_Future___init__},
{Py_tp_new, PyType_GenericNew},
{Py_tp_finalize, (destructor)FutureObj_finalize},
{Py_am_await, (unaryfunc)future_new_iter},
{0, NULL},
};
static PyType_Spec Future_spec = {
.name = "_asyncio.Future",
.basicsize = sizeof(FutureObj),
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE |
Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_MANAGED_DICT),
.slots = Future_slots,
};
static void
FutureObj_dealloc(PyObject *self)
{
FutureObj *fut = (FutureObj *)self;
if (PyObject_CallFinalizerFromDealloc(self) < 0) {
return;
}
PyTypeObject *tp = Py_TYPE(fut);
PyObject_GC_UnTrack(self);
if (fut->fut_weakreflist != NULL) {
PyObject_ClearWeakRefs(self);
}
(void)FutureObj_clear(fut);
tp->tp_free(fut);
Py_DECREF(tp);
}
typedef struct futureiterobject {
PyObject_HEAD
FutureObj *future;
} futureiterobject;
static void
FutureIter_dealloc(futureiterobject *it)
{
PyTypeObject *tp = Py_TYPE(it);
asyncio_state *state = get_asyncio_state_by_def((PyObject *)it);
PyObject_GC_UnTrack(it);
tp->tp_clear((PyObject *)it);
if (state->fi_freelist_len < FI_FREELIST_MAXLEN) {
state->fi_freelist_len++;
it->future = (FutureObj*) state->fi_freelist;
state->fi_freelist = it;
}
else {
PyObject_GC_Del(it);
Py_DECREF(tp);
}
}
static PySendResult
FutureIter_am_send(futureiterobject *it,
PyObject *Py_UNUSED(arg),
PyObject **result)
{
PyObject *res;
FutureObj *fut = it->future;
*result = NULL;
if (fut == NULL) {
return PYGEN_ERROR;
}
if (fut->fut_state == STATE_PENDING) {
if (!fut->fut_blocking) {
fut->fut_blocking = 1;
*result = Py_NewRef(fut);
return PYGEN_NEXT;
}
PyErr_SetString(PyExc_RuntimeError,
"await wasn't used with future");
return PYGEN_ERROR;
}
it->future = NULL;
res = _asyncio_Future_result_impl(fut);
if (res != NULL) {
Py_DECREF(fut);
*result = res;
return PYGEN_RETURN;
}
Py_DECREF(fut);
return PYGEN_ERROR;
}
static PyObject *
FutureIter_iternext(futureiterobject *it)
{
PyObject *result;
switch (FutureIter_am_send(it, Py_None, &result)) {
case PYGEN_RETURN:
(void)_PyGen_SetStopIterationValue(result);
Py_DECREF(result);
return NULL;
case PYGEN_NEXT:
return result;
case PYGEN_ERROR:
return NULL;
default:
Py_UNREACHABLE();
}
}
static PyObject *
FutureIter_send(futureiterobject *self, PyObject *unused)
{
return FutureIter_iternext(self);
}
static PyObject *
FutureIter_throw(futureiterobject *self, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *type, *val = NULL, *tb = NULL;
if (!_PyArg_CheckPositional("throw", nargs, 1, 3)) {
return NULL;
}
if (nargs > 1) {
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"the (type, exc, tb) signature of throw() is deprecated, "
"use the single-arg signature instead.",
1) < 0) {
return NULL;
}
}
type = args[0];
if (nargs == 3) {
val = args[1];
tb = args[2];
}
else if (nargs == 2) {
val = args[1];
}
if (val == Py_None) {
val = NULL;
}
if (tb == Py_None ) {
tb = NULL;
} else if (tb != NULL && !PyTraceBack_Check(tb)) {
PyErr_SetString(PyExc_TypeError, "throw() third argument must be a traceback");
return NULL;
}
Py_INCREF(type);
Py_XINCREF(val);
Py_XINCREF(tb);
if (PyExceptionClass_Check(type)) {
PyErr_NormalizeException(&type, &val, &tb);
} else if (PyExceptionInstance_Check(type)) {
if (val) {
PyErr_SetString(PyExc_TypeError,
"instance exception may not have a separate value");
goto fail;
}
val = type;
type = PyExceptionInstance_Class(type);
Py_INCREF(type);
if (tb == NULL)
tb = PyException_GetTraceback(val);
} else {
PyErr_SetString(PyExc_TypeError,
"exceptions must be classes deriving BaseException or "
"instances of such a class");
goto fail;
}
Py_CLEAR(self->future);
PyErr_Restore(type, val, tb);
return NULL;
fail:
Py_DECREF(type);
Py_XDECREF(val);
Py_XDECREF(tb);
return NULL;
}
static int
FutureIter_clear(futureiterobject *it)
{
Py_CLEAR(it->future);
return 0;
}
static PyObject *
FutureIter_close(futureiterobject *self, PyObject *arg)
{
(void)FutureIter_clear(self);
Py_RETURN_NONE;
}
static int
FutureIter_traverse(futureiterobject *it, visitproc visit, void *arg)
{
Py_VISIT(Py_TYPE(it));
Py_VISIT(it->future);
return 0;
}
static PyMethodDef FutureIter_methods[] = {
{"send", (PyCFunction)FutureIter_send, METH_O, NULL},
{"throw", _PyCFunction_CAST(FutureIter_throw), METH_FASTCALL, NULL},
{"close", (PyCFunction)FutureIter_close, METH_NOARGS, NULL},
{NULL, NULL}
};
static PyType_Slot FutureIter_slots[] = {
{Py_tp_dealloc, (destructor)FutureIter_dealloc},
{Py_tp_getattro, PyObject_GenericGetAttr},
{Py_tp_traverse, (traverseproc)FutureIter_traverse},
{Py_tp_clear, FutureIter_clear},
{Py_tp_iter, PyObject_SelfIter},
{Py_tp_iternext, (iternextfunc)FutureIter_iternext},
{Py_tp_methods, FutureIter_methods},
{Py_am_send, (sendfunc)FutureIter_am_send},
{0, NULL},
};
static PyType_Spec FutureIter_spec = {
.name = "_asyncio.FutureIter",
.basicsize = sizeof(futureiterobject),
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_IMMUTABLETYPE),
.slots = FutureIter_slots,
};
static PyObject *
future_new_iter(PyObject *fut)
{
futureiterobject *it;
asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut);
ENSURE_FUTURE_ALIVE(state, fut)
if (state->fi_freelist_len) {
state->fi_freelist_len--;
it = state->fi_freelist;
state->fi_freelist = (futureiterobject*) it->future;
it->future = NULL;
_Py_NewReference((PyObject*) it);
}
else {
it = PyObject_GC_New(futureiterobject, state->FutureIterType);
if (it == NULL) {
return NULL;
}
}
it->future = (FutureObj*)Py_NewRef(fut);
PyObject_GC_Track(it);
return (PyObject*)it;
}
static int task_call_step_soon(asyncio_state *state, TaskObj *, PyObject *);
static PyObject * task_wakeup(TaskObj *, PyObject *);
static PyObject * task_step(asyncio_state *, TaskObj *, PyObject *);
static int task_eager_start(asyncio_state *state, TaskObj *task);
static int
TaskStepMethWrapper_clear(TaskStepMethWrapper *o)
{
Py_CLEAR(o->sw_task);
Py_CLEAR(o->sw_arg);
return 0;
}
static void
TaskStepMethWrapper_dealloc(TaskStepMethWrapper *o)
{
PyTypeObject *tp = Py_TYPE(o);
PyObject_GC_UnTrack(o);
(void)TaskStepMethWrapper_clear(o);
Py_TYPE(o)->tp_free(o);
Py_DECREF(tp);
}
static PyObject *
TaskStepMethWrapper_call(TaskStepMethWrapper *o,
PyObject *args, PyObject *kwds)
{
if (kwds != NULL && PyDict_GET_SIZE(kwds) != 0) {
PyErr_SetString(PyExc_TypeError, "function takes no keyword arguments");
return NULL;
}
if (args != NULL && PyTuple_GET_SIZE(args) != 0) {
PyErr_SetString(PyExc_TypeError, "function takes no positional arguments");
return NULL;
}
asyncio_state *state = get_asyncio_state_by_def((PyObject *)o);
return task_step(state, o->sw_task, o->sw_arg);
}
static int
TaskStepMethWrapper_traverse(TaskStepMethWrapper *o,
visitproc visit, void *arg)
{
Py_VISIT(Py_TYPE(o));
Py_VISIT(o->sw_task);
Py_VISIT(o->sw_arg);
return 0;
}
static PyObject *
TaskStepMethWrapper_get___self__(TaskStepMethWrapper *o, void *Py_UNUSED(ignored))
{
if (o->sw_task) {
return Py_NewRef(o->sw_task);
}
Py_RETURN_NONE;
}
static PyGetSetDef TaskStepMethWrapper_getsetlist[] = {
{"__self__", (getter)TaskStepMethWrapper_get___self__, NULL, NULL},
{NULL}
};
static PyType_Slot TaskStepMethWrapper_slots[] = {
{Py_tp_getset, TaskStepMethWrapper_getsetlist},
{Py_tp_dealloc, (destructor)TaskStepMethWrapper_dealloc},
{Py_tp_call, (ternaryfunc)TaskStepMethWrapper_call},
{Py_tp_getattro, PyObject_GenericGetAttr},
{Py_tp_traverse, (traverseproc)TaskStepMethWrapper_traverse},
{Py_tp_clear, (inquiry)TaskStepMethWrapper_clear},
{0, NULL},
};
static PyType_Spec TaskStepMethWrapper_spec = {
.name = "_asyncio.TaskStepMethWrapper",
.basicsize = sizeof(TaskStepMethWrapper),
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_IMMUTABLETYPE),
.slots = TaskStepMethWrapper_slots,
};
static PyObject *
TaskStepMethWrapper_new(TaskObj *task, PyObject *arg)
{
asyncio_state *state = get_asyncio_state_by_def((PyObject *)task);
TaskStepMethWrapper *o;
o = PyObject_GC_New(TaskStepMethWrapper, state->TaskStepMethWrapper_Type);
if (o == NULL) {
return NULL;
}
o->sw_task = (TaskObj*)Py_NewRef(task);
o->sw_arg = Py_XNewRef(arg);
PyObject_GC_Track(o);
return (PyObject*) o;
}
static PyMethodDef TaskWakeupDef = {
"task_wakeup",
(PyCFunction)task_wakeup,
METH_O,
NULL
};
static int
register_task(asyncio_state *state, PyObject *task)
{
PyObject *res = PyObject_CallMethodOneArg(state->scheduled_tasks,
&_Py_ID(add), task);
if (res == NULL) {
return -1;
}
Py_DECREF(res);
return 0;
}
static int
register_eager_task(asyncio_state *state, PyObject *task)
{
return PySet_Add(state->eager_tasks, task);
}
static int
unregister_task(asyncio_state *state, PyObject *task)
{
PyObject *res = PyObject_CallMethodOneArg(state->scheduled_tasks,
&_Py_ID(discard), task);
if (res == NULL) {
return -1;
}
Py_DECREF(res);
return 0;
}
static int
unregister_eager_task(asyncio_state *state, PyObject *task)
{
return PySet_Discard(state->eager_tasks, task);
}
static int
enter_task(asyncio_state *state, PyObject *loop, PyObject *task)
{
PyObject *item;
Py_hash_t hash;
hash = PyObject_Hash(loop);
if (hash == -1) {
return -1;
}
item = _PyDict_GetItem_KnownHash(state->current_tasks, loop, hash);
if (item != NULL) {
Py_INCREF(item);
PyErr_Format(
PyExc_RuntimeError,
"Cannot enter into task %R while another " \
"task %R is being executed.",
task, item, NULL);
Py_DECREF(item);
return -1;
}
if (PyErr_Occurred()) {
return -1;
}
return _PyDict_SetItem_KnownHash(state->current_tasks, loop, task, hash);
}
static int
leave_task(asyncio_state *state, PyObject *loop, PyObject *task)
{
PyObject *item;
Py_hash_t hash;
hash = PyObject_Hash(loop);
if (hash == -1) {
return -1;
}
item = _PyDict_GetItem_KnownHash(state->current_tasks, loop, hash);
if (item != task) {
if (item == NULL) {
item = Py_None;
}
PyErr_Format(
PyExc_RuntimeError,
"Leaving task %R does not match the current task %R.",
task, item, NULL);
return -1;
}
return _PyDict_DelItem_KnownHash(state->current_tasks, loop, hash);
}
static PyObject *
swap_current_task(asyncio_state *state, PyObject *loop, PyObject *task)
{
PyObject *prev_task;
Py_hash_t hash;
hash = PyObject_Hash(loop);
if (hash == -1) {
return NULL;
}
prev_task = _PyDict_GetItem_KnownHash(state->current_tasks, loop, hash);
if (prev_task == NULL) {
if (PyErr_Occurred()) {
return NULL;
}
prev_task = Py_None;
}
Py_INCREF(prev_task);
if (task == Py_None) {
if (_PyDict_DelItem_KnownHash(state->current_tasks, loop, hash) == -1) {
goto error;
}
} else {
if (_PyDict_SetItem_KnownHash(state->current_tasks, loop, task, hash) == -1) {
goto error;
}
}
return prev_task;
error:
Py_DECREF(prev_task);
return NULL;
}
static int
_asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop,
PyObject *name, PyObject *context,
int eager_start)
{
if (future_init((FutureObj*)self, loop)) {
return -1;
}
asyncio_state *state = get_asyncio_state_by_def((PyObject *)self);
int is_coro = is_coroutine(state, coro);
if (is_coro == -1) {
return -1;
}
if (is_coro == 0) {
self->task_log_destroy_pending = 0;
PyErr_Format(PyExc_TypeError,
"a coroutine was expected, got %R",
coro, NULL);
return -1;
}
if (context == Py_None) {
Py_XSETREF(self->task_context, PyContext_CopyCurrent());
if (self->task_context == NULL) {
return -1;
}
} else {
self->task_context = Py_NewRef(context);
}
Py_CLEAR(self->task_fut_waiter);
self->task_must_cancel = 0;
self->task_log_destroy_pending = 1;
self->task_num_cancels_requested = 0;
Py_INCREF(coro);
Py_XSETREF(self->task_coro, coro);
if (name == Py_None) {
name = PyLong_FromUnsignedLongLong(++state->task_name_counter);
} else if (!PyUnicode_CheckExact(name)) {
name = PyObject_Str(name);
} else {
Py_INCREF(name);
}
Py_XSETREF(self->task_name, name);
if (self->task_name == NULL) {
return -1;
}
if (eager_start) {
PyObject *res = PyObject_CallMethodNoArgs(loop, &_Py_ID(is_running));
if (res == NULL) {
return -1;
}
int is_loop_running = Py_IsTrue(res);
Py_DECREF(res);
if (is_loop_running) {
if (task_eager_start(state, self)) {
return -1;
}
return 0;
}
}
if (task_call_step_soon(state, self, NULL)) {
return -1;
}
return register_task(state, (PyObject*)self);
}
static int
TaskObj_clear(TaskObj *task)
{
(void)FutureObj_clear((FutureObj*) task);
Py_CLEAR(task->task_context);
Py_CLEAR(task->task_coro);
Py_CLEAR(task->task_name);
Py_CLEAR(task->task_fut_waiter);
return 0;
}
static int
TaskObj_traverse(TaskObj *task, visitproc visit, void *arg)
{
Py_VISIT(Py_TYPE(task));
Py_VISIT(task->task_context);
Py_VISIT(task->task_coro);
Py_VISIT(task->task_name);
Py_VISIT(task->task_fut_waiter);
FutureObj *fut = (FutureObj *)task;
Py_VISIT(fut->fut_loop);
Py_VISIT(fut->fut_callback0);
Py_VISIT(fut->fut_context0);
Py_VISIT(fut->fut_callbacks);
Py_VISIT(fut->fut_result);
Py_VISIT(fut->fut_exception);
Py_VISIT(fut->fut_exception_tb);
Py_VISIT(fut->fut_source_tb);
Py_VISIT(fut->fut_cancel_msg);
Py_VISIT(fut->fut_cancelled_exc);
_PyObject_VisitManagedDict((PyObject *)fut, visit, arg);
return 0;
}
static PyObject *
TaskObj_get_log_destroy_pending(TaskObj *task, void *Py_UNUSED(ignored))
{
if (task->task_log_destroy_pending) {
Py_RETURN_TRUE;
}
else {
Py_RETURN_FALSE;
}
}
static int
TaskObj_set_log_destroy_pending(TaskObj *task, PyObject *val, void *Py_UNUSED(ignored))
{
if (val == NULL) {
PyErr_SetString(PyExc_AttributeError, "cannot delete attribute");
return -1;
}
int is_true = PyObject_IsTrue(val);
if (is_true < 0) {
return -1;
}
task->task_log_destroy_pending = is_true;
return 0;
}
static PyObject *
TaskObj_get_must_cancel(TaskObj *task, void *Py_UNUSED(ignored))
{
if (task->task_must_cancel) {
Py_RETURN_TRUE;
}
else {
Py_RETURN_FALSE;
}
}
static PyObject *
TaskObj_get_coro(TaskObj *task, void *Py_UNUSED(ignored))
{
if (task->task_coro) {
return Py_NewRef(task->task_coro);
}
Py_RETURN_NONE;
}
static PyObject *
TaskObj_get_fut_waiter(TaskObj *task, void *Py_UNUSED(ignored))
{
if (task->task_fut_waiter) {
return Py_NewRef(task->task_fut_waiter);
}
Py_RETURN_NONE;
}
static PyObject *
TaskObj_repr(TaskObj *task)
{
asyncio_state *state = get_asyncio_state_by_def((PyObject *)task);
return PyObject_CallOneArg(state->asyncio_task_repr_func,
(PyObject *)task);
}
static PyObject *
_asyncio_Task__make_cancelled_error_impl(TaskObj *self)
{
FutureObj *fut = (FutureObj*)self;
return _asyncio_Future__make_cancelled_error_impl(fut);
}
static PyObject *
_asyncio_Task_cancel_impl(TaskObj *self, PyObject *msg)
{
self->task_log_tb = 0;
if (self->task_state != STATE_PENDING) {
Py_RETURN_FALSE;
}
self->task_num_cancels_requested += 1;
if (self->task_fut_waiter) {
PyObject *res;
int is_true;
res = PyObject_CallMethodOneArg(self->task_fut_waiter,
&_Py_ID(cancel), msg);
if (res == NULL) {
return NULL;
}
is_true = PyObject_IsTrue(res);
Py_DECREF(res);
if (is_true < 0) {
return NULL;
}
if (is_true) {
Py_RETURN_TRUE;
}
}
self->task_must_cancel = 1;
Py_XINCREF(msg);
Py_XSETREF(self->task_cancel_msg, msg);
Py_RETURN_TRUE;
}
static PyObject *
_asyncio_Task_cancelling_impl(TaskObj *self)
{
return PyLong_FromLong(self->task_num_cancels_requested);
}
static PyObject *
_asyncio_Task_uncancel_impl(TaskObj *self)
{
if (self->task_num_cancels_requested > 0) {
self->task_num_cancels_requested -= 1;
}
return PyLong_FromLong(self->task_num_cancels_requested);
}
static PyObject *
_asyncio_Task_get_stack_impl(TaskObj *self, PyTypeObject *cls,
PyObject *limit)
{
asyncio_state *state = get_asyncio_state_by_cls(cls);
PyObject *stack[] = {(PyObject *)self, limit};
return PyObject_Vectorcall(state->asyncio_task_get_stack_func,
stack, 2, NULL);
}
static PyObject *
_asyncio_Task_print_stack_impl(TaskObj *self, PyTypeObject *cls,
PyObject *limit, PyObject *file)
{
asyncio_state *state = get_asyncio_state_by_cls(cls);
PyObject *stack[] = {(PyObject *)self, limit, file};
return PyObject_Vectorcall(state->asyncio_task_print_stack_func,
stack, 3, NULL);
}
static PyObject *
_asyncio_Task_set_result(TaskObj *self, PyObject *result)
{
PyErr_SetString(PyExc_RuntimeError,
"Task does not support set_result operation");
return NULL;
}
static PyObject *
_asyncio_Task_set_exception(TaskObj *self, PyObject *exception)
{
PyErr_SetString(PyExc_RuntimeError,
"Task does not support set_exception operation");
return NULL;
}
static PyObject *
_asyncio_Task_get_coro_impl(TaskObj *self)
{
return Py_NewRef(self->task_coro);
}
static PyObject *
_asyncio_Task_get_context_impl(TaskObj *self)
{
return Py_NewRef(self->task_context);
}
static PyObject *
_asyncio_Task_get_name_impl(TaskObj *self)
{
if (self->task_name) {
if (PyLong_CheckExact(self->task_name)) {
PyObject *name = PyUnicode_FromFormat("Task-%S", self->task_name);
if (name == NULL) {
return NULL;
}
Py_SETREF(self->task_name, name);
}
return Py_NewRef(self->task_name);
}
Py_RETURN_NONE;
}
static PyObject *
_asyncio_Task_set_name(TaskObj *self, PyObject *value)
{
if (!PyUnicode_CheckExact(value)) {
value = PyObject_Str(value);
if (value == NULL) {
return NULL;
}
} else {
Py_INCREF(value);
}
Py_XSETREF(self->task_name, value);
Py_RETURN_NONE;
}
static void
TaskObj_finalize(TaskObj *task)
{
PyObject *context;
PyObject *message = NULL;
PyObject *func;
if (task->task_state != STATE_PENDING || !task->task_log_destroy_pending) {
goto done;
}
PyObject *exc = PyErr_GetRaisedException();
context = PyDict_New();
if (context == NULL) {
goto finally;
}
message = PyUnicode_FromString("Task was destroyed but it is pending!");
if (message == NULL) {
goto finally;
}
if (PyDict_SetItem(context, &_Py_ID(message), message) < 0 ||
PyDict_SetItem(context, &_Py_ID(task), (PyObject*)task) < 0)
{
goto finally;
}
if (task->task_source_tb != NULL) {
if (PyDict_SetItem(context, &_Py_ID(source_traceback),
task->task_source_tb) < 0)
{
goto finally;
}
}
func = PyObject_GetAttr(task->task_loop, &_Py_ID(call_exception_handler));
if (func != NULL) {
PyObject *res = PyObject_CallOneArg(func, context);
if (res == NULL) {
PyErr_WriteUnraisable(func);
}
else {
Py_DECREF(res);
}
Py_DECREF(func);
}
finally:
Py_XDECREF(context);
Py_XDECREF(message);
PyErr_SetRaisedException(exc);
done:
FutureObj_finalize((FutureObj*)task);
}
static void TaskObj_dealloc(PyObject *);
static PyMethodDef TaskType_methods[] = {
_ASYNCIO_FUTURE_RESULT_METHODDEF
_ASYNCIO_FUTURE_EXCEPTION_METHODDEF
_ASYNCIO_FUTURE_ADD_DONE_CALLBACK_METHODDEF
_ASYNCIO_FUTURE_REMOVE_DONE_CALLBACK_METHODDEF
_ASYNCIO_FUTURE_CANCELLED_METHODDEF
_ASYNCIO_FUTURE_DONE_METHODDEF
_ASYNCIO_TASK_SET_RESULT_METHODDEF
_ASYNCIO_TASK_SET_EXCEPTION_METHODDEF
_ASYNCIO_TASK_CANCEL_METHODDEF
_ASYNCIO_TASK_CANCELLING_METHODDEF
_ASYNCIO_TASK_UNCANCEL_METHODDEF
_ASYNCIO_TASK_GET_STACK_METHODDEF
_ASYNCIO_TASK_PRINT_STACK_METHODDEF
_ASYNCIO_TASK__MAKE_CANCELLED_ERROR_METHODDEF
_ASYNCIO_TASK_GET_NAME_METHODDEF
_ASYNCIO_TASK_SET_NAME_METHODDEF
_ASYNCIO_TASK_GET_CORO_METHODDEF
_ASYNCIO_TASK_GET_CONTEXT_METHODDEF
{"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
{NULL, NULL}
};
static PyMemberDef TaskType_members[] = {
{"__weaklistoffset__", T_PYSSIZET, offsetof(TaskObj, task_weakreflist), READONLY},
{NULL},
};
static PyGetSetDef TaskType_getsetlist[] = {
FUTURE_COMMON_GETSETLIST
{"_log_destroy_pending", (getter)TaskObj_get_log_destroy_pending,
(setter)TaskObj_set_log_destroy_pending, NULL},
{"_must_cancel", (getter)TaskObj_get_must_cancel, NULL, NULL},
{"_coro", (getter)TaskObj_get_coro, NULL, NULL},
{"_fut_waiter", (getter)TaskObj_get_fut_waiter, NULL, NULL},
{NULL}
};
static PyType_Slot Task_slots[] = {
{Py_tp_dealloc, TaskObj_dealloc},
{Py_tp_repr, (reprfunc)TaskObj_repr},
{Py_tp_doc, (void *)_asyncio_Task___init____doc__},
{Py_tp_traverse, (traverseproc)TaskObj_traverse},
{Py_tp_clear, (inquiry)TaskObj_clear},
{Py_tp_iter, (getiterfunc)future_new_iter},
{Py_tp_methods, TaskType_methods},
{Py_tp_members, TaskType_members},
{Py_tp_getset, TaskType_getsetlist},
{Py_tp_init, (initproc)_asyncio_Task___init__},
{Py_tp_new, PyType_GenericNew},
{Py_tp_finalize, (destructor)TaskObj_finalize},
{Py_am_await, (unaryfunc)future_new_iter},
{0, NULL},
};
static PyType_Spec Task_spec = {
.name = "_asyncio.Task",
.basicsize = sizeof(TaskObj),
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE |
Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_MANAGED_DICT),
.slots = Task_slots,
};
static void
TaskObj_dealloc(PyObject *self)
{
TaskObj *task = (TaskObj *)self;
if (PyObject_CallFinalizerFromDealloc(self) < 0) {
return;
}
PyTypeObject *tp = Py_TYPE(task);
PyObject_GC_UnTrack(self);
if (task->task_weakreflist != NULL) {
PyObject_ClearWeakRefs(self);
}
(void)TaskObj_clear(task);
tp->tp_free(task);
Py_DECREF(tp);
}
static int
task_call_step_soon(asyncio_state *state, TaskObj *task, PyObject *arg)
{
PyObject *cb = TaskStepMethWrapper_new(task, arg);
if (cb == NULL) {
return -1;
}
int ret = call_soon(state, task->task_loop, cb, NULL, task->task_context);
Py_DECREF(cb);
return ret;
}
static PyObject *
task_set_error_soon(asyncio_state *state, TaskObj *task, PyObject *et,
const char *format, ...)
{
PyObject* msg;
va_list vargs;
va_start(vargs, format);
msg = PyUnicode_FromFormatV(format, vargs);
va_end(vargs);
if (msg == NULL) {
return NULL;
}
PyObject *e = PyObject_CallOneArg(et, msg);
Py_DECREF(msg);
if (e == NULL) {
return NULL;
}
if (task_call_step_soon(state, task, e) == -1) {
Py_DECREF(e);
return NULL;
}
Py_DECREF(e);
Py_RETURN_NONE;
}
static inline int
gen_status_from_result(PyObject **result)
{
if (*result != NULL) {
return PYGEN_NEXT;
}
if (_PyGen_FetchStopIterationValue(result) == 0) {
return PYGEN_RETURN;
}
assert(PyErr_Occurred());
return PYGEN_ERROR;
}
static PyObject *
task_step_impl(asyncio_state *state, TaskObj *task, PyObject *exc)
{
int res;
int clear_exc = 0;
PyObject *result = NULL;
PyObject *coro;
PyObject *o;
if (task->task_state != STATE_PENDING) {
PyErr_Format(state->asyncio_InvalidStateError,
"_step(): already done: %R %R",
task,
exc ? exc : Py_None);
goto fail;
}
if (task->task_must_cancel) {
assert(exc != Py_None);
if (exc) {
res = PyObject_IsInstance(exc, state->asyncio_CancelledError);
if (res == -1) {
goto fail;
}
if (res == 0) {
exc = NULL;
}
}
if (!exc) {
exc = create_cancelled_error(state, (FutureObj*)task);
if (!exc) {
goto fail;
}
clear_exc = 1;
}
task->task_must_cancel = 0;
}
Py_CLEAR(task->task_fut_waiter);
coro = task->task_coro;
if (coro == NULL) {
PyErr_SetString(PyExc_RuntimeError, "uninitialized Task object");
if (clear_exc) {
Py_DECREF(exc);
}
return NULL;
}
int gen_status = PYGEN_ERROR;
if (exc == NULL) {
gen_status = PyIter_Send(coro, Py_None, &result);
}
else {
result = PyObject_CallMethodOneArg(coro, &_Py_ID(throw), exc);
gen_status = gen_status_from_result(&result);
if (clear_exc) {
Py_DECREF(exc);
}
}
if (gen_status == PYGEN_RETURN || gen_status == PYGEN_ERROR) {
if (result != NULL) {
PyObject *tmp;
if (task->task_must_cancel) {
task->task_must_cancel = 0;
tmp = future_cancel(state, (FutureObj*)task,
task->task_cancel_msg);
}
else {
tmp = future_set_result(state, (FutureObj*)task, result);
}
Py_DECREF(result);
if (tmp == NULL) {
return NULL;
}
Py_DECREF(tmp);
Py_RETURN_NONE;
}
if (PyErr_ExceptionMatches(state->asyncio_CancelledError)) {
PyObject *exc = PyErr_GetRaisedException();
assert(exc);
FutureObj *fut = (FutureObj*)task;
fut->fut_cancelled_exc = exc;
return future_cancel(state, fut, NULL);
}
PyObject *exc = PyErr_GetRaisedException();
assert(exc);
o = future_set_exception(state, (FutureObj*)task, exc);
if (!o) {
Py_DECREF(exc);
goto fail;
}
assert(o == Py_None);
Py_DECREF(o);
if (PyErr_GivenExceptionMatches(exc, PyExc_KeyboardInterrupt) ||
PyErr_GivenExceptionMatches(exc, PyExc_SystemExit))
{
PyErr_SetRaisedException(exc);
goto fail;
}
Py_DECREF(exc);
Py_RETURN_NONE;
}
PyObject *ret = task_step_handle_result_impl(state, task, result);
return ret;
fail:
return NULL;
}
static PyObject *
task_step_handle_result_impl(asyncio_state *state, TaskObj *task, PyObject *result)
{
int res;
PyObject *o;
if (result == (PyObject*)task) {
goto self_await;
}
if (Future_CheckExact(state, result) || Task_CheckExact(state, result)) {
PyObject *wrapper;
PyObject *tmp;
FutureObj *fut = (FutureObj*)result;
if (fut->fut_loop != task->task_loop) {
goto different_loop;
}
if (!fut->fut_blocking) {
goto yield_insteadof_yf;
}
fut->fut_blocking = 0;
wrapper = PyCFunction_New(&TaskWakeupDef, (PyObject *)task);
if (wrapper == NULL) {
goto fail;
}
tmp = future_add_done_callback(state,
(FutureObj*)result, wrapper, task->task_context);
Py_DECREF(wrapper);
if (tmp == NULL) {
goto fail;
}
Py_DECREF(tmp);
task->task_fut_waiter = result;
if (task->task_must_cancel) {
PyObject *r;
int is_true;
r = PyObject_CallMethodOneArg(result, &_Py_ID(cancel),
task->task_cancel_msg);
if (r == NULL) {
return NULL;
}
is_true = PyObject_IsTrue(r);
Py_DECREF(r);
if (is_true < 0) {
return NULL;
}
else if (is_true) {
task->task_must_cancel = 0;
}
}
Py_RETURN_NONE;
}
if (result == Py_None) {
if (task_call_step_soon(state, task, NULL)) {
goto fail;
}
return result;
}
if (_PyObject_LookupAttr(result, &_Py_ID(_asyncio_future_blocking), &o) < 0) {
goto fail;
}
if (o != NULL && o != Py_None) {
PyObject *wrapper;
PyObject *tmp;
int blocking = PyObject_IsTrue(o);
Py_DECREF(o);
if (blocking < 0) {
goto fail;
}
PyObject *oloop = get_future_loop(state, result);
if (oloop == NULL) {
goto fail;
}
if (oloop != task->task_loop) {
Py_DECREF(oloop);
goto different_loop;
}
Py_DECREF(oloop);
if (!blocking) {
goto yield_insteadof_yf;
}
if (PyObject_SetAttr(
result, &_Py_ID(_asyncio_future_blocking), Py_False) == -1) {
goto fail;
}
wrapper = PyCFunction_New(&TaskWakeupDef, (PyObject *)task);
if (wrapper == NULL) {
goto fail;
}
PyObject *add_cb = PyObject_GetAttr(
result, &_Py_ID(add_done_callback));
if (add_cb == NULL) {
Py_DECREF(wrapper);
goto fail;
}
PyObject *stack[2];
stack[0] = wrapper;
stack[1] = (PyObject *)task->task_context;
EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_API, add_cb);
tmp = PyObject_Vectorcall(add_cb, stack, 1, state->context_kwname);
Py_DECREF(add_cb);
Py_DECREF(wrapper);
if (tmp == NULL) {
goto fail;
}
Py_DECREF(tmp);
task->task_fut_waiter = result;
if (task->task_must_cancel) {
PyObject *r;
int is_true;
r = PyObject_CallMethodOneArg(result, &_Py_ID(cancel),
task->task_cancel_msg);
if (r == NULL) {
return NULL;
}
is_true = PyObject_IsTrue(r);
Py_DECREF(r);
if (is_true < 0) {
return NULL;
}
else if (is_true) {
task->task_must_cancel = 0;
}
}
Py_RETURN_NONE;
}
Py_XDECREF(o);
res = PyObject_IsInstance(result, (PyObject*)&PyGen_Type);
if (res < 0) {
goto fail;
}
if (res) {
o = task_set_error_soon(
state, task, PyExc_RuntimeError,
"yield was used instead of yield from for "
"generator in task %R with %R", task, result);
Py_DECREF(result);
return o;
}
o = task_set_error_soon(
state, task, PyExc_RuntimeError, "Task got bad yield: %R", result);
Py_DECREF(result);
return o;
self_await:
o = task_set_error_soon(
state, task, PyExc_RuntimeError,
"Task cannot await on itself: %R", task);
Py_DECREF(result);
return o;
yield_insteadof_yf:
o = task_set_error_soon(
state, task, PyExc_RuntimeError,
"yield was used instead of yield from "
"in task %R with %R",
task, result);
Py_DECREF(result);
return o;
different_loop:
o = task_set_error_soon(
state, task, PyExc_RuntimeError,
"Task %R got Future %R attached to a different loop",
task, result);
Py_DECREF(result);
return o;
fail:
Py_XDECREF(result);
return NULL;
}
static PyObject *
task_step(asyncio_state *state, TaskObj *task, PyObject *exc)
{
PyObject *res;
if (enter_task(state, task->task_loop, (PyObject*)task) < 0) {
return NULL;
}
res = task_step_impl(state, task, exc);
if (res == NULL) {
PyObject *exc = PyErr_GetRaisedException();
leave_task(state, task->task_loop, (PyObject*)task);
_PyErr_ChainExceptions1(exc);
return NULL;
}
else {
if (leave_task(state, task->task_loop, (PyObject*)task) < 0) {
Py_DECREF(res);
return NULL;
}
else {
return res;
}
}
}
static int
task_eager_start(asyncio_state *state, TaskObj *task)
{
assert(task != NULL);
PyObject *prevtask = swap_current_task(state, task->task_loop, (PyObject *)task);
if (prevtask == NULL) {
return -1;
}
if (register_eager_task(state, (PyObject *)task) == -1) {
Py_DECREF(prevtask);
return -1;
}
if (PyContext_Enter(task->task_context) == -1) {
Py_DECREF(prevtask);
return -1;
}
int retval = 0;
PyObject *stepres = task_step_impl(state, task, NULL);
if (stepres == NULL) {
PyObject *exc = PyErr_GetRaisedException();
_PyErr_ChainExceptions1(exc);
retval = -1;
} else {
Py_DECREF(stepres);
}
PyObject *curtask = swap_current_task(state, task->task_loop, prevtask);
Py_DECREF(prevtask);
if (curtask == NULL) {
retval = -1;
} else {
assert(curtask == (PyObject *)task);
Py_DECREF(curtask);
}
if (unregister_eager_task(state, (PyObject *)task) == -1) {
retval = -1;
}
if (PyContext_Exit(task->task_context) == -1) {
retval = -1;
}
if (task->task_state == STATE_PENDING) {
if (register_task(state, (PyObject *)task) == -1) {
retval = -1;
}
} else {
Py_CLEAR(task->task_coro);
}
return retval;
}
static PyObject *
task_wakeup(TaskObj *task, PyObject *o)
{
PyObject *result;
assert(o);
asyncio_state *state = get_asyncio_state_by_def((PyObject *)task);
if (Future_CheckExact(state, o) || Task_CheckExact(state, o)) {
PyObject *fut_result = NULL;
int res = future_get_result(state, (FutureObj*)o, &fut_result);
switch(res) {
case -1:
assert(fut_result == NULL);
break;
case 0:
Py_DECREF(fut_result);
return task_step(state, task, NULL);
default:
assert(res == 1);
result = task_step(state, task, fut_result);
Py_DECREF(fut_result);
return result;
}
}
else {
PyObject *fut_result = PyObject_CallMethod(o, "result", NULL);
if (fut_result != NULL) {
Py_DECREF(fut_result);
return task_step(state, task, NULL);
}
}
PyObject *exc = PyErr_GetRaisedException();
assert(exc);
result = task_step(state, task, exc);
Py_DECREF(exc);
return result;
}
static PyObject *
_asyncio__get_running_loop_impl(PyObject *module)
{
PyObject *loop;
asyncio_state *state = get_asyncio_state(module);
if (get_running_loop(state, &loop)) {
return NULL;
}
if (loop == NULL) {
Py_RETURN_NONE;
}
return loop;
}
static PyObject *
_asyncio__set_running_loop(PyObject *module, PyObject *loop)
{
asyncio_state *state = get_asyncio_state(module);
if (set_running_loop(state, loop)) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *
_asyncio_get_event_loop_impl(PyObject *module)
{
asyncio_state *state = get_asyncio_state(module);
return get_event_loop(state);
}
static PyObject *
_asyncio_get_running_loop_impl(PyObject *module)
{
PyObject *loop;
asyncio_state *state = get_asyncio_state(module);
if (get_running_loop(state, &loop)) {
return NULL;
}
if (loop == NULL) {
PyErr_SetString(
PyExc_RuntimeError, "no running event loop");
}
return loop;
}
static PyObject *
_asyncio__register_task_impl(PyObject *module, PyObject *task)
{
asyncio_state *state = get_asyncio_state(module);
if (register_task(state, task) < 0) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *
_asyncio__register_eager_task_impl(PyObject *module, PyObject *task)
{
asyncio_state *state = get_asyncio_state(module);
if (register_eager_task(state, task) < 0) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *
_asyncio__unregister_task_impl(PyObject *module, PyObject *task)
{
asyncio_state *state = get_asyncio_state(module);
if (unregister_task(state, task) < 0) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *
_asyncio__unregister_eager_task_impl(PyObject *module, PyObject *task)
{
asyncio_state *state = get_asyncio_state(module);
if (unregister_eager_task(state, task) < 0) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *
_asyncio__enter_task_impl(PyObject *module, PyObject *loop, PyObject *task)
{
asyncio_state *state = get_asyncio_state(module);
if (enter_task(state, loop, task) < 0) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *
_asyncio__leave_task_impl(PyObject *module, PyObject *loop, PyObject *task)
{
asyncio_state *state = get_asyncio_state(module);
if (leave_task(state, loop, task) < 0) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *
_asyncio__swap_current_task_impl(PyObject *module, PyObject *loop,
PyObject *task)
{
return swap_current_task(get_asyncio_state(module), loop, task);
}
static PyObject *
_asyncio_current_task_impl(PyObject *module, PyObject *loop)
{
PyObject *ret;
asyncio_state *state = get_asyncio_state(module);
if (loop == Py_None) {
loop = _asyncio_get_running_loop_impl(module);
if (loop == NULL) {
return NULL;
}
} else {
Py_INCREF(loop);
}
ret = PyDict_GetItemWithError(state->current_tasks, loop);
Py_DECREF(loop);
if (ret == NULL && PyErr_Occurred()) {
return NULL;
}
else if (ret == NULL) {
Py_RETURN_NONE;
}
Py_INCREF(ret);
return ret;
}
static void
module_free_freelists(asyncio_state *state)
{
PyObject *next;
PyObject *current;
next = (PyObject*) state->fi_freelist;
while (next != NULL) {
assert(state->fi_freelist_len > 0);
state->fi_freelist_len--;
current = next;
next = (PyObject*) ((futureiterobject*) current)->future;
PyObject_GC_Del(current);
}
assert(state->fi_freelist_len == 0);
state->fi_freelist = NULL;
}
static int
module_traverse(PyObject *mod, visitproc visit, void *arg)
{
asyncio_state *state = get_asyncio_state(mod);
Py_VISIT(state->FutureIterType);
Py_VISIT(state->TaskStepMethWrapper_Type);
Py_VISIT(state->FutureType);
Py_VISIT(state->TaskType);
Py_VISIT(state->asyncio_mod);
Py_VISIT(state->traceback_extract_stack);
Py_VISIT(state->asyncio_future_repr_func);
Py_VISIT(state->asyncio_get_event_loop_policy);
Py_VISIT(state->asyncio_iscoroutine_func);
Py_VISIT(state->asyncio_task_get_stack_func);
Py_VISIT(state->asyncio_task_print_stack_func);
Py_VISIT(state->asyncio_task_repr_func);
Py_VISIT(state->asyncio_InvalidStateError);
Py_VISIT(state->asyncio_CancelledError);
Py_VISIT(state->scheduled_tasks);
Py_VISIT(state->eager_tasks);
Py_VISIT(state->current_tasks);
Py_VISIT(state->iscoroutine_typecache);
Py_VISIT(state->context_kwname);
PyObject *next = (PyObject*) state->fi_freelist;
while (next != NULL) {
PyObject *current = next;
Py_VISIT(current);
next = (PyObject*) ((futureiterobject*) current)->future;
}
return 0;
}
static int
module_clear(PyObject *mod)
{
asyncio_state *state = get_asyncio_state(mod);
Py_CLEAR(state->FutureIterType);
Py_CLEAR(state->TaskStepMethWrapper_Type);
Py_CLEAR(state->FutureType);
Py_CLEAR(state->TaskType);
Py_CLEAR(state->asyncio_mod);
Py_CLEAR(state->traceback_extract_stack);
Py_CLEAR(state->asyncio_future_repr_func);
Py_CLEAR(state->asyncio_get_event_loop_policy);
Py_CLEAR(state->asyncio_iscoroutine_func);
Py_CLEAR(state->asyncio_task_get_stack_func);
Py_CLEAR(state->asyncio_task_print_stack_func);
Py_CLEAR(state->asyncio_task_repr_func);
Py_CLEAR(state->asyncio_InvalidStateError);
Py_CLEAR(state->asyncio_CancelledError);
Py_CLEAR(state->scheduled_tasks);
Py_CLEAR(state->eager_tasks);
Py_CLEAR(state->current_tasks);
Py_CLEAR(state->iscoroutine_typecache);
Py_CLEAR(state->context_kwname);
module_free_freelists(state);
return 0;
}
static void
module_free(void *mod)
{
(void)module_clear((PyObject *)mod);
}
static int
module_init(asyncio_state *state)
{
PyObject *module = NULL;
state->asyncio_mod = PyImport_ImportModule("asyncio");
if (state->asyncio_mod == NULL) {
goto fail;
}
state->current_tasks = PyDict_New();
if (state->current_tasks == NULL) {
goto fail;
}
state->iscoroutine_typecache = PySet_New(NULL);
if (state->iscoroutine_typecache == NULL) {
goto fail;
}
state->context_kwname = Py_BuildValue("(s)", "context");
if (state->context_kwname == NULL) {
goto fail;
}
#define WITH_MOD(NAME) \
Py_CLEAR(module); \
module = PyImport_ImportModule(NAME); \
if (module == NULL) { \
goto fail; \
}
#define GET_MOD_ATTR(VAR, NAME) \
VAR = PyObject_GetAttrString(module, NAME); \
if (VAR == NULL) { \
goto fail; \
}
WITH_MOD("asyncio.events")
GET_MOD_ATTR(state->asyncio_get_event_loop_policy, "get_event_loop_policy")
WITH_MOD("asyncio.base_futures")
GET_MOD_ATTR(state->asyncio_future_repr_func, "_future_repr")
WITH_MOD("asyncio.exceptions")
GET_MOD_ATTR(state->asyncio_InvalidStateError, "InvalidStateError")
GET_MOD_ATTR(state->asyncio_CancelledError, "CancelledError")
WITH_MOD("asyncio.base_tasks")
GET_MOD_ATTR(state->asyncio_task_repr_func, "_task_repr")
GET_MOD_ATTR(state->asyncio_task_get_stack_func, "_task_get_stack")
GET_MOD_ATTR(state->asyncio_task_print_stack_func, "_task_print_stack")
WITH_MOD("asyncio.coroutines")
GET_MOD_ATTR(state->asyncio_iscoroutine_func, "iscoroutine")
WITH_MOD("traceback")
GET_MOD_ATTR(state->traceback_extract_stack, "extract_stack")
PyObject *weak_set;
WITH_MOD("weakref")
GET_MOD_ATTR(weak_set, "WeakSet");
state->scheduled_tasks = PyObject_CallNoArgs(weak_set);
Py_CLEAR(weak_set);
if (state->scheduled_tasks == NULL) {
goto fail;
}
state->eager_tasks = PySet_New(NULL);
if (state->eager_tasks == NULL) {
goto fail;
}
Py_DECREF(module);
return 0;
fail:
Py_CLEAR(module);
return -1;
#undef WITH_MOD
#undef GET_MOD_ATTR
}
PyDoc_STRVAR(module_doc, "Accelerator module for asyncio");
static PyMethodDef asyncio_methods[] = {
_ASYNCIO_CURRENT_TASK_METHODDEF
_ASYNCIO_GET_EVENT_LOOP_METHODDEF
_ASYNCIO_GET_RUNNING_LOOP_METHODDEF
_ASYNCIO__GET_RUNNING_LOOP_METHODDEF
_ASYNCIO__SET_RUNNING_LOOP_METHODDEF
_ASYNCIO__REGISTER_TASK_METHODDEF
_ASYNCIO__REGISTER_EAGER_TASK_METHODDEF
_ASYNCIO__UNREGISTER_TASK_METHODDEF
_ASYNCIO__UNREGISTER_EAGER_TASK_METHODDEF
_ASYNCIO__ENTER_TASK_METHODDEF
_ASYNCIO__LEAVE_TASK_METHODDEF
_ASYNCIO__SWAP_CURRENT_TASK_METHODDEF
{NULL, NULL}
};
static int
module_exec(PyObject *mod)
{
asyncio_state *state = get_asyncio_state(mod);
#define CREATE_TYPE(m, tp, spec, base) \
do { \
tp = (PyTypeObject *)PyType_FromMetaclass(NULL, m, spec, \
(PyObject *)base); \
if (tp == NULL) { \
return -1; \
} \
} while (0)
CREATE_TYPE(mod, state->TaskStepMethWrapper_Type, &TaskStepMethWrapper_spec, NULL);
CREATE_TYPE(mod, state->FutureIterType, &FutureIter_spec, NULL);
CREATE_TYPE(mod, state->FutureType, &Future_spec, NULL);
CREATE_TYPE(mod, state->TaskType, &Task_spec, state->FutureType);
#undef CREATE_TYPE
if (PyModule_AddType(mod, state->FutureType) < 0) {
return -1;
}
if (PyModule_AddType(mod, state->TaskType) < 0) {
return -1;
}
if (module_init(state) < 0) {
return -1;
}
if (PyModule_AddObjectRef(mod, "_scheduled_tasks", state->scheduled_tasks) < 0) {
return -1;
}
if (PyModule_AddObjectRef(mod, "_eager_tasks", state->eager_tasks) < 0) {
return -1;
}
if (PyModule_AddObjectRef(mod, "_current_tasks", state->current_tasks) < 0) {
return -1;
}
return 0;
}
static struct PyModuleDef_Slot module_slots[] = {
{Py_mod_exec, module_exec},
{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
{0, NULL},
};
static struct PyModuleDef _asynciomodule = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "_asyncio",
.m_doc = module_doc,
.m_size = sizeof(asyncio_state),
.m_methods = asyncio_methods,
.m_slots = module_slots,
.m_traverse = module_traverse,
.m_clear = module_clear,
.m_free = (freefunc)module_free,
};
PyMODINIT_FUNC
PyInit__asyncio(void)
{
return PyModuleDef_Init(&_asynciomodule);
}