@@ -365,6 +365,25 @@ def _copy_future_state(source, dest):
365365 else :
366366 dest .set_result (result )
367367
368+
369+ def _cancel_future_in_loop (fut , loop , timeout = None ):
370+ """Cancel a future in (maybe another) event loop.
371+
372+ We need to check loop is not running loop to avoid dead lock.
373+ """
374+ if loop is None or loop is events ._get_running_loop ():
375+ return fut .cancel ()
376+ cancel_fut = concurrent .futures .Future ()
377+ def _cancel ():
378+ try :
379+ result = fut .cancel ()
380+ cancel_fut .set_result (result )
381+ except BaseException as exc :
382+ cancel_fut .set_exception (exc )
383+ loop .call_soon_threadsafe (_cancel )
384+ return cancel_fut .result (timeout = timeout )
385+
386+
368387def _chain_future (source , destination ):
369388 """Chain two futures so that when one completes, so does the other.
370389
@@ -389,16 +408,13 @@ def _set_state(future, other):
389408
390409 def _call_check_cancel (destination ):
391410 if destination .cancelled ():
392- if source_loop is None or source_loop is dest_loop :
393- source .cancel ()
394- else :
395- source_loop .call_soon_threadsafe (source .cancel )
411+ _cancel_future_in_loop (source , source_loop )
396412
397413 def _call_set_state (source ):
398414 if (destination .cancelled () and
399415 dest_loop is not None and dest_loop .is_closed ()):
400416 return
401- if dest_loop is None or dest_loop is source_loop :
417+ if dest_loop is None or dest_loop is events . _get_running_loop () :
402418 _set_state (destination , source )
403419 else :
404420 if dest_loop .is_closed ():
0 commit comments