@@ -366,28 +366,40 @@ get_event_loop(asyncio_state *state)
366366}
367367
368368
369+ static int
370+ is_asyncio_base_event_loop_type (PyTypeObject * loop_type )
371+ {
372+ if (strcmp (loop_type -> tp_name , "BaseEventLoop" ) != 0 ) {
373+ return 0 ;
374+ }
375+
376+ PyObject * module_name =
377+ PyDict_GetItemWithError (loop_type -> tp_dict , & _Py_ID (__module__ ));
378+ if (module_name == NULL ) {
379+ if (PyErr_Occurred ()) {
380+ return -1 ;
381+ }
382+ return 0 ;
383+ }
384+
385+ return (
386+ PyUnicode_Check (module_name ) &&
387+ PyUnicode_CompareWithASCIIString (module_name , "asyncio.base_events" ) == 0
388+ );
389+ }
390+
369391static int
370392is_asyncio_base_event_loop_subclass (PyTypeObject * loop_type )
371393{
372394 // The _asyncio module is imported from asyncio.events while
373395 // asyncio.base_events is still initializing, so we can't cache the
374396 // BaseEventLoop type during module init without creating an import cycle.
375397 for (PyTypeObject * base = loop_type ; base != NULL ; base = base -> tp_base ) {
376- if (strcmp (base -> tp_name , "BaseEventLoop" ) != 0 ) {
377- continue ;
378- }
379-
380- PyObject * module_name =
381- PyDict_GetItemWithError (base -> tp_dict , & _Py_ID (__module__ ));
382- if (module_name == NULL ) {
383- if (PyErr_Occurred ()) {
384- return -1 ;
385- }
386- continue ;
398+ int is_base_event_loop = is_asyncio_base_event_loop_type (base );
399+ if (is_base_event_loop < 0 ) {
400+ return -1 ;
387401 }
388-
389- if (PyUnicode_Check (module_name ) &&
390- PyUnicode_CompareWithASCIIString (module_name , "asyncio.base_events" ) == 0 ) {
402+ if (is_base_event_loop ) {
391403 return 1 ;
392404 }
393405 }
@@ -443,7 +455,10 @@ call_soon(asyncio_state *state, PyObject *loop, PyObject *func, PyObject *arg,
443455 int is_base_event_loop_subclass =
444456 is_asyncio_base_event_loop_subclass (loop_type );
445457 int is_stdlib_base_event_loop =
446- strcmp (loop_type -> tp_name , "BaseEventLoop" ) == 0 ;
458+ is_asyncio_base_event_loop_type (loop_type );
459+ if (is_base_event_loop_subclass < 0 || is_stdlib_base_event_loop < 0 ) {
460+ return -1 ;
461+ }
447462 PyObject * call_soon_attr =
448463 PyDict_GetItemWithError (loop_type -> tp_dict , & _Py_ID (call_soon ));
449464 if (call_soon_attr == NULL && PyErr_Occurred ()) {
@@ -454,15 +469,8 @@ call_soon(asyncio_state *state, PyObject *loop, PyObject *func, PyObject *arg,
454469 return -1 ;
455470 }
456471
457- PyObject * module_name = PyDict_GetItemWithError (loop_type -> tp_dict , & _Py_ID (__module__ ));
458- if (module_name == NULL && PyErr_Occurred ()) {
459- return -1 ;
460- }
461-
462472 int use_fastpath = (
463473 is_base_event_loop_subclass &&
464- module_name != NULL &&
465- PyUnicode_Check (module_name ) &&
466474 // Only use the private fast path when the subclass keeps the public
467475 // call_soon() contract unchanged at both the type and instance level.
468476 !has_instance_call_soon_shadow &&
0 commit comments