Commit 425aaa11 authored by Victor Stinner's avatar Victor Stinner

(Merge 3.4) asyncio, Tulip issue 171: BaseEventLoop.close() now raises an

exception if the event loop is running. You must first stop the event loop and
then wait until it stopped, before closing it.
parents 422a76d6 f328c7dc
...@@ -132,6 +132,8 @@ Run an event loop ...@@ -132,6 +132,8 @@ Run an event loop
This clears the queues and shuts down the executor, but does not wait for This clears the queues and shuts down the executor, but does not wait for
the executor to finish. the executor to finish.
The event loop must not be running.
This is idempotent and irreversible. No other methods should be called after This is idempotent and irreversible. No other methods should be called after
this one. this one.
......
...@@ -247,7 +247,11 @@ class BaseEventLoop(events.AbstractEventLoop): ...@@ -247,7 +247,11 @@ class BaseEventLoop(events.AbstractEventLoop):
This clears the queues and shuts down the executor, This clears the queues and shuts down the executor,
but does not wait for the executor to finish. 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: if self._closed:
return return
self._closed = True self._closed = True
......
...@@ -355,12 +355,12 @@ class BaseProactorEventLoop(base_events.BaseEventLoop): ...@@ -355,12 +355,12 @@ class BaseProactorEventLoop(base_events.BaseEventLoop):
def close(self): def close(self):
if self.is_closed(): if self.is_closed():
return return
super().close()
self._stop_accept_futures() self._stop_accept_futures()
self._close_self_pipe() self._close_self_pipe()
self._proactor.close() self._proactor.close()
self._proactor = None self._proactor = None
self._selector = None self._selector = None
super().close()
def sock_recv(self, sock, n): def sock_recv(self, sock, n):
return self._proactor.recv(sock, n) return self._proactor.recv(sock, n)
......
...@@ -57,11 +57,11 @@ class BaseSelectorEventLoop(base_events.BaseEventLoop): ...@@ -57,11 +57,11 @@ class BaseSelectorEventLoop(base_events.BaseEventLoop):
def close(self): def close(self):
if self.is_closed(): if self.is_closed():
return return
super().close()
self._close_self_pipe() self._close_self_pipe()
if self._selector is not None: if self._selector is not None:
self._selector.close() self._selector.close()
self._selector = None self._selector = None
super().close()
def _socketpair(self): def _socketpair(self):
raise NotImplementedError raise NotImplementedError
......
...@@ -44,9 +44,9 @@ class _UnixSelectorEventLoop(selector_events.BaseSelectorEventLoop): ...@@ -44,9 +44,9 @@ class _UnixSelectorEventLoop(selector_events.BaseSelectorEventLoop):
return socket.socketpair() return socket.socketpair()
def close(self): def close(self):
super().close()
for sig in list(self._signal_handlers): for sig in list(self._signal_handlers):
self.remove_signal_handler(sig) self.remove_signal_handler(sig)
super().close()
def add_signal_handler(self, sig, callback, *args): def add_signal_handler(self, sig, callback, *args):
"""Add a handler for a signal. UNIX only. """Add a handler for a signal. UNIX only.
......
...@@ -1365,6 +1365,15 @@ class EventLoopTestsMixin: ...@@ -1365,6 +1365,15 @@ class EventLoopTestsMixin:
with self.assertRaises(RuntimeError): with self.assertRaises(RuntimeError):
loop.add_writer(w, callback) 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: class SubprocessTestsMixin:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment