@@ -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+
369429static int
370430call_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