From 511fbb5c73acf1177fb29cabe8d92ed11b58ed00 Mon Sep 17 00:00:00 2001 From: Yury Selivanov Date: Mon, 7 Nov 2016 14:51:00 -0500 Subject: [PATCH 1/2] Fix remove_signal_handler to not to crush after PyOS_FiniInterrupts --- asyncio/unix_events.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/asyncio/unix_events.py b/asyncio/unix_events.py index 65b61db6..7eb0241f 100644 --- a/asyncio/unix_events.py +++ b/asyncio/unix_events.py @@ -1,5 +1,6 @@ """Selector event loop for Unix with signal handling.""" +import atexit import errno import os import signal @@ -9,6 +10,7 @@ import sys import threading import warnings +import weakref from . import base_events @@ -39,6 +41,12 @@ def _sighandler_noop(signum, frame): pass +def _loop_atexit_callback(loop_ref): + loop = loop_ref() + if loop is not None: + loop._interpreter_shutting_down = True + + class _UnixSelectorEventLoop(selector_events.BaseSelectorEventLoop): """Unix event loop. @@ -47,6 +55,15 @@ class _UnixSelectorEventLoop(selector_events.BaseSelectorEventLoop): def __init__(self, selector=None): super().__init__(selector) + + # atexit callbacks are fired before PyOS_FiniInterrupts, which + # allows us to workaround bugs in remove_signal_handler. + atexit.register(_loop_atexit_callback, weakref.ref(self)) + # When _interpreter_shutting_down is True, PyOS_FiniInterrupts + # has already been called and signalmodule's internal state was + # cleaned up. + self._interpreter_shutting_down = False + self._signal_handlers = {} def _socketpair(self): @@ -124,6 +141,11 @@ def remove_signal_handler(self, sig): Return True if a signal handler was removed, False if not. """ + if self._interpreter_shutting_down: + # The interpreter is being shutdown. `PyOS_FiniInterrupts` + # was already called and it has restored all signals already. + return + self._check_signal(sig) try: del self._signal_handlers[sig] From 92f36ae82295fbf8d182d1e6f1338a51afd7f76b Mon Sep 17 00:00:00 2001 From: Yury Selivanov Date: Mon, 7 Nov 2016 16:29:04 -0500 Subject: [PATCH 2/2] Issue a warning in debug mode; return False when interpreter is finalizing --- asyncio/unix_events.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/asyncio/unix_events.py b/asyncio/unix_events.py index 7eb0241f..658e7e93 100644 --- a/asyncio/unix_events.py +++ b/asyncio/unix_events.py @@ -144,7 +144,11 @@ def remove_signal_handler(self, sig): if self._interpreter_shutting_down: # The interpreter is being shutdown. `PyOS_FiniInterrupts` # was already called and it has restored all signals already. - return + if self._debug: + warnings.warn( + "the loop was not closed properly; call loop.close()", + ResourceWarning) + return False self._check_signal(sig) try: