]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
asyncio: Don't raise "IOLoop is closing" in add_callback
authorBen Darnell <ben@bendarnell.com>
Sun, 31 Dec 2017 22:05:05 +0000 (17:05 -0500)
committerBen Darnell <ben@bendarnell.com>
Sun, 31 Dec 2017 22:05:05 +0000 (17:05 -0500)
This mirrors a previous change to PollIOLoop. Fix a test that had
rotted and become meaningless.

Fixes #2191

tornado/platform/asyncio.py
tornado/test/ioloop_test.py

index adc7c1aeb1fe808783dba29a878a66b8e59efb67..42c8a800126af70bea6de7c7558c87654d12bf35 100644 (file)
@@ -130,13 +130,17 @@ class BaseAsyncIOLoop(IOLoop):
         timeout.cancel()
 
     def add_callback(self, callback, *args, **kwargs):
-        if self.closing:
-            # TODO: this is racy; we need a lock to ensure that the
-            # loop isn't closed during call_soon_threadsafe.
-            raise RuntimeError("IOLoop is closing")
-        self.asyncio_loop.call_soon_threadsafe(
-            self._run_callback,
-            functools.partial(stack_context.wrap(callback), *args, **kwargs))
+        try:
+            self.asyncio_loop.call_soon_threadsafe(
+                self._run_callback,
+                functools.partial(stack_context.wrap(callback), *args, **kwargs))
+        except RuntimeError:
+            # "Event loop is closed". Swallow the exception for
+            # consistency with PollIOLoop (and logical consistency
+            # with the fact that we can't guarantee that an
+            # add_callback that completes without error will
+            # eventually execute).
+            pass
 
     add_callback_from_signal = add_callback
 
index 616099452aaa742a47cc814479daa22ab4ab53ea..0ca52c66af939ccd02430625671665b592b4c830 100644 (file)
@@ -171,10 +171,9 @@ class TestIOLoop(AsyncTestCase):
         other_ioloop.close()
 
     def test_add_callback_while_closing(self):
-        # Issue #635: add_callback() should raise a clean exception
-        # if called while another thread is closing the IOLoop.
-        if IOLoop.configured_class().__name__.endswith('AsyncIOLoop'):
-            raise unittest.SkipTest("AsyncIOMainLoop shutdown not thread safe")
+        # add_callback should not fail if it races with another thread
+        # closing the IOLoop. The callbacks are dropped silently
+        # without executing.
         closing = threading.Event()
 
         def target():
@@ -187,11 +186,7 @@ class TestIOLoop(AsyncTestCase):
         thread.start()
         closing.wait()
         for i in range(1000):
-            try:
-                other_ioloop.add_callback(lambda: None)
-            except RuntimeError as e:
-                self.assertEqual("IOLoop is closing", str(e))
-                break
+            other_ioloop.add_callback(lambda: None)
 
     def test_handle_callback_exception(self):
         # IOLoop.handle_callback_exception can be overridden to catch