Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork33.7k
GH-107803: double linked list implementation for asyncio tasks#107804
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Changes from1 commit
cc66eebd5a3d87a0c5fcf77d012f5d9653d5a001984cdc83435a00f1fddb9d61d32835b46bcfeee7ead2af0280a999fff787a223118124083cb567395526365c5b55982cf69b8998f6ad93c4e135726d98dd0492832530280b65e0b67649e1252b2f457739a4670731e061081836d254efce4b3c7b604c56beb04File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
- Loading branch information
Uh oh!
There was an error while loading.Please reload this page.
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -16,6 +16,59 @@ module _asyncio | ||
| [clinic start generated code]*/ | ||
| /*[clinic end generated code: output=da39a3ee5e6b4b0d input=8fd17862aa989c69]*/ | ||
| 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; \ | ||
| fut_state prefix##_state; \ | ||
| int prefix##_log_tb; \ | ||
| int prefix##_blocking; \ | ||
| PyObject *dict; \ | ||
| PyObject *prefix##_weakreflist; \ | ||
| PyObject *prefix##_cancelled_exc; | ||
| typedef struct { | ||
| FutureObj_HEAD(fut) | ||
| } FutureObj; | ||
| typedef struct TaskObj { | ||
| FutureObj_HEAD(task) | ||
| PyObject *task_fut_waiter; | ||
| PyObject *task_coro; | ||
| PyObject *task_name; | ||
| PyObject *task_context; | ||
| int task_must_cancel; | ||
| int task_log_destroy_pending; | ||
| int task_num_cancels_requested; | ||
| struct TaskObj *next; | ||
| struct TaskObj *prev; | ||
| } 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) | ||
| #define FI_FREELIST_MAXLEN 255 | ||
| @@ -73,6 +126,11 @@ typedef struct { | ||
| futureiterobject *fi_freelist; | ||
| Py_ssize_t fi_freelist_len; | ||
| struct { | ||
| TaskObj *head; | ||
| } asyncio_tasks; | ||
| } asyncio_state; | ||
| static inline asyncio_state * | ||
| @@ -102,56 +160,6 @@ get_asyncio_state_by_def(PyObject *self) | ||
| return get_asyncio_state(mod); | ||
| } | ||
| #include "clinic/_asynciomodule.c.h" | ||
| @@ -1939,16 +1947,17 @@ static PyMethodDef TaskWakeupDef = { | ||
| /* ----- Task introspection helpers */ | ||
| staticvoid | ||
| register_task(asyncio_state *state,TaskObj *task) | ||
| { | ||
| assert(Task_Check(state, task)); | ||
kumaraditya303 marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| assert(task->prev == NULL); | ||
kumaraditya303 marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| assert(task->next == NULL); | ||
| task->prev = state->asyncio_tasks.head; | ||
| if (state->asyncio_tasks.head != NULL) { | ||
| state->asyncio_tasks.head->next = task; | ||
| } | ||
| state->asyncio_tasks.head = task; | ||
| } | ||
| static int | ||
| @@ -1957,16 +1966,22 @@ register_eager_task(asyncio_state *state, PyObject *task) | ||
| return PySet_Add(state->eager_tasks, task); | ||
| } | ||
| staticvoid | ||
| unregister_task(asyncio_state *state,TaskObj *task) | ||
| { | ||
| assert(Task_Check(state, task)); | ||
| if (task->prev != NULL) { | ||
| task->prev->next = task->next; | ||
| } | ||
| if (task->next != NULL) { | ||
| task->next->prev = task->prev; | ||
| } | ||
| if (state->asyncio_tasks.head == task) { | ||
| assert(task->next == NULL); | ||
| state->asyncio_tasks.head = task->prev; | ||
| } | ||
| task->next = NULL; | ||
| task->prev = NULL; | ||
| } | ||
| static int | ||
| @@ -2147,7 +2162,8 @@ _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop, | ||
| if (task_call_step_soon(state, self, NULL)) { | ||
| return -1; | ||
| } | ||
| register_task(state, self); | ||
| return 0; | ||
| } | ||
| static int | ||
| @@ -2552,6 +2568,9 @@ _asyncio_Task_set_name(TaskObj *self, PyObject *value) | ||
| static void | ||
| TaskObj_finalize(TaskObj *task) | ||
kumaraditya303 marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| { | ||
| asyncio_state *state = get_asyncio_state_by_def((PyObject *)task); | ||
| unregister_task(state, task); | ||
| PyObject *context; | ||
| PyObject *message = NULL; | ||
| PyObject *func; | ||
| @@ -3184,9 +3203,7 @@ task_eager_start(asyncio_state *state, TaskObj *task) | ||
| } | ||
| if (task->task_state == STATE_PENDING) { | ||
| register_task(state, task); | ||
| } else { | ||
| // This seems to really help performance on pyperformance benchmarks | ||
| Py_CLEAR(task->task_coro); | ||
| @@ -3352,9 +3369,16 @@ _asyncio__register_task_impl(PyObject *module, PyObject *task) | ||
| /*[clinic end generated code: output=8672dadd69a7d4e2 input=21075aaea14dfbad]*/ | ||
| { | ||
| asyncio_state *state = get_asyncio_state(module); | ||
| if (!Task_Check(state, task)) { | ||
kumaraditya303 marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| PyObject *res = PyObject_CallMethodOneArg(state->scheduled_tasks, | ||
| &_Py_ID(add), task); | ||
| if (res == NULL) { | ||
| return NULL; | ||
| } | ||
| Py_DECREF(res); | ||
| Py_RETURN_NONE; | ||
| } | ||
| register_task(state, (TaskObj *)task); | ||
kumaraditya303 marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| Py_RETURN_NONE; | ||
| } | ||
| @@ -3395,9 +3419,16 @@ _asyncio__unregister_task_impl(PyObject *module, PyObject *task) | ||
| /*[clinic end generated code: output=6e5585706d568a46 input=28fb98c3975f7bdc]*/ | ||
| { | ||
| asyncio_state *state = get_asyncio_state(module); | ||
| if (!Task_Check(state, task)) { | ||
| PyObject *res = PyObject_CallMethodOneArg(state->scheduled_tasks, | ||
| &_Py_ID(discard), task); | ||
| if (res == NULL) { | ||
| return NULL; | ||
| } | ||
| Py_DECREF(res); | ||
| Py_RETURN_NONE; | ||
| } | ||
| unregister_task(state, (TaskObj *)task); | ||
| Py_RETURN_NONE; | ||
| } | ||
| @@ -3534,6 +3565,37 @@ _asyncio_current_task_impl(PyObject *module, PyObject *loop) | ||
| /*********************** Module **************************/ | ||
| /*[clinic input] | ||
| _asyncio.all_tasks | ||
| loop: object = None | ||
| Return set of tasks associated for loop. | ||
kumaraditya303 marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| [clinic start generated code]*/ | ||
| static PyObject * | ||
| _asyncio_all_tasks_impl(PyObject *module, PyObject *loop) | ||
| /*[clinic end generated code: output=0e107cbb7f72aa7b input=02fab144171b1879]*/ | ||
| { | ||
| PyObject *tasks = PySet_New(NULL); | ||
| if (tasks == NULL) { | ||
| return NULL; | ||
| } | ||
| asyncio_state *state = get_asyncio_state(module); | ||
| TaskObj *head = state->asyncio_tasks.head; | ||
| while (head) | ||
| { | ||
| if (loop == Py_None || head->task_loop == loop) { | ||
| if (PySet_Add(tasks, (PyObject *)head) < 0) { | ||
| Py_DECREF(tasks); | ||
| return NULL; | ||
| } | ||
| } | ||
| head = head->prev; | ||
kumaraditya303 marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| } | ||
| return tasks; | ||
| } | ||
| static void | ||
| module_free_freelists(asyncio_state *state) | ||
| @@ -3731,13 +3793,15 @@ static PyMethodDef asyncio_methods[] = { | ||
| _ASYNCIO__ENTER_TASK_METHODDEF | ||
| _ASYNCIO__LEAVE_TASK_METHODDEF | ||
| _ASYNCIO__SWAP_CURRENT_TASK_METHODDEF | ||
| _ASYNCIO_ALL_TASKS_METHODDEF | ||
| {NULL, NULL} | ||
| }; | ||
| static int | ||
| module_exec(PyObject *mod) | ||
| { | ||
| asyncio_state *state = get_asyncio_state(mod); | ||
| state->asyncio_tasks.head = NULL; | ||
| #define CREATE_TYPE(m, tp, spec, base) \ | ||
| do { \ | ||
Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.
Uh oh!
There was an error while loading.Please reload this page.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| import asyncio | ||
| import gc | ||
| async def foo():pass | ||
| async def main(): | ||
| await asyncio.create_task(foo()) | ||
| gc.collect(0) | ||
| print(asyncio.all_tasks()) | ||
| asyncio.run(main()) |