Skip to content

Commit 0def8d4

Browse files
committed
Restore main changes in _asynciomodule.c and remove comments
1 parent 3f23308 commit 0def8d4

2 files changed

Lines changed: 59 additions & 25 deletions

File tree

‎Lib/test/test_asyncio/test_free_threading.py‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,10 @@ def make_pending_tasks(loop, count):
133133
def worker(batches):
134134
loop = asyncio.new_event_loop()
135135
loop.set_task_factory(self.factory)
136-
137136
tls_tasks = make_pending_tasks(loop, 8)
138137
for task in tls_tasks:
139138
task.get_coro().close()
140139
tls.tasks = tls_tasks
141-
142140
batches.append((loop, make_pending_tasks(loop, 8)))
143141

144142
stop = threading.Event()

‎Modules/_asynciomodule.c‎

Lines changed: 59 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -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

17991796
static 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+
19451966
static int
19461967
FutureIter_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-
19601974
static int
19611975
FutureIter_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+
19762006
static 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
21722206
unregister_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

Comments
 (0)