Skip to content

Commit 1bf3003

Browse files
committed
Broaden asyncio fast path for loop subclasses
1 parent b796c7f commit 1bf3003

1 file changed

Lines changed: 77 additions & 14 deletions

File tree

Modules/_asynciomodule.c

Lines changed: 77 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,66 @@ get_event_loop(asyncio_state *state)
366366
}
367367

368368

369+
static int
370+
is_asyncio_base_event_loop_subclass(PyTypeObject *loop_type)
371+
{
372+
for (PyTypeObject *base = loop_type; base != NULL; base = base->tp_base) {
373+
if (strcmp(base->tp_name, "BaseEventLoop") != 0) {
374+
continue;
375+
}
376+
377+
PyObject *module_name =
378+
PyDict_GetItemWithError(base->tp_dict, &_Py_ID(__module__));
379+
if (module_name == NULL) {
380+
if (PyErr_Occurred()) {
381+
return -1;
382+
}
383+
continue;
384+
}
385+
386+
if (PyUnicode_Check(module_name) &&
387+
PyUnicode_CompareWithASCIIString(module_name, "asyncio.base_events") == 0) {
388+
return 1;
389+
}
390+
}
391+
392+
return 0;
393+
}
394+
395+
static int
396+
loop_has_instance_call_soon_shadow(PyObject *loop)
397+
{
398+
PyTypeObject *loop_type = Py_TYPE(loop);
399+
PyObject *attr = NULL;
400+
401+
if ((loop_type->tp_flags & Py_TPFLAGS_INLINE_VALUES) &&
402+
_PyObject_TryGetInstanceAttribute(loop, &_Py_ID(call_soon), &attr)) {
403+
int has_shadow = attr != NULL;
404+
Py_XDECREF(attr);
405+
return has_shadow;
406+
}
407+
408+
PyObject *dict;
409+
if (loop_type->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
410+
dict = (PyObject *)_PyObject_GetManagedDict(loop);
411+
}
412+
else {
413+
PyObject **dictptr = _PyObject_ComputedDictPointer(loop);
414+
dict = dictptr != NULL ? FT_ATOMIC_LOAD_PTR_ACQUIRE(*dictptr) : NULL;
415+
}
416+
417+
if (dict == NULL) {
418+
return 0;
419+
}
420+
421+
int rc = PyDict_GetItemRef(dict, &_Py_ID(call_soon), &attr);
422+
if (rc < 0) {
423+
return -1;
424+
}
425+
Py_XDECREF(attr);
426+
return rc > 0;
427+
}
428+
369429
static int
370430
call_soon(asyncio_state *state, PyObject *loop, PyObject *func, PyObject *arg,
371431
PyObject *ctx)
@@ -374,28 +434,31 @@ call_soon(asyncio_state *state, PyObject *loop, PyObject *func, PyObject *arg,
374434
PyObject *handle = NULL;
375435

376436
PyTypeObject *loop_type = Py_TYPE(loop);
437+
int is_base_event_loop_subclass =
438+
is_asyncio_base_event_loop_subclass(loop_type);
439+
int is_stdlib_base_event_loop =
440+
strcmp(loop_type->tp_name, "BaseEventLoop") == 0;
441+
PyObject *call_soon_attr =
442+
PyDict_GetItemWithError(loop_type->tp_dict, &_Py_ID(call_soon));
443+
if (call_soon_attr == NULL && PyErr_Occurred()) {
444+
return -1;
445+
}
446+
int has_instance_call_soon_shadow = loop_has_instance_call_soon_shadow(loop);
447+
if (has_instance_call_soon_shadow < 0) {
448+
return -1;
449+
}
450+
377451
PyObject *module_name = PyDict_GetItemWithError(loop_type->tp_dict, &_Py_ID(__module__));
378452
if (module_name == NULL && PyErr_Occurred()) {
379453
return -1;
380454
}
381455

382456
int use_fastpath = (
457+
is_base_event_loop_subclass &&
383458
module_name != NULL &&
384459
PyUnicode_Check(module_name) &&
385-
(
386-
(strcmp(loop_type->tp_name, "BaseEventLoop") == 0 &&
387-
PyUnicode_CompareWithASCIIString(module_name, "asyncio.base_events") == 0) ||
388-
(strcmp(loop_type->tp_name, "BaseSelectorEventLoop") == 0 &&
389-
PyUnicode_CompareWithASCIIString(module_name, "asyncio.selector_events") == 0) ||
390-
(strcmp(loop_type->tp_name, "_UnixSelectorEventLoop") == 0 &&
391-
PyUnicode_CompareWithASCIIString(module_name, "asyncio.unix_events") == 0) ||
392-
(strcmp(loop_type->tp_name, "_WindowsSelectorEventLoop") == 0 &&
393-
PyUnicode_CompareWithASCIIString(module_name, "asyncio.windows_events") == 0) ||
394-
(strcmp(loop_type->tp_name, "BaseProactorEventLoop") == 0 &&
395-
PyUnicode_CompareWithASCIIString(module_name, "asyncio.proactor_events") == 0) ||
396-
(strcmp(loop_type->tp_name, "ProactorEventLoop") == 0 &&
397-
PyUnicode_CompareWithASCIIString(module_name, "asyncio.windows_events") == 0)
398-
)
460+
!has_instance_call_soon_shadow &&
461+
(is_stdlib_base_event_loop || call_soon_attr == NULL)
399462
);
400463

401464
if (use_fastpath) {

0 commit comments

Comments
 (0)