@@ -71,6 +71,7 @@ typedef struct TaskObj {
7171 // unique id (PyThreadState.id) of the thread state that created this
7272 // task, see unregister_task()
7373 uint64_t task_tstate_id ;
74+
7475#endif
7576} TaskObj ;
7677
@@ -1796,9 +1797,10 @@ FutureIter_dealloc(PyObject *it)
17961797}
17971798
17981799static PySendResult
1799- FutureIter_am_send_lock_held (FutureObj * fut , PyObject * * result )
1800+ FutureIter_am_send_lock_held (futureiterobject * it , PyObject * * result )
18001801{
18011802 PyObject * res ;
1803+ FutureObj * fut = it -> future ;
18021804 _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED (fut );
18031805
18041806 * result = NULL ;
@@ -1829,24 +1831,11 @@ FutureIter_am_send(PyObject *op,
18291831 PyObject * * result )
18301832{
18311833 futureiterobject * it = (futureiterobject * )op ;
1832-
1833- FutureObj * fut ;
1834- Py_BEGIN_CRITICAL_SECTION (op );
1835- fut = (FutureObj * )Py_XNewRef (it -> future );
1836- Py_END_CRITICAL_SECTION ();
1837-
1838- if (fut == NULL ) {
1839- PyErr_SetNone (PyExc_StopIteration );
1840- * result = NULL ;
1841- return PYGEN_ERROR ;
1842- }
1843-
18441834 /* arg is unused, see the comment on FutureIter_send for clarification */
18451835 PySendResult res ;
1846- Py_BEGIN_CRITICAL_SECTION (fut );
1847- res = FutureIter_am_send_lock_held (fut , result );
1836+ Py_BEGIN_CRITICAL_SECTION (it -> future );
1837+ res = FutureIter_am_send_lock_held (it , result );
18481838 Py_END_CRITICAL_SECTION ();
1849- Py_DECREF (fut );
18501839 return res ;
18511840}
18521841
@@ -1940,9 +1929,7 @@ FutureIter_throw(PyObject *op, PyObject *const *args, Py_ssize_t nargs)
19401929 goto fail ;
19411930 }
19421931
1943- Py_BEGIN_CRITICAL_SECTION (self );
19441932 Py_CLEAR (self -> future );
1945- Py_END_CRITICAL_SECTION ();
19461933
19471934 PyErr_Restore (type , val , tb );
19481935
@@ -1955,16 +1942,6 @@ FutureIter_throw(PyObject *op, PyObject *const *args, Py_ssize_t nargs)
19551942 return NULL ;
19561943}
19571944
1958- static PyObject *
1959- FutureIter_close (PyObject * self , PyObject * arg )
1960- {
1961- futureiterobject * it = (futureiterobject * )self ;
1962- Py_BEGIN_CRITICAL_SECTION (self );
1963- Py_CLEAR (it -> future );
1964- Py_END_CRITICAL_SECTION ();
1965- Py_RETURN_NONE ;
1966- }
1967-
19681945static int
19691946FutureIter_clear (PyObject * op )
19701947{
@@ -1973,6 +1950,13 @@ FutureIter_clear(PyObject *op)
19731950 return 0 ;
19741951}
19751952
1953+ static PyObject *
1954+ FutureIter_close (PyObject * self , PyObject * arg )
1955+ {
1956+ (void )FutureIter_clear (self );
1957+ Py_RETURN_NONE ;
1958+ }
1959+
19761960static int
19771961FutureIter_traverse (PyObject * op , visitproc visit , void * arg )
19781962{
@@ -1989,22 +1973,6 @@ static PyMethodDef FutureIter_methods[] = {
19891973 {NULL , NULL } /* Sentinel */
19901974};
19911975
1992- static PyObject *
1993- FutureIter_get_fi_future (PyObject * op , void * Py_UNUSED (closure ))
1994- {
1995- futureiterobject * it = (futureiterobject * )op ;
1996- PyObject * fut ;
1997- Py_BEGIN_CRITICAL_SECTION (op );
1998- fut = it -> future ? Py_NewRef (it -> future ) : Py_None ;
1999- Py_END_CRITICAL_SECTION ();
2000- return fut ;
2001- }
2002-
2003- static PyGetSetDef FutureIter_getsetlist [] = {
2004- {"fi_future" , FutureIter_get_fi_future , NULL , NULL },
2005- {NULL } /* Sentinel */
2006- };
2007-
20081976static PyType_Slot FutureIter_slots [] = {
20091977 {Py_tp_dealloc , FutureIter_dealloc },
20101978 {Py_tp_getattro , PyObject_GenericGetAttr },
@@ -2013,7 +1981,6 @@ static PyType_Slot FutureIter_slots[] = {
20131981 {Py_tp_iter , PyObject_SelfIter },
20141982 {Py_tp_iternext , FutureIter_iternext },
20151983 {Py_tp_methods , FutureIter_methods },
2016- {Py_tp_getset , FutureIter_getsetlist },
20171984
20181985 // async methods
20191986 {Py_am_send , FutureIter_am_send },
@@ -2186,9 +2153,6 @@ register_task(_PyThreadStateImpl *ts, TaskObj *task)
21862153 assert (task -> task_node .prev != NULL );
21872154 return ;
21882155 }
2189- #ifdef Py_GIL_DISABLED
2190- task -> task_tstate_id = ts -> base .id ;
2191- #endif
21922156 struct llist_node * head = & ts -> asyncio_tasks_head ;
21932157 llist_insert_tail (head , & task -> task_node );
21942158}
@@ -2208,19 +2172,15 @@ static void
22082172unregister_task (TaskObj * task )
22092173{
22102174#ifdef Py_GIL_DISABLED
2211- PyThreadState * tstate = _PyThreadState_GET ();
2212- // The lock-free path is only safe while the task is still linked into the
2213- // current thread's own list. That holds if this thread state created the
2214- // task and has not started PyThreadState_Clear(), which moves lingering
2215- // tasks onto the shared interp->asyncio_tasks_head list. Compare thread
2216- // state ids rather than _Py_ThreadId(), which is reused by threads that
2217- // start after the creating thread has exited.
2218- if (task -> task_tstate_id == tstate -> id && !tstate -> _status .finalizing ) {
2175+ // check if we are in the same thread
2176+ // if so, we can avoid locking
2177+ if (task -> task_tid == _Py_ThreadId ()) {
22192178 unregister_task_safe (task );
22202179 }
22212180 else {
2222- // the task may be linked into another thread's list or into the
2223- // interpreter's list: stop the world then check and remove the task
2181+ // we are in a different thread
2182+ // stop the world then check and remove the task
2183+ PyThreadState * tstate = _PyThreadState_GET ();
22242184 _PyEval_StopTheWorld (tstate -> interp );
22252185 unregister_task_safe (task );
22262186 _PyEval_StartTheWorld (tstate -> interp );
@@ -2349,9 +2309,7 @@ _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop,
23492309
23502310 Py_CLEAR (self -> task_fut_waiter );
23512311#ifdef Py_GIL_DISABLED
2352- if (self -> task_node .next == NULL ) {
2353- self -> task_tstate_id = _PyThreadState_GET ()-> id ;
2354- }
2312+ self -> task_tid = _Py_ThreadId ();
23552313#endif
23562314 self -> task_must_cancel = 0 ;
23572315 self -> task_log_destroy_pending = 1 ;
@@ -2813,12 +2771,7 @@ _asyncio_Task_get_name_impl(TaskObj *self)
28132771{
28142772 if (self -> task_name ) {
28152773 if (PyLong_CheckExact (self -> task_name )) {
2816- // Formatting can run arbitrary code (e.g. a GC finalizer that logs
2817- // and re-enters get_name()), which may replace self->task_name.
2818- // Hold a strong reference to the counter while formatting it.
2819- PyObject * counter = Py_NewRef (self -> task_name );
2820- PyObject * name = PyUnicode_FromFormat ("Task-%S" , counter );
2821- Py_DECREF (counter );
2774+ PyObject * name = PyUnicode_FromFormat ("Task-%S" , self -> task_name );
28222775 if (name == NULL ) {
28232776 return NULL ;
28242777 }
@@ -3997,10 +3950,7 @@ add_tasks_llist(struct llist_node *head, PyListObject *tasks)
39973950 struct llist_node * node ;
39983951 llist_for_each_safe (node , head ) {
39993952 TaskObj * task = llist_data (node , TaskObj , task_node );
4000- // The task may already be done but not yet unlinked: its state is set
4001- // before unregister_task() removes it, and that removal may be
4002- // waiting for a stop-the-world pause. add_one_task() filters out
4003- // tasks that are done.
3953+ assert (task -> task_state == STATE_PENDING );
40043954 // The linked list holds borrowed references to task
40053955 // as such it is possible that the task is concurrently
40063956 // deallocated while added to this list.
0 commit comments