@@ -356,28 +356,40 @@ get_event_loop(asyncio_state *state)
356356}
357357
358358
359+ static int
360+ is_asyncio_base_event_loop_type (PyTypeObject * loop_type )
361+ {
362+ if (strcmp (loop_type -> tp_name , "BaseEventLoop" ) != 0 ) {
363+ return 0 ;
364+ }
365+
366+ PyObject * module_name =
367+ PyDict_GetItemWithError (loop_type -> tp_dict , & _Py_ID (__module__ ));
368+ if (module_name == NULL ) {
369+ if (PyErr_Occurred ()) {
370+ return -1 ;
371+ }
372+ return 0 ;
373+ }
374+
375+ return (
376+ PyUnicode_Check (module_name ) &&
377+ PyUnicode_CompareWithASCIIString (module_name , "asyncio.base_events" ) == 0
378+ );
379+ }
380+
359381static int
360382is_asyncio_base_event_loop_subclass (PyTypeObject * loop_type )
361383{
362384 // The _asyncio module is imported from asyncio.events while
363385 // asyncio.base_events is still initializing, so we can't cache the
364386 // BaseEventLoop type during module init without creating an import cycle.
365387 for (PyTypeObject * base = loop_type ; base != NULL ; base = base -> tp_base ) {
366- if (strcmp (base -> tp_name , "BaseEventLoop" ) != 0 ) {
367- continue ;
368- }
369-
370- PyObject * module_name =
371- PyDict_GetItemWithError (base -> tp_dict , & _Py_ID (__module__ ));
372- if (module_name == NULL ) {
373- if (PyErr_Occurred ()) {
374- return -1 ;
375- }
376- continue ;
388+ int is_base_event_loop = is_asyncio_base_event_loop_type (base );
389+ if (is_base_event_loop < 0 ) {
390+ return -1 ;
377391 }
378-
379- if (PyUnicode_Check (module_name ) &&
380- PyUnicode_CompareWithASCIIString (module_name , "asyncio.base_events" ) == 0 ) {
392+ if (is_base_event_loop ) {
381393 return 1 ;
382394 }
383395 }
@@ -432,7 +444,10 @@ call_soon(asyncio_state *state, PyObject *loop, PyObject *func, PyObject *arg,
432444 int is_base_event_loop_subclass =
433445 is_asyncio_base_event_loop_subclass (loop_type );
434446 int is_stdlib_base_event_loop =
435- strcmp (loop_type -> tp_name , "BaseEventLoop" ) == 0 ;
447+ is_asyncio_base_event_loop_type (loop_type );
448+ if (is_base_event_loop_subclass < 0 || is_stdlib_base_event_loop < 0 ) {
449+ return -1 ;
450+ }
436451 PyObject * call_soon_attr =
437452 PyDict_GetItemWithError (loop_type -> tp_dict , & _Py_ID (call_soon ));
438453 if (call_soon_attr == NULL && PyErr_Occurred ()) {
@@ -443,15 +458,8 @@ call_soon(asyncio_state *state, PyObject *loop, PyObject *func, PyObject *arg,
443458 return -1 ;
444459 }
445460
446- PyObject * module_name = PyDict_GetItemWithError (loop_type -> tp_dict , & _Py_ID (__module__ ));
447- if (module_name == NULL && PyErr_Occurred ()) {
448- return -1 ;
449- }
450-
451461 int use_fastpath = (
452462 is_base_event_loop_subclass &&
453- module_name != NULL &&
454- PyUnicode_Check (module_name ) &&
455463 // Only use the private fast path when the subclass keeps the public
456464 // call_soon() contract unchanged at both the type and instance level.
457465 !has_instance_call_soon_shadow &&
0 commit comments