@@ -68,10 +68,7 @@ typedef struct TaskObj {
6868 PyObject * task_context ;
6969 struct llist_node task_node ;
7070#ifdef Py_GIL_DISABLED
71- // unique id (PyThreadState.id) of the thread state that created this
72- // task, see unregister_task()
7371 uint64_t task_tstate_id ;
74-
7572#endif
7673} TaskObj ;
7774
@@ -1797,10 +1794,9 @@ FutureIter_dealloc(PyObject *it)
17971794}
17981795
17991796static PySendResult
1800- FutureIter_am_send_lock_held (futureiterobject * it , PyObject * * result )
1797+ FutureIter_am_send_lock_held (FutureObj * fut , PyObject * * result )
18011798{
18021799 PyObject * res ;
1803- FutureObj * fut = it -> future ;
18041800 _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED (fut );
18051801
18061802 * result = NULL ;
@@ -1831,11 +1827,24 @@ FutureIter_am_send(PyObject *op,
18311827 PyObject * * result )
18321828{
18331829 futureiterobject * it = (futureiterobject * )op ;
1830+
1831+ FutureObj * fut ;
1832+ Py_BEGIN_CRITICAL_SECTION (op );
1833+ fut = (FutureObj * )Py_XNewRef (it -> future );
1834+ Py_END_CRITICAL_SECTION ();
1835+
1836+ if (fut == NULL ) {
1837+ PyErr_SetNone (PyExc_StopIteration );
1838+ * result = NULL ;
1839+ return PYGEN_ERROR ;
1840+ }
1841+
18341842 /* arg is unused, see the comment on FutureIter_send for clarification */
18351843 PySendResult res ;
1836- Py_BEGIN_CRITICAL_SECTION (it -> future );
1837- res = FutureIter_am_send_lock_held (it , result );
1844+ Py_BEGIN_CRITICAL_SECTION (fut );
1845+ res = FutureIter_am_send_lock_held (fut , result );
18381846 Py_END_CRITICAL_SECTION ();
1847+ Py_DECREF (fut );
18391848 return res ;
18401849}
18411850
@@ -1929,7 +1938,9 @@ FutureIter_throw(PyObject *op, PyObject *const *args, Py_ssize_t nargs)
19291938 goto fail ;
19301939 }
19311940
1941+ Py_BEGIN_CRITICAL_SECTION (self );
19321942 Py_CLEAR (self -> future );
1943+ Py_END_CRITICAL_SECTION ();
19331944
19341945 PyErr_Restore (type , val , tb );
19351946
@@ -1942,6 +1953,16 @@ FutureIter_throw(PyObject *op, PyObject *const *args, Py_ssize_t nargs)
19421953 return NULL ;
19431954}
19441955
1956+ static PyObject *
1957+ FutureIter_close (PyObject * self , PyObject * arg )
1958+ {
1959+ futureiterobject * it = (futureiterobject * )self ;
1960+ Py_BEGIN_CRITICAL_SECTION (self );
1961+ Py_CLEAR (it -> future );
1962+ Py_END_CRITICAL_SECTION ();
1963+ Py_RETURN_NONE ;
1964+ }
1965+
19451966static int
19461967FutureIter_clear (PyObject * op )
19471968{
@@ -1950,13 +1971,6 @@ FutureIter_clear(PyObject *op)
19501971 return 0 ;
19511972}
19521973
1953- static PyObject *
1954- FutureIter_close (PyObject * self , PyObject * arg )
1955- {
1956- (void )FutureIter_clear (self );
1957- Py_RETURN_NONE ;
1958- }
1959-
19601974static int
19611975FutureIter_traverse (PyObject * op , visitproc visit , void * arg )
19621976{
@@ -1973,6 +1987,22 @@ static PyMethodDef FutureIter_methods[] = {
19731987 {NULL , NULL } /* Sentinel */
19741988};
19751989
1990+ static PyObject *
1991+ FutureIter_get_fi_future (PyObject * op , void * Py_UNUSED (closure ))
1992+ {
1993+ futureiterobject * it = (futureiterobject * )op ;
1994+ PyObject * fut ;
1995+ Py_BEGIN_CRITICAL_SECTION (op );
1996+ fut = it -> future ? Py_NewRef (it -> future ) : Py_None ;
1997+ Py_END_CRITICAL_SECTION ();
1998+ return fut ;
1999+ }
2000+
2001+ static PyGetSetDef FutureIter_getsetlist [] = {
2002+ {"fi_future" , FutureIter_get_fi_future , NULL , NULL },
2003+ {NULL } /* Sentinel */
2004+ };
2005+
19762006static PyType_Slot FutureIter_slots [] = {
19772007 {Py_tp_dealloc , FutureIter_dealloc },
19782008 {Py_tp_getattro , PyObject_GenericGetAttr },
@@ -1981,6 +2011,7 @@ static PyType_Slot FutureIter_slots[] = {
19812011 {Py_tp_iter , PyObject_SelfIter },
19822012 {Py_tp_iternext , FutureIter_iternext },
19832013 {Py_tp_methods , FutureIter_methods },
2014+ {Py_tp_getset , FutureIter_getsetlist },
19842015
19852016 // async methods
19862017 {Py_am_send , FutureIter_am_send },
@@ -2153,6 +2184,9 @@ register_task(_PyThreadStateImpl *ts, TaskObj *task)
21532184 assert (task -> task_node .prev != NULL );
21542185 return ;
21552186 }
2187+ #ifdef Py_GIL_DISABLED
2188+ task -> task_tstate_id = ts -> base .id ;
2189+ #endif
21562190 struct llist_node * head = & ts -> asyncio_tasks_head ;
21572191 llist_insert_tail (head , & task -> task_node );
21582192}
@@ -2172,15 +2206,11 @@ static void
21722206unregister_task (TaskObj * task )
21732207{
21742208#ifdef Py_GIL_DISABLED
2175- // check if we are in the same thread
2176- // if so, we can avoid locking
2177- if (task -> task_tid == _Py_ThreadId ()) {
2209+ PyThreadState * tstate = _PyThreadState_GET ();
2210+ if (task -> task_tstate_id == tstate -> id && !tstate -> _status .finalizing ) {
21782211 unregister_task_safe (task );
21792212 }
21802213 else {
2181- // we are in a different thread
2182- // stop the world then check and remove the task
2183- PyThreadState * tstate = _PyThreadState_GET ();
21842214 _PyEval_StopTheWorld (tstate -> interp );
21852215 unregister_task_safe (task );
21862216 _PyEval_StartTheWorld (tstate -> interp );
@@ -2309,7 +2339,9 @@ _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop,
23092339
23102340 Py_CLEAR (self -> task_fut_waiter );
23112341#ifdef Py_GIL_DISABLED
2312- self -> task_tid = _Py_ThreadId ();
2342+ if (self -> task_node .next == NULL ) {
2343+ self -> task_tstate_id = _PyThreadState_GET ()-> id ;
2344+ }
23132345#endif
23142346 self -> task_must_cancel = 0 ;
23152347 self -> task_log_destroy_pending = 1 ;
@@ -2771,7 +2803,12 @@ _asyncio_Task_get_name_impl(TaskObj *self)
27712803{
27722804 if (self -> task_name ) {
27732805 if (PyLong_CheckExact (self -> task_name )) {
2774- PyObject * name = PyUnicode_FromFormat ("Task-%S" , self -> task_name );
2806+ // Formatting can run arbitrary code (e.g. a GC finalizer that logs
2807+ // and re-enters get_name()), which may replace self->task_name.
2808+ // Hold a strong reference to the counter while formatting it.
2809+ PyObject * counter = Py_NewRef (self -> task_name );
2810+ PyObject * name = PyUnicode_FromFormat ("Task-%S" , counter );
2811+ Py_DECREF (counter );
27752812 if (name == NULL ) {
27762813 return NULL ;
27772814 }
@@ -3950,7 +3987,6 @@ add_tasks_llist(struct llist_node *head, PyListObject *tasks)
39503987 struct llist_node * node ;
39513988 llist_for_each_safe (node , head ) {
39523989 TaskObj * task = llist_data (node , TaskObj , task_node );
3953- assert (task -> task_state == STATE_PENDING );
39543990 // The linked list holds borrowed references to task
39553991 // as such it is possible that the task is concurrently
39563992 // deallocated while added to this list.
0 commit comments