diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index e62f5efa638..c242fc3dc1b 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -132,6 +132,8 @@ Run an event loop This clears the queues and shuts down the executor, but does not wait for the executor to finish. + The event loop must not be running. + This is idempotent and irreversible. No other methods should be called after this one. diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index 2f7f1979d3e..42d8b0b4027 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -247,7 +247,11 @@ class BaseEventLoop(events.AbstractEventLoop): This clears the queues and shuts down the executor, but does not wait for the executor to finish. + + The event loop must not be running. """ + if self._running: + raise RuntimeError("cannot close a running event loop") if self._closed: return self._closed = True diff --git a/Lib/asyncio/proactor_events.py b/Lib/asyncio/proactor_events.py index 757a22e83ab..b76f69ee571 100644 --- a/Lib/asyncio/proactor_events.py +++ b/Lib/asyncio/proactor_events.py @@ -355,12 +355,12 @@ class BaseProactorEventLoop(base_events.BaseEventLoop): def close(self): if self.is_closed(): return + super().close() self._stop_accept_futures() self._close_self_pipe() self._proactor.close() self._proactor = None self._selector = None - super().close() def sock_recv(self, sock, n): return self._proactor.recv(sock, n) diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py index a62a8e58267..df64aece3ba 100644 --- a/Lib/asyncio/selector_events.py +++ b/Lib/asyncio/selector_events.py @@ -57,11 +57,11 @@ class BaseSelectorEventLoop(base_events.BaseEventLoop): def close(self): if self.is_closed(): return + super().close() self._close_self_pipe() if self._selector is not None: self._selector.close() self._selector = None - super().close() def _socketpair(self): raise NotImplementedError diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py index acb327d9981..ad4c229438c 100644 --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -44,9 +44,9 @@ class _UnixSelectorEventLoop(selector_events.BaseSelectorEventLoop): return socket.socketpair() def close(self): + super().close() for sig in list(self._signal_handlers): self.remove_signal_handler(sig) - super().close() def add_signal_handler(self, sig, callback, *args): """Add a handler for a signal. UNIX only. diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py index 37e45e1df70..020d12303d8 100644 --- a/Lib/test/test_asyncio/test_events.py +++ b/Lib/test/test_asyncio/test_events.py @@ -1365,6 +1365,15 @@ class EventLoopTestsMixin: with self.assertRaises(RuntimeError): loop.add_writer(w, callback) + def test_close_running_event_loop(self): + @asyncio.coroutine + def close_loop(loop): + self.loop.close() + + coro = close_loop(self.loop) + with self.assertRaises(RuntimeError): + self.loop.run_until_complete(coro) + class SubprocessTestsMixin: